通常,当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里面,这是整个资源文件的代码
我们只需要关注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.TargetName="background"这一段出错,至于为何报错,为何不能查找到,还请前辈们告之,这里我找到了解决办法。
参看
那么我们需要为故事版的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); }
这样,就通过后台控制到了动画的播放。