WPF 利用數據綁定超簡單實現很火羅盤時鐘

整個邏輯還是很簡單的,沒有什麼正弦餘弦計算,沒有什麼座標計算。就是簡單的旋轉動畫;

源碼地址:https://github.com/Super0Lan/Timer.git

exe地址:https://github.com/Super0Lan/ControlDesign/blob/master/DemoList.exe

直接上代碼

Xaml代碼:

<Window.Resources>
        <Style TargetType="ListBox">
            <Setter Property="IsHitTestVisible" Value="False"></Setter>
            <Setter Property="BorderThickness" Value="0"></Setter>
            <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"></Setter>
            <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"></Setter>
            <Setter Property="Background" Value="Transparent"></Setter>
            <Setter Property="RenderTransformOrigin" Value="0.5,0.5"></Setter>
            <Setter Property="ItemsPanel">
                <Setter.Value>
                    <ItemsPanelTemplate>
                        <Grid Background="Transparent"></Grid>
                    </ItemsPanelTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <Style TargetType="ListBoxItem" x:Key="TimeItem">
            <Setter Property="IsHitTestVisible" Value="False"></Setter>
            <Setter Property="Width" Value="150"></Setter>
            <Setter Property="HorizontalContentAlignment" Value="Right"></Setter>
            <Setter Property="Height" Value="150"></Setter>
            <Setter Property="RenderTransformOrigin" Value="0.5,0.5"></Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                        <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                            <ContentPresenter Content="{Binding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="RenderTransform">
                <Setter.Value>
                    <TransformGroup>
                        <RotateTransform Angle="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ListBoxItem},Path=DataContext.Angle}"/>
                    </TransformGroup>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Foreground" Value="White"></Setter>
                </Trigger>
            </Style.Triggers>
        </Style>

        <Style TargetType="ListBoxItem" x:Key="DaysItem" BasedOn="{StaticResource TimeItem}">
            <Setter Property="Width" Value="300"></Setter>
            <Setter Property="Height" Value="300"></Setter>
        </Style>

        <Style TargetType="ListBoxItem" x:Key="HoursItem" BasedOn="{StaticResource TimeItem}">
            <Setter Property="Width" Value="450"></Setter>
            <Setter Property="Height" Value="450"></Setter>
        </Style>

        <Style TargetType="ListBoxItem" x:Key="MinsItem" BasedOn="{StaticResource TimeItem}">
            <Setter Property="Width" Value="600"></Setter>
            <Setter Property="Height" Value="600"></Setter>
        </Style>

        <Style TargetType="ListBoxItem" x:Key="SecondsItem" BasedOn="{StaticResource TimeItem}">
            <Setter Property="Width" Value="750"></Setter>
            <Setter Property="Height" Value="750"></Setter>
        </Style>
    </Window.Resources>
    <Grid RenderTransformOrigin="0.5,0.5" Background="Transparent">
        <ListBox SelectedIndex="{Binding CurrentMonth}" x:Name="MonthItems" SelectionChanged="MonthItems_SelectionChanged"  ItemsSource="{Binding Months}" ItemContainerStyle="{StaticResource TimeItem}"></ListBox>
        <ListBox SelectedIndex="{Binding CurrentDay}"  x:Name="DayItems" SelectionChanged="DayItems_SelectionChanged"  ItemsSource="{Binding Days}" ItemContainerStyle="{StaticResource DaysItem}"></ListBox>
        <ListBox SelectedIndex="{Binding CurrentHour}" x:Name="HourItems" SelectionChanged="HourItems_SelectionChanged"  ItemsSource="{Binding Hours}" ItemContainerStyle="{StaticResource HoursItem}"></ListBox>
        <ListBox SelectedIndex="{Binding CurrentMin}" x:Name="MinItems" SelectionChanged="MinItems_SelectionChanged"  ItemsSource="{Binding Mins}" ItemContainerStyle="{StaticResource MinsItem}"></ListBox>
        <ListBox SelectedIndex="{Binding CurrentSecond}" x:Name="SecondItems" SelectionChanged="SecondItems_SelectionChanged" ItemsSource="{Binding Seconds}" ItemContainerStyle="{StaticResource SecondsItem}"></ListBox>
    </Grid>

C# 代碼

    public partial class MainWindow : Window
    {

        public TimeItemCollection Data = new TimeItemCollection();

        public MainWindow()
        {
            InitializeComponent();
            DataContext = Data;

            Timer timer = new Timer((state) =>
            {
                Dispatcher.Invoke(() =>
                {
                    DateTime date = DateTime.Now;
                    Data.CurrentMonth = date.Month - 1;
                    Data.CurrentDay = date.Day - 1;
                    Data.CurrentHour = date.Hour;
                    Data.CurrentMin = date.Minute;
                    Data.CurrentSecond = date.Second;
                });
            });
            timer.Change(0, 100);
        }


        private void SecondItems_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.RemovedItems.Count > 0)
            {
                Data.CorrectSecond();
                SecondItems.BeginRotate(0, 6);
            }

        }

        private void MonthItems_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.RemovedItems.Count > 0)
            {
                Data.CorrectMonth();
                MonthItems.BeginRotate(0, 30);
            }
        }

        private void DayItems_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.RemovedItems.Count > 0)
            {
                Data.CorrectDay();
                DayItems.BeginRotate(0, 360.0 / 31.0);
            }
        }

        private void HourItems_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.RemovedItems.Count > 0)
            {
                Data.CorrectHour();
                HourItems.BeginRotate(0, 15);
            }
        }

        private void MinItems_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (e.RemovedItems.Count > 0)
            {
                Data.CorrectMin();
                MinItems.BeginRotate(0, 6);
            }
        }
    }

    public static class UIElementExtensions
    {
        public static void BeginRotate(this UIElement uIElement, double from, double to, int mili = 500)
        {
            RotateTransform rtf = new RotateTransform();
            uIElement.RenderTransform = rtf;
            uIElement.RenderTransform.BeginAnimation(RotateTransform.AngleProperty, new DoubleAnimation(from, to, new Duration(TimeSpan.FromMilliseconds(mili)))
            {
                BeginTime = new TimeSpan(0),
            });
        }
    }

    public class TimeItemCollection : BaseModel
    {
        public ObservableCollection<TimeItem> Months { get; set; } = new ObservableCollection<TimeItem>();
        public ObservableCollection<TimeItem> Days { get; set; } = new ObservableCollection<TimeItem>();
        public ObservableCollection<TimeItem> Hours { get; set; } = new ObservableCollection<TimeItem>();
        public ObservableCollection<TimeItem> Mins { get; set; } = new ObservableCollection<TimeItem>();
        public ObservableCollection<TimeItem> Seconds { get; set; } = new ObservableCollection<TimeItem>();


        private int _currentMonth;
        public int CurrentMonth { get { return _currentMonth; } set { Set(ref _currentMonth, value); } }

        private int _currentDay;
        public int CurrentDay { get { return _currentDay; } set { Set(ref _currentDay, value); } }

        private int _currentHour;

        public int CurrentHour { get { return _currentHour; } set { Set(ref _currentHour, value); } }

        private int _currentMin;
        public int CurrentMin { get { return _currentMin; } set { Set(ref _currentMin, value); } }

        private int _currentSecond;
        public int CurrentSecond { get { return _currentSecond; } set { Set(ref _currentSecond, value); } }


        public TimeItemCollection()
        {
            DateTime date = DateTime.Now;
            int month = date.Month;
            int day = date.Day;
            int hour = date.Hour;
            int min = date.Minute;
            int second = date.Second;

            for (int i = 1; i <= 12; i++)
            {
                Months.Add(new TimeItem()
                {
                    Content = $"{i.ToString().PadLeft(2, '0')}月",
                    Value = i,
                    Angle = 30 * (i - month - 1)
                });
            }
            for (int i = 1; i <= 31; i++)
            {
                Days.Add(new TimeItem()
                {
                    Content = $"{i.ToString().PadLeft(2, '0')}天",
                    Value = i,
                    Angle = 360.0 / 31.0 * (i - day - 1)
                });
            }
            for (int i = 0; i < 24; i++)
            {
                Hours.Add(new TimeItem()
                {
                    Content = $"{i.ToString().PadLeft(2, '0')}點",
                    Value = i,
                    Angle = 15 * (i - hour - 1)
                });
            }
            for (int i = 0; i < 60; i++)
            {
                Mins.Add(new TimeItem()
                {
                    Content = $"{i.ToString().PadLeft(2, '0')}分",
                    Value = i,
                    Angle = 6 * (i - min - 1)
                });
            }
            for (int i = 0; i < 60; i++)
            {
                Seconds.Add(new TimeItem()
                {
                    Content = $"{i.ToString().PadLeft(2, '0')}秒",
                    Value = i,
                    Angle = 6 * (i - second - 1)
                });
            }
        }


        public void CorrectSecond()
        {

            int second = DateTime.Now.Second;
            Parallel.For(0, 60, (i) =>
            {
                Seconds[i].Angle = 6 * (i - second -1);
            });
        }
        public void CorrectMonth()
        {

            int month = DateTime.Now.Month;
            Parallel.For(0, 12, (i) =>
            {
                Months[i].Angle = 30 * (i - month);
            });
        }
        public void CorrectDay()
        {

            int day = DateTime.Now.Day;
            Parallel.For(0, 31, (i) =>
            {
                Days[i].Angle = 360.0 / 31.0 * (i - day);
            });
        }
        public void CorrectHour()
        {

            int hour = DateTime.Now.Hour;
            Parallel.For(0, 24, (i) =>
            {
                Hours[i].Angle = 15 * (i - hour - 1);
            });
        }
        public void CorrectMin()
        {

            int min = DateTime.Now.Minute;
            Parallel.For(0, 60, (i) =>
            {
                Mins[i].Angle = 6 * (i - min - 1);
            });
        }
    }

    public class TimeItem : BaseModel
    {
        public string Content { get; set; }
        public int Value { get; set; }
        private double _anlge;
        public double Angle { get { return _anlge; } set { Set(ref _anlge, value); } }
    }

    public class BaseModel : INotifyPropertyChanged
    {
        protected bool Set<T>(ref T field, T newValue = default(T), [CallerMemberName]string propertyName = "")
        {
            if (EqualityComparer<T>.Default.Equals(field, newValue))
            {
                return false;
            }
            var oldValue = field;
            field = newValue;
            RaisePropertyChanged(propertyName);
            return true;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void RaisePropertyChanged([CallerMemberName]string propertyName = "")
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章