zoukankan      html  css  js  c++  java
  • [转]WPF 构建无外观(Lookless)控件

    构建一个用户可以使用Template属性设置外观的WPF控件需要以下几步

    1. 1、继承自System.Windows.Controls.Control 
      2、设置DefaultStyleKeyProperty 
      3、实现控件功能
    2. 4、定义默认Sytle
    3. 5、添加ThemeInfo 
      我借用一个时钟的控件例子,讲解以下每一个步骤
    4. 第1步 继承自System.Windows.Controls.Control

     

    我们的自定义控件继承自System.Windows.Controls.Control,如果有更特别的控件,也可以继承自更复杂的控件。

    类声明

       1: public class Clock : Control
       2: {
       3: }

    第2步 设置DefaultStyleKeyProperty

     

    无外观的控件需要在静态构造函数中设置DefaultStyleKeyProperty,这样它会去在themes/generic.xaml的文件获取默认的样式。

       1: static Clock()
       2: {
       3:     DefaultStyleKeyProperty.OverrideMetadata(typeof(Clock), new FrameworkPropertyMetadata(typeof(Clock)));
       4: }

    第3步 实现控件功能

    这一步没什么特别的,就是内部有个DateTime类型和一个DispatcherTimer,完成一个时钟的功能

       1: public class Clock : Control
       2: {
       3:     private DispatcherTimer timer;
       4:  
       5:     static Clock()
       6:     {
       7:         DefaultStyleKeyProperty.OverrideMetadata(typeof(Clock), new FrameworkPropertyMetadata(typeof(Clock)));
       8:     }
       9:  
      10:     protected override void OnInitialized(EventArgs e)
      11:     {
      12:         base.OnInitialized(e);
      13:  
      14:         UpdateDateTime();
      15:  
      16:         timer = new DispatcherTimer();
      17:         timer.Interval = TimeSpan.FromMilliseconds(1000 - DateTime.Now.Millisecond);
      18:         timer.Tick += new EventHandler(Timer_Tick);
      19:         timer.Start();
      20:     }
      21:  
      22:     private void Timer_Tick(object sender, EventArgs e)
      23:     {
      24:         UpdateDateTime();
      25:  
      26:         timer.Interval = TimeSpan.FromMilliseconds(1000 - DateTime.Now.Millisecond);
      27:         timer.Start();
      28:     }
      29:  
      30:     private void UpdateDateTime()
      31:     {
      32:         this.DateTime = System.DateTime.Now;
      33:     }
      34:  
      35:     public DateTime DateTime
      36:     {
      37:         get
      38:         {
      39:             return (DateTime)GetValue(DateTimeProperty);
      40:         }
      41:         private set
      42:         {
      43:             SetValue(DateTimeProperty, value);
      44:         }
      45:     }
      46:  
      47:     public static DependencyProperty DateTimeProperty = DependencyProperty.Register(
      48:             "DateTime",
      49:             typeof(DateTime),
      50:             typeof(Clock),
      51:             new PropertyMetadata(DateTime.Now, new PropertyChangedCallback(OnDateTimeInvalidated)));
      52:  
      53:     public static readonly RoutedEvent DateTimeChangedEvent =
      54:         EventManager.RegisterRoutedEvent("DateTimeChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<DateTime>), typeof(Clock));
      55:  
      56:     protected virtual void OnDateTimeChanged(DateTime oldValue, DateTime newValue)
      57:     {
      58:         RoutedPropertyChangedEventArgs<DateTime> args = new RoutedPropertyChangedEventArgs<DateTime>(oldValue, newValue);
      59:         args.RoutedEvent = Clock.DateTimeChangedEvent;
      60:         RaiseEvent(args);
      61:     }
      62:  
      63:     private static void OnDateTimeInvalidated(DependencyObject d, DependencyPropertyChangedEventArgs e)
      64:     {
      65:         Clock clock = (Clock)d;
      66:  
      67:         DateTime oldValue = (DateTime)e.OldValue;
      68:         DateTime newValue = (DateTime)e.NewValue;
      69:  
      70:         clock.OnDateTimeChanged(oldValue, newValue);
      71:     }
      72: }

    第4步 定义默认Sytle

     

    如上所述,我们还需要一个默认的Template,它写在themes/generic.xaml文件中,这个文件可能需要自己创建

       1: <ResourceDictionary
       2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       4:     xmlns:local="clr-namespace:CustomControlLibrary"
       5:     >
       6:  
       7:     <Style TargetType="{x:Type local:Clock}">
       8:         <Setter Property="Template">
       9:             <Setter.Value>
      10:                 <ControlTemplate TargetType="{x:Type local:Clock}">
      11:                     <TextBlock Text="{Binding Path=DateTime, RelativeSource={RelativeSource TemplatedParent}}" />
      12:                 </ControlTemplate>
      13:             </Setter.Value>
      14:         </Setter>
      15:     </Style>
      16: </ResourceDictionary>

    这里要注意TargetType的使用。到这里控件还是不能找到默认的模板,还需要下面的最后一步

    1. 第5步 添加ThemeInfo

     

    最后还需要在AssemblyInfo.cs文件中加入ThemeInfo信息,在文件中加入以下特性

       1: [assembly: ThemeInfo(
       2:     ResourceDictionaryLocation.None,
       3:     ResourceDictionaryLocation.SourceAssembly
       4: )]
    1. 附注

     

    如果需要在模板中使用特定的元素名,来或许模板中的某个特定控件,还有几个地方需要注意。

    1、模板内的Name最好以PART开头,好的名称类似于PART_TextBox

    2、获取Template中控件的代码,需要重载OnApplyTemplate()方法,可以使用GetTemplateChild方法获取,如下
       1: public override void OnApplyTemplate()
       2: {
       3:     base.OnApplyTemplate();
       4:  
       5:     //从模板中获取名称为PART_PresentationTextBox的TextBox
       6:     _presentationTextBox = GetTemplateChild("PART_PresentationTextBox") as TextBox;
       7:     if(_presentationTextBox != null)
       8:     {
       9:         //对_presentationTextBox进行操作
      10:     }
      11: }

    3、在控件类添加TemplatePart

       1: [TemplatePart(Name = "PART_PresentationTextBox", Type = typeof(TextBox))]
       2: public class TimeSpanPicker:Control

    这个内容可以参考https://gitcafe.com/atskyline/WPFTimeSpanPickerControl

    1. 参考资料

     

    http://www.codeproject.com/Articles/14340/Creating-a-look-less-custom-control-in-WPF

    http://www.codeproject.com/Articles/35444/Defining-the-Default-Style-for-a-Lookless-Control

  • 相关阅读:
    熟悉常用的HBase操作,编写MapReduce作业
    爬虫大作业
    熟悉常用的HDFS操作
    数据结构化与保存
    获取全部校园新闻
    爬取校园新闻首页的新闻
    网络爬虫基础练习
    leetcode
    归并排序
    选择排序法
  • 原文地址:https://www.cnblogs.com/luohengstudy/p/3578010.html
Copyright © 2011-2022 走看看