我正在开发我的第一个 WPF 自定义控件,但遇到了一些问题,这是我目前使用的代码的简化版本:
using System.Windows;
using System.Windows.Controls;
namespace MyControls
{
[TemplatePart(Name = "PART_Button", Type = typeof (Button))]
public class MyControl : Control
{
public static readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof (object), typeof (MyControl), new PropertyMetadata(null, OnLabelPropertyChanged));
private Button _buttonElement;
public object Content
{
get { return this.GetValue(LabelProperty); }
set { this.SetValue(ContentProperty, value); }
}
static MyControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof (MyControl), new FrameworkPropertyMetadata(typeof (MyControl)));
}
private static void OnContentPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
MyControl myControl = sender as MyControl;
if (myControl != null && myControl._buttonElement != null)
myControl._buttonElement.Content = e.NewValue;
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
this._buttonElement = this.Template.FindName("PART_Button", this) as Button;
}
}
}
这是我的自定义控件的模板:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyControls">
<Style TargetType="{x:Type local:MyControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MyControl}">
<Button x:Name="PART_Button" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
然后我把它放在一个 Grid 中并尝试设置它的 Content 属性:
<Grid x:Name="layoutRoot">
<controls:MyControl x:Name="myControl" />
</Grid>
这是后面的代码:
using System.Windows;
namespace MyControls
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
this.InitializeComponent();
this.myControl.Content = "test";
}
}
}
这不起作用,由于某种原因,在 OnApplyTemplate 之前调用了 OnContentPropertyChanged 回调,因此 myControl._buttonElement 分配得太晚,并且在尝试设置其内容时它仍然为空。为什么会发生这种情况,我该如何改变这种行为?
我还需要提供完整的设计时支持,但我找不到让我的自定义控件接受一些额外标记的方法,就像 Grid 控件对 ColumnDefinitions 所做的那样:
<Grid x:Name="layoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
任何帮助将不胜感激!
更新
我找到了一个文档,解释了为什么在设置控制属性后调用 OnApplyTemplate 方法:
http://msdn.microsoft.com/en-us/library/dd351483%28v=vs.95%29.aspx
所以问题是:如何跟踪设置的属性(在 XAML 中或以编程方式)和在控件尚未初始化时调用的方法,以便在调用 OnApplyTemplate 方法时设置/调用它们?相同的回调/方法如何在控件初始化之前和之后工作而不复制代码?