










//D:\C\WpfApp2\WpfApp2\RotateWheel.cs using System; using System.Collections.Generic; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Threading; namespace WpfApp2 { /// <summary> /// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file. /// /// Step 1a) Using this custom control in a XAML file that exists in the current project. /// Add this XmlNamespace attribute to the root element of the markup file where it is /// to be used: /// /// xmlns:MyNamespace="clr-namespace:WpfApp2" /// /// /// Step 1b) Using this custom control in a XAML file that exists in a different project. /// Add this XmlNamespace attribute to the root element of the markup file where it is /// to be used: /// /// xmlns:MyNamespace="clr-namespace:WpfApp2;assembly=WpfApp2" /// /// You will also need to add a project reference from the project where the XAML file lives /// to this project and Rebuild to avoid compilation errors: /// /// Right click on the target project in the Solution Explorer and /// "Add Reference"->"Projects"->[Browse to and select this project] /// /// /// Step 2) /// Go ahead and use your control in the XAML file. /// /// <MyNamespace:RotateWheel/> /// /// </summary> public class RotateWheel : Control { private DispatcherTimer tmr; private double speedInterval=10.0d; public RotateWheel() { tmr = new DispatcherTimer(); tmr.Interval = TimeSpan.FromSeconds(1); tmr.Tick += Tmr_Tick; tmr.Start(); } private void Tmr_Tick(object? sender, EventArgs e) { double current = SpeedKmh; if(SpeedKmh>=200) { speedInterval = -20; } else if(current<=10) { speedInterval = 20; } SpeedKmh = current + speedInterval; } static RotateWheel() { DefaultStyleKeyProperty.OverrideMetadata(typeof(RotateWheel), new FrameworkPropertyMetadata(typeof(RotateWheel))); } #region DependencyProperties public bool IsClockWise { get { return (bool)GetValue(IsClockWiseProperty); } set { SetValue(IsClockWiseProperty, value); } } // Using a DependencyProperty as the backing store for IsClockWise. This enables animation, styling, binding, etc... public static readonly DependencyProperty IsClockWiseProperty = DependencyProperty.Register(nameof(IsClockWise), typeof(bool), typeof(RotateWheel), new PropertyMetadata(true,OnClockWiseChanged)); private static void OnClockWiseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((RotateWheel)d).UpdateAnimationState(); } public double SpeedKmh { get { return (double)GetValue(SpeedKmhProperty); } set { SetValue(SpeedKmhProperty, value); } } // Using a DependencyProperty as the backing store for SpeedKmh. This enables animation, styling, binding, etc... public static readonly DependencyProperty SpeedKmhProperty = DependencyProperty.Register(nameof(SpeedKmh), typeof(double), typeof(RotateWheel), new PropertyMetadata(10.0,OnSpeedChanged,CoerceSpeedChanged)); private static object CoerceSpeedChanged(DependencyObject d, object baseValue) { double v = (double)baseValue; return Math.Clamp(v, 0, 200); } private static void OnSpeedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { ((RotateWheel)d).UpdateAnimationState(); } #endregion #region Template Children refs private RotateTransform wheelRotateTransform; private DoubleAnimation rotatedAnimation; #endregion public override void OnApplyTemplate() { base.OnApplyTemplate(); wheelRotateTransform = GetTemplateChild("PART_WheelRotateTransform") as RotateTransform; SetupAnimation(); UpdateAnimationState(); } private void UpdateAnimationState() { if(wheelRotateTransform is null || rotatedAnimation is null) { return; } double speed = SpeedKmh; if(speed<=double.Epsilon) { wheelRotateTransform.BeginAnimation(RotateTransform.AngleProperty, null); return; } double secPerRad = 2.0 / speed; double fullCircleRad = 2 * Math.PI; double fullCircleSeconds = secPerRad * fullCircleRad; rotatedAnimation.Duration = TimeSpan.FromSeconds(fullCircleSeconds); //clockwise rotatedAnimation.IsCumulative = true; rotatedAnimation.From = 0; rotatedAnimation.To = IsClockWise ? 360 : -360; wheelRotateTransform.BeginAnimation(RotateTransform.AngleProperty, null); wheelRotateTransform.BeginAnimation(RotateTransform.AngleProperty, rotatedAnimation); } private void SetupAnimation() { if(wheelRotateTransform==null) { return; } rotatedAnimation = new DoubleAnimation { From = 0, To = 360, RepeatBehavior = RepeatBehavior.Forever, FillBehavior = FillBehavior.HoldEnd, }; wheelRotateTransform.BeginAnimation(RotateTransform.AngleProperty, rotatedAnimation); } } } //D:\C\WpfApp2\WpfApp2\Themes\Generic.xaml <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WpfApp2"> <Style TargetType="{x:Type local:RotateWheel}"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type local:RotateWheel}"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="6*"/> <RowDefinition/> </Grid.RowDefinitions> <Grid Grid.Row="0" HorizontalAlignment="Center" Height="500" Width="500" RenderTransformOrigin="0.5,0.5" > <Grid.RenderTransform> <RotateTransform x:Name="PART_WheelRotateTransform" Angle="0"/> </Grid.RenderTransform> <Path Width="500" Height="500"> <Path.Data> <CombinedGeometry GeometryCombineMode="Union"> <CombinedGeometry.Geometry1> <EllipseGeometry RadiusX="250" RadiusY="250" Center="250,250"/> </CombinedGeometry.Geometry1> <CombinedGeometry.Geometry2> <EllipseGeometry RadiusX="200" RadiusY="200" Center="250,250"/> </CombinedGeometry.Geometry2> </CombinedGeometry> </Path.Data> <Path.Fill> <LinearGradientBrush> <GradientStop Color="LightPink" Offset="0.1"/> <GradientStop Color="Red" Offset="0.2"/> <GradientStop Color="Orange" Offset="0.3"/> <GradientStop Color="DarkOrange" Offset="0.4"/> <GradientStop Color="DarkBlue" Offset="0.5"/> <GradientStop Color="Yellow" Offset="0.6"/> <GradientStop Color="LightGreen" Offset="0.7"/> <GradientStop Color="Green" Offset="0.8"/> <GradientStop Color="Cyan" Offset="0.9"/> <GradientStop Color="DarkCyan" Offset="1.0"/> </LinearGradientBrush> </Path.Fill> </Path> </Grid> <Grid Grid.Row="1"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <CheckBox Grid.Column="0" IsChecked="{Binding IsClockWise,RelativeSource={RelativeSource TemplatedParent}}" Content="Clockwise" Margin="10" HorizontalAlignment="Center"/> <Slider Grid.Column="1" Minimum="0" Maximum="200" Interval="10" Value="{Binding SpeedKmh,RelativeSource={RelativeSource TemplatedParent}}" Margin="5,5" Width="300" HorizontalAlignment="Center"/> <TextBlock Grid.Column="2" Text="{Binding SpeedKmh, RelativeSource={RelativeSource TemplatedParent}, StringFormat='Speed:{0:F2} km/h'}" HorizontalAlignment="Center"/> </Grid> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary> //D:\C\WpfApp2\WpfApp2\MainWindow.xaml <Window x:Class="WpfApp2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp2" mc:Ignorable="d" Title="MainWindow" WindowState="Maximized"> <Grid> <local:RotateWheel/> </Grid> </Window>


此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。