您的位置:首页 > 其它

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

2014-02-14 17:06 232 查看
建一个用户可以使用Template属性设置外观的WPF控件需要以下几步

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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: