WPF 自定义风扇
成品效果如下:
制作方法:
1.添加UserControl,其详细代码如下:
<UserControl x:Class="WpfControl.UserControls.NFan" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WpfControl.UserControls" mc:Ignorable="d" d:DesignHeight="1000" d:DesignWidth="1000"> <!--<UserControl.Triggers> <EventTrigger RoutedEvent="UserControl.Loaded"> <BeginStoryboard> <Storyboard> <DoubleAnimationUsingKeyFrames RepeatBehavior="Forever" Storyboard.TargetName="path1" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/> <EasingDoubleKeyFrame KeyTime="00:00:01" Value="360"/> </DoubleAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames RepeatBehavior="Forever" Storyboard.TargetName="path1" Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)"> <EasingPointKeyFrame KeyTime="00:00:00" Value="0.667,0.735"/> <EasingPointKeyFrame KeyTime="00:00:01" Value="0.667,0.735"/> </PointAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </UserControl.Triggers>--> <!--<UserControl.Resources> <Storyboard x:Key="Storyboard1"> <DoubleAnimationUsingKeyFrames Storyboard.TargetName="path1" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" RepeatBehavior="Forever"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/> <EasingDoubleKeyFrame KeyTime="00:00:01" Value="360"/> </DoubleAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames Storyboard.TargetName="path1" Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)"> <EasingPointKeyFrame KeyTime="00:00:00" Value="0.667,0.735"/> <EasingPointKeyFrame KeyTime="00:00:01" Value="0.667,0.735"/> </PointAnimationUsingKeyFrames> </Storyboard> </UserControl.Resources>--> <Border> <VisualStateManager.VisualStateGroups> <VisualStateGroup> <VisualState x:Name="normalState"> <Storyboard > <DoubleAnimationUsingKeyFrames RepeatBehavior="Forever" Storyboard.TargetName="path1" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)"> <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/> <EasingDoubleKeyFrame KeyTime="00:00:01" Value="360"/> </DoubleAnimationUsingKeyFrames> <PointAnimationUsingKeyFrames RepeatBehavior="Forever" Storyboard.TargetName="path1" Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)"> <EasingPointKeyFrame KeyTime="00:00:00" Value="0.667,0.735"/> <EasingPointKeyFrame KeyTime="00:00:01" Value="0.667,0.735"/> </PointAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="errorState"> <Storyboard> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Viewbox HorizontalAlignment="Center" VerticalAlignment="Center"> <Grid> <Canvas Width="1000" Height="1000"> <Path Data="M903 94.5H121c-5.5 0-10 4.5-10 10v748c0 5.5 4.5 10 10 10h143v58c0 5.5 4.5 10 10 10h68c5.5 0 10-4.5 10-10v-58h320v58c0 5.5 4.5 10 10 10h68c5.5 0 10-4.5 10-10v-58h143c5.5 0 10-4.5 10-10v-748c0-5.5-4.5-10-10-10z m-571 816h-48v-48h48v48z m408 0h-48v-48h48v48z m153-68H131v-728h762v728z" Fill="#1296db"></Path> <Path x:Name="path" Data="M512 811.5c88.9 0 172.6-34.6 235.5-97.5S845 567.4 845 478.5 810.4 305.9 747.5 243C684.6 180.1 601 145.5 512 145.5c-88.9 0-172.6 34.6-235.5 97.5-62.9 62.9-97.5 146.6-97.5 235.5s34.6 172.6 97.5 235.5c62.9 62.9 146.6 97.5 235.5 97.5z m0-646c172.6 0 313 140.4 313 313s-140.4 313-313 313-313-140.4-313-313 140.4-313 313-313z" Fill="#1296db" RenderTransformOrigin="0.5,0.5"></Path> <Path x:Name="path1" Data="M331.1 658.9c11.5 0 21.9-4.2 29.7-12.1l92.7-93.5c16.1 12.7 36.5 20.2 58.5 20.2s42.4-7.6 58.5-20.2l92.7 93.5c7.8 7.9 18.2 12.1 29.7 12.1 2.1 0 4.2-0.1 6.4-0.4 22.9-3 46.5-21.1 61.7-47.5 15.2-26.3 19.1-55.9 10.3-77.2-5.4-13-15.4-22.1-28.2-25.4l-133.2-35c-1-0.3-2-0.4-3-0.3-1.9-34.2-22-63.6-50.7-78.7L592 263.3c3.5-12.7 0.6-25.9-7.9-37.1-14-18.3-41.6-29.7-71.9-29.7s-58 11.4-71.9 29.7c-8.6 11.2-11.4 24.4-7.9 37.1l35.8 131.1c-28.7 15.1-48.8 44.5-50.7 78.7-1 0-2 0-3 0.3l-133.2 35c-12.7 3.3-22.7 12.4-28.2 25.4-8.9 21.3-4.9 50.8 10.3 77.2 15.2 26.3 38.8 44.5 61.7 47.5 1.8 0.2 3.9 0.4 6 0.4z m281.1-164.2L738 527.8c6.7 1.8 11.7 6.4 14.8 13.8 6.4 15.4 2.8 38.7-9.1 59.5-12 20.7-30.4 35.5-46.9 37.6-7.9 1-14.4-1-19.3-5.9L586 540.4l5.9-10.2c1.8-2.8 3.5-5.8 5.1-8.8l15.2-26.7zM485.6 383.5L451.4 258c-1.8-6.7-0.3-13.4 4.5-19.7C466 225 488 216.5 512 216.5s45.9 8.6 56.1 21.8c4.8 6.3 6.4 13 4.5 19.7l-34.2 125.5h-52.8z m26.4 20c41.4 0 75 33.6 75 75 0 12.1-2.9 23.5-8 33.6l-4.4 7.6c-13.4 20.4-36.5 33.9-62.7 33.9-26.2 0-49.3-13.5-62.7-33.9L445 512c-5.1-10.1-8-21.5-8-33.5 0-41.4 33.6-75 75-75zM280.4 601c-12-20.7-15.5-44.1-9.1-59.5 3.1-7.4 8-12 14.8-13.8l125.8-33.1 15.4 26.7c1.5 3 3.2 6 5.1 8.8l5.9 10.1-91.5 92.4c-4.9 5-11.4 7-19.3 5.9-16.7-2-35.2-16.8-47.1-37.5z" Fill="#1296db" RenderTransformOrigin="0.516,0.48"> <Path.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </Path.RenderTransform> </Path> </Canvas> </Grid> </Viewbox> </Border> </UserControl>
上述注释为在blend中调试时使用代码……动画的制作最好在blend中进行相应的测试,测试好没问题,再将代码添加到VisualStateGroup中,UserControl.Triggers中代码则是为了使自定义控件能实现在加载完成后就启动相应的动画,以查看相应效果。
2.添加后台代码,以实现绑定属性来显示正常运转与停止异常。代码如下:
1 /// <summary> 2 /// NFan.xaml 的交互逻辑 3 /// </summary> 4 public partial class NFan : UserControl 5 { 6 public NFan() 7 { 8 InitializeComponent(); 9 } 10 public RunningState RunningState 11 { 12 get { return (RunningState)GetValue(RunningStateProperty); } 13 set { SetValue(RunningStateProperty, value); } 14 } 15 16 // Using a DependencyProperty as the backing store for RunningState. This enables animation, styling, binding, etc... 17 public static readonly DependencyProperty RunningStateProperty = 18 DependencyProperty.Register("RunningState", typeof(RunningState), typeof(NFan), new PropertyMetadata(default(RunningState), RunningStateChangedCallback)); 19 20 private static void RunningStateChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) 21 { 22 RunningState value = (RunningState)e.NewValue; 23 VisualStateManager.GoToState(d as NFan, value == RunningState.Normal ? "normalState" : "errorState", false); 24 } 25 }
上述代码中还涉及到一个 RunningState的枚举类,其主要就是涉及Normal与Error两个值,不然你可以添加其他值。
最终在Window中引入方法如下:
<Window x:Class="WpfControl.TestWindow2" 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:uctrl="clr-namespace:WpfControl.UserControls" mc:Ignorable="d" Title="Test" Height="450" Width="800"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <uctrl:NFan Grid.Column="2" RunningState="Normal" Width="100" Height="100"/> <uctrl:NFan Grid.Column="3" RunningState="Error" Width="100" Height="100"/> </Grid> </Window>
Tips:
1.添加旋转动画时一定注意其旋转轴心问题,即上自定义控件中动画涉及到的 <EasingPointKeyFrame KeyTime="00:00:00" Value="0.667,0.735"/>,起始都 需做好轴心的标记。以免其出现异常。
2. Canvas一定设置Width Height,否则其内Control不能正常显示。
3. UserControl中Canvas外的Grid可以不要。
4. UserControl中直接使用Canvas会导致控件放到window或page时不能缩放。
5. ViewBox是使用时能绽放的关键,一定不能忘记。
本文参考WPF工控组态软件之温度计 - 小六公子 - 博客园 (cnblogs.com)
*****有道无术,术尚可求;有术无道,止于术。*****