• WPF自定义控件 《动画》


    通常,当WPF常用的控件不能满足我们的需求时,我们就会创建自己的控件,有用户控件和自定义控件两种。就很想winform中的,用户控件可以基于当前的控件组合成我们需要的控件,而自定义控件那么就是从0做起,不过继承自一个和我们功能相似的类会效果更好,比如CustomControl继承Button的一些方法特性。

    UserControl非常好理解,网上有许多教程。

    CustomControl由于其没有Xaml界面,界面是放到Themes/Generic.xaml中来定义的,所以在开发中,特别是初学者带来一些困惑,今天怒搞一天,把自己的经验分享一下,也希望前辈们能多多指教。

    好,创建一个CustomControl,发现目录机构如下

    我们并没有看到CustomControl.xaml文件,打开CustomControl1.cs,代码如下

    static TemControl()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(TemControl), new FrameworkPropertyMetadata(typeof(TemControl)));
            }

    其实,这里就是为我们的控件指定了一个默认的外观,这个外观在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:TemControl">
        <Style TargetType="{x:Type local:TemControl}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:TemControl}">
                        <ControlTemplate.Resources>
                            <Storyboard x:Key="Alarm">
                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="background">
                                    <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
                                    <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/>
                                </DoubleAnimationUsingKeyFrames>
                            </Storyboard>
                        </ControlTemplate.Resources>
                        <!--<ControlTemplate.Triggers>
                            <EventTrigger RoutedEvent="UIElement.MouseLeftButtonDown" SourceName="background">
                                <BeginStoryboard Storyboard="{StaticResource Alarm}"/>
                            </EventTrigger>
                        </ControlTemplate.Triggers>-->
                        <Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="Tempreature" Width="250" Height="280" Clip="F1 M 0,0L 250,0L 250,280L 0,280L 0,0">
                            <Canvas x:Name="background" Width="250" Height="280" Canvas.Left="0" Canvas.Top="0" RenderTransformOrigin="0.5,0.5">
                                <Canvas.RenderTransform>
                                    <TransformGroup>
                                        <ScaleTransform/>
                                        <SkewTransform/>
                                        <RotateTransform/>
                                        <TranslateTransform/>
                                    </TransformGroup>
                                </Canvas.RenderTransform>
                                <Path x:Name="Path" Width="230" Height="230" Canvas.Left="10" Canvas.Top="4.99991" Stretch="Fill" Data="F1 M 20,4.99991L 230,4.99991C 235.523,4.99991 240,9.47702 240,14.9999L 240,225C 240,230.523 235.523,235 230,235L 20,235C 14.4772,235 10,230.523 10,225L 10,14.9999C 10,9.47702 14.4772,4.99991 20,4.99991 Z ">
                                    <Path.Fill>
                                        <LinearGradientBrush StartPoint="0.5,1.25168" EndPoint="0.5,-0.25168">
                                            <LinearGradientBrush.GradientStops>
                                                <GradientStop Color="#FF000000" Offset="0"/>
                                                <GradientStop Color="#FF4C4E4C" Offset="0.748837"/>
                                                <GradientStop Color="#FF989D98" Offset="1"/>
                                            </LinearGradientBrush.GradientStops>
                                        </LinearGradientBrush>
                                    </Path.Fill>
                                    <Path.Effect>
                                        <DropShadowEffect BlurRadius="8" ShadowDepth="3.77953" Opacity="0.599998" Color="#FF000000" Direction="315"/>
                                    </Path.Effect>
                                </Path>
                            </Canvas>
                            <Canvas x:Name="tempreature" Width="250" Height="280" Canvas.Left="0" Canvas.Top="0">
                                <Viewbox x:Name="Group" Width="58" Height="191" Canvas.Left="45" Canvas.Top="25">
                                    <Canvas Width="58" Height="191">
                                        <Path x:Name="Path_0" Width="20" Height="147" Canvas.Left="16.115" Canvas.Top="1.34552" Stretch="Fill" StrokeThickness="6" StrokeStartLineCap="Round" StrokeEndLineCap="Round" StrokeLineJoin="Round" Stroke="#FF96C240" Fill="#0096C240" Data="F1 M 26.115,4.34552L 26.115,4.34552C 29.981,4.34552 33.115,7.47954 33.115,11.3455L 33.115,138.345C 33.115,142.211 29.981,145.345 26.115,145.345L 26.115,145.345C 22.249,145.345 19.115,142.211 19.115,138.345L 19.115,11.3455C 19.115,7.47954 22.249,4.34552 26.115,4.34552 Z ">
                                            <Path.Effect>
                                                <DropShadowEffect BlurRadius="8" ShadowDepth="3.77953" Opacity="0.599998" Color="#FF000000" Direction="315"/>
                                            </Path.Effect>
                                        </Path>
                                        <Ellipse x:Name="Ellipse" Width="49.6471" Height="46.8889" Canvas.Left="1.29151" Canvas.Top="136.303" Stretch="Fill" Fill="#FF96C240">
                                            <Ellipse.Effect>
                                                <DropShadowEffect BlurRadius="8" ShadowDepth="3.77953" Opacity="0.599998" Color="#FF000000" Direction="315"/>
                                            </Ellipse.Effect>
                                        </Ellipse>
                                    </Canvas>
                                </Viewbox>
                            </Canvas>
                        </Canvas>
    
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>

    我们只需要关注ControTemplate这一标记,内部其实就是实现我们自定义控件的外观。好,进入正题,今天之所以研究一天是因为对于它的动画故事版。

    故事版我们可以在Blend中设计,然后移植到这里即可,但是需要注意的是:Resouce和Trigger都应该放到ControlTemplate下,而不是Style下。

    有时某些动画的控制我需要在后台控制。那就是只需要获取到故事版,然后在相应的事件上让故事版播放即可。

    那么如何获取放在Themes/Generic.xaml下的故事版呢?

    查阅MSDN,要访问ControlTemplate下的资源,可以使用Template.Resources属性获得资源字典,得到资源字典后,那就是根据Key值获取到相应的资源了。这里需要注意,要获得资源字典

    必须重写父类的OnApplyTemplate方法,从中不只能得到资源,也能得到ControlTemplate下的控件。

    public override void OnApplyTemplate()
            {
                ResourceDictionary r = this.Template.Resources;
                sb = r["Alarm"] as Storyboard;
                ca = this.GetTemplateChild("background") as Canvas;
                base.OnApplyTemplate();
            }

    好,得到故事版了,那么在重写单击事件,然后让故事版播放,发现出错了

    看我们故事版的代码

    <Storyboard x:Key="Alarm">
                                <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" Storyboard.TargetName="background">
                                    <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
                                    <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0"/>
                                </DoubleAnimationUsingKeyFrames>
                            </Storyboard>

    其中Storyboard.TargetName="background"这一段出错,至于为何报错,为何不能查找到,还请前辈们告之,这里我找到了解决办法。

    参看http://social.msdn.microsoft.com/Forums/zh-TW/802/thread/1365449e-965d-4df7-82df-e3e0e8d0ca19

    那么我们需要为故事版的Begin方法将Target对象传进去。background是Canvas对象,前面提到使用GetTemplateChild很容易获取到ControlTemplate下的控件。

    获取到background后,带入Begin方法,功能实现。

    public override void OnApplyTemplate()
            {
                ResourceDictionary r = this.Template.Resources;
                sb = r["Alarm"] as Storyboard;
                ca = this.GetTemplateChild("background") as Canvas;
                base.OnApplyTemplate();
            }
    
            protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
            {
                sb.Begin(ca);
                base.OnMouseLeftButtonDown(e);
            }

    这样,就通过后台控制到了动画的播放。

  • 相关阅读:
    Windows 经典DOS命令大全
    Linux常用命令大全(全面)
    Nova 实现的 Fit Instance NUMA to Host NUMA 算法
    计算机组成原理 — 冯诺依曼体系结构
    计算机组成的基本硬件设备
    OpenStack 高性能虚拟机之大页内存
    Ironic 的 Rescue 救援模式实现流程
    SQLite 版本引发的 Python 程序调用问题
    Ceph 故障修复记录(持续更新)
    注册 Ironic 裸金属节点并部署裸金属实例
  • 原文地址:https://www.cnblogs.com/HelloMyWorld/p/2998660.html
Copyright © 2020-2023  润新知