[转]WPF 构建无外观(Lookless)控件
2014-02-14 17:06
232 查看
建一个用户可以使用Template属性设置外观的WPF控件需要以下几步
1、继承自System.Windows.Controls.Control
2、设置DefaultStyleKeyProperty
3、实现控件功能
4、定义默认Sytle
5、添加ThemeInfo
我借用一个时钟的控件例子,讲解以下每一个步骤
类声明
[/code]
[/code]
[/code]
[/code]
[/code]
[/code]
[/code]
[/code]
这里要注意TargetType的使用。到这里控件还是不能找到默认的模板,还需要下面的最后一步
[/code]
[/code]
1、模板内的Name最好以PART开头,好的名称类似于PART_TextBox
[/code]
[/code]
3、在控件类添加TemplatePart
[/code]
[/code]
这个内容可以参考https://gitcafe.com/atskyline/WPFTimeSpanPickerControl
http://www.codeproject.com/Articles/35444/Defining-the-Default-Style-for-a-Lookless-Control
转载文章来源:http://www.cnblogs.com/atskyline/archive/2012/11/16/2773806.html
1、继承自System.Windows.Controls.Control
2、设置DefaultStyleKeyProperty
3、实现控件功能
4、定义默认Sytle
5、添加ThemeInfo
我借用一个时钟的控件例子,讲解以下每一个步骤
第1步 继承自System.Windows.Controls.Control
我们的自定义控件继承自System.Windows.Controls.Control,如果有更特别的控件,也可以继承自更复杂的控件。
类声明
[code] [code] public class Clock : Control
{
}
[/code]
[/code]
第2步 设置DefaultStyleKeyProperty
无外观的控件需要在静态构造函数中设置DefaultStyleKeyProperty,这样它会去在themes/generic.xaml的文件获取默认的样式。
[code] [code] static Clock()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Clock), new FrameworkPropertyMetadata(typeof(Clock)));
}
[/code]
[/code]
第3步 实现控件功能
这一步没什么特别的,就是内部有个DateTime类型和一个DispatcherTimer,完成一个时钟的功能[code] [code] public class Clock : Control
{
private DispatcherTimer timer;
static Clock()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Clock), new FrameworkPropertyMetadata(typeof(Clock)));
}
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
UpdateDateTime();
timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(1000 - DateTime.Now.Millisecond);
timer.Tick += new EventHandler(Timer_Tick);
timer.Start();
}
private void Timer_Tick(object sender, EventArgs e)
{
UpdateDateTime();
timer.Interval = TimeSpan.FromMilliseconds(1000 - DateTime.Now.Millisecond);
timer.Start();
}
private void UpdateDateTime()
{
this.DateTime = System.DateTime.Now;
}
public DateTime DateTime
{
get
{
return (DateTime)GetValue(DateTimeProperty);
}
private set
{
SetValue(DateTimeProperty, value);
}
}
public static DependencyProperty DateTimeProperty = DependencyProperty.Register(
"DateTime",
typeof(DateTime),
typeof(Clock),
new PropertyMetadata(DateTime.Now, new PropertyChangedCallback(OnDateTimeInvalidated)));
public static readonly RoutedEvent DateTimeChangedEvent =
EventManager.RegisterRoutedEvent("DateTimeChanged", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<DateTime>), typeof(Clock));
protected virtual void OnDateTimeChanged(DateTime oldValue, DateTime newValue)
{
RoutedPropertyChangedEventArgs<DateTime> args = new RoutedPropertyChangedEventArgs<DateTime>(oldValue, newValue);
args.RoutedEvent = Clock.DateTimeChangedEvent;
RaiseEvent(args);
}
private static void OnDateTimeInvalidated(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Clock clock = (Clock)d;
DateTime oldValue = (DateTime)e.OldValue;
DateTime newValue = (DateTime)e.NewValue;
clock.OnDateTimeChanged(oldValue, newValue);
}
}
[/code]
[/code]
第4步 定义默认Sytle
如上所述,我们还需要一个默认的Template,它写在themes/generic.xaml文件中,这个文件可能需要自己创建
[code] [code] <ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CustomControlLibrary"
>
<Style TargetType="{x:Type local:Clock}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Clock}">
<TextBlock Text="{Binding Path=DateTime, RelativeSource={RelativeSource TemplatedParent}}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
[/code]
[/code]
这里要注意TargetType的使用。到这里控件还是不能找到默认的模板,还需要下面的最后一步
第5步 添加ThemeInfo
最后还需要在AssemblyInfo.cs文件中加入ThemeInfo信息,在文件中加入以下特性
[code] [code] [assembly: ThemeInfo(
ResourceDictionaryLocation.None,
ResourceDictionaryLocation.SourceAssembly
)]
[/code]
[/code]
附注
如果需要在模板中使用特定的元素名,来或许模板中的某个特定控件,还有几个地方需要注意。
1、模板内的Name最好以PART开头,好的名称类似于PART_TextBox
2、获取Template中控件的代码,需要重载OnApplyTemplate()方法,可以使用GetTemplateChild方法获取,如下
[code] [code] public override void OnApplyTemplate()
{
base.OnApplyTemplate();
//从模板中获取名称为PART_PresentationTextBox的TextBox
_presentationTextBox = GetTemplateChild("PART_PresentationTextBox") as TextBox;
if(_presentationTextBox != null)
{
//对_presentationTextBox进行操作
}
}
[/code]
[/code]
3、在控件类添加TemplatePart
[code] [code] [TemplatePart(Name = "PART_PresentationTextBox", Type = typeof(TextBox))]
public class TimeSpanPicker:Control
[/code]
[/code]
这个内容可以参考https://gitcafe.com/atskyline/WPFTimeSpanPickerControl
参考资料
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
转载文章来源:http://www.cnblogs.com/atskyline/archive/2012/11/16/2773806.html
相关文章推荐
- C#中byte类型转换为double类型
- 逻辑题笔记
- 编写一个文字游戏
- Easyui的DateBox日期格式化
- matlab冒号的用法总结
- hibernate mysql 时间类型
- Scala School 笔记(五)--高级类型
- ORA-12052: cannot fast refresh materialized view DCS_BIZ.MV_TMP_16
- std::mutex 和 std::lock_guard 小例子
- 多行文字溢出时自动转成”...“
- tomcat移动位置后相关问题解决方案
- Scala School 笔记(四)--类型和多态基础
- MatLab基础知识小结
- spring四种依赖注入方式
- 那些年我们一起清除过的浮动
- 通途 - 爱商
- mongodb:在mongo终端上操作将数据从一个字段复制到另一个字段上。
- 邮箱自动填充js
- mysql三大循环(while ,repeat,loop)
- placeholder在某些浏览器下不垂直居中问题