原文: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

WPF 构建无外观(Lookless)控件的更多相关文章

  1. [转]WPF 构建无外观(Lookless)控件

    构建一个用户可以使用Template属性设置外观的WPF控件需要以下几步 1.继承自System.Windows.Controls.Control 2.设置DefaultStyleKeyPropert ...

  2. 【WPF学习】第六十四章 构建基本的用户控件

    创建一个简单用户控件是开始自定义控件的好方法.本章主要介绍创建一个基本的颜色拾取器.接下来分析如何将这个控件分解成功能更强大的基于模板的控件. 创建基本的颜色拾取器很容易.然而,创建自定义颜色拾取器仍 ...

  3. WPF Timeline简易时间轴控件的实现

    原文:WPF Timeline简易时间轴控件的实现 效果图: 由于整个控件是实现之后才写的教程,因此这里记录的代码是最终实现后的,前后会引用到其他的一些依赖属性或者代码,需要阅读整篇文章. 1.确定T ...

  4. .Net中使用无闪刷新控件时提示框不显示

    今天做提示框的时候一直不显示,让我郁闷好久,晚上吃饭的时候问了同事一下,他给了一个思路, 他说可能是因为由于页面中的无闪刷新导致的结果:百度了一下真找到了解决方法 在页面中存在无闪刷新控件的时候提示框 ...

  5. WPF自定义控件(一)の控件分类

    一.什么是控件(Controls) 控件是指对数据和方法的封装.控件可以有自己的属性和方法,其中属性是控件数据的简单访问者,方法则是控件的一些简单而可见的功能.控件创建过程包括设计.开发.调试(就是所 ...

  6. 基于 WPF 平台的 ActiveReports Viewer控件

    ActiveReports 报表控件致力于为组织和个人提供最出色的报表解决方案,多年来ActiveReports已经提供了 Windows Forms.Web.Silverlight和Flash平台的 ...

  7. WPF不同线程之间的控件的访问

    原文:WPF不同线程之间的控件的访问 WPF不同线程之间的控件是不同访问的,为了能够访问其他线程之间的控件,需要用Dispatcher.Invoke执行一个新的活动即可. 例如: public voi ...

  8. WindowsXamlHost:在 WPF 中使用 UWP 的控件(Windows Community Toolkit)

    Windows Community Toolkit 再次更新到 5.0.以前可以在 WPF 中使用有限的 UWP 控件,而现在有了 WindowsXamlHost,则可以使用更多 UWP 原生控件了. ...

  9. WPF 动画:同为控件不同命 - 简书

    原文:WPF 动画:同为控件不同命 - 简书 1. 及格与优秀 读大学的时候,有一门课的作业是用 PPT 展示. 但是我们很多同学都把 PPT 当做 Word 来用,就单纯地往里面堆文字. 大家都单纯 ...

随机推荐

  1. 解决Myeclipse报PermGen space异常的问题

    最近使用eclipse做开发,使用的服务器是tomcat,但在启动时报了Caused by: java.lang.OutOfMemoryError: PermGen space的异常. 这个错误很常见 ...

  2. 第二次scrum冲击

    1.小组第二次冲刺任务及其完成情况描述. 本次冲刺我们小组经过讨论,实现的使我们爱上长大系统中的失物招领功能,由于在实际的实现中,对于本功能的逐渐深入和了解,渐渐发现这个功能实现起来需要由很多部分组成 ...

  3. oozie调用java实例------shell action

    Oozie提供了一个方便的方式来运行任何命令.这可能是Unix命令,Perl或Python脚本,甚至java程序都可以通过Unix shell调用.shell命令运行在任意的Hadoop集群节点上,并 ...

  4. 为什么A经理的团队总是会陷入加班与救火之中

    最近在看一本名为<稀缺>的书,作者从行为经济学的角度解释了穷人为什么会更穷,忙碌的人越来越没有时间,节食的人总是失败.由于缺乏闲余导致的带宽负担会进一步导致稀缺,由于总是优先处理紧急的事情 ...

  5. mobile easyui兼容实体数据(tree插件为例)

    ORM的实体类和数据库的类是一一对应的,如果有多级的嵌套循环json返回到前台为了方便展示可以使用mobile easyui,但是mobile easyui又需要特定的属性才可以,比如id,text, ...

  6. swift的特性:扩展、协议、泛型

    swift的特性:扩展.协议.泛型 扩展与继承:对象的生长方式: 协议:支持 协议->类型.类型<-协议 的双向抽象: 泛型:

  7. pthread使用

    https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/Multithreading/CreatingTh ...

  8. 前端:Bootstrap框架

    一,bootstrap介绍 Bootstrap是Twitter开源的基于HTML.CSS.JavaScript的前端框架. 它是为实现快速开发Web应用程序而设计的一套前端工具包. 它支持响应式布局, ...

  9. 【UVA1309】Sudoku(DLX)

    点此看题面 大致题意: 让你填完整一个\(16*16\)的数独. 解题思路 我们知道,数独问题显然可以用\(DLX\)解决. 考虑对于一个数独,它要满足的要求为:每个位置都必须有数,每一行都必须有全部 ...

  10. Vue开发 localhost 替换成 本机ip无法访问

    新版 vue-cli(@3.10.10) 构建的项目.localhost 替换成本机 ip 地址之后无法访问.但是替换成 127.0.0.1 可以访问 找到 config 文件夹下面的 index.i ...