如何使用模板成员属性

本文关键字:成员 属性 何使用 | 更新日期: 2023-09-27 18:08:51

首先,我为下面这个冗长的问题道歉。由于我是WPF的新手,我决定解释更多,以便可能获得更多的技巧!


我有一个UserControl:

<UserControl x:Class="MyNamespace.MyUserControl2"...
             xmlns:local="clr-namespace:MyNamespace"
             Style="{DynamicResource ResourceKey=style1}">
    <UserControl.Resources>
        <Style x:Key="style1" TargetType="{x:Type UserControl}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type UserControl}">
                        ...
                        <local:MyUserControl1 x:Name="myUserControl1" .../>
                        ...
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>
</UserControl>
为了从后面的代码访问myUserControl1,我使用了一个属性。
private MyUserControl1 _myUserControl1;
private MyUserControl1 myUserControl1
{
    get
    {
        if (_myUserControl1 == null)
            _myUserControl1 = this.Template.FindName("myUserControl1", this) as MyUserControl1;
        return _myUserControl1;
    }
}

(这是访问模板成员的好方法吗?)

另一方面,在MyUserControl2类中有一个依赖属性(比如DP1),它负责修改myUserControl1依赖属性之一。(说SomeProperty)

private static void IsDP1PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var instance = d as MyUserControl2;
    if (instance != null)
    {
        instance.myUserControl1.SomeProperty = function(e.NewValue);
    }
}

当我尝试运行上面的代码时,我注意到这个实例。myUserControl1为空。所以我是这样处理的:

if (instance != null && instance.myUserControl1 != null)
{
    instance.myUserControl1.SomeProperty = function(e.NewValue);
}

虽然这种方法解决了这个问题,但它导致myUserControl1.SomeProperty保持未初始化状态。因此,我将以下代码片段放在加载的事件中来解析它:

private void MyUserControl2_Loaded(object sender, RoutedEventArgs e)
{
    this.myUserControl1.SomeProperty = function(DP1);
}

在那之后,我遇到了另一个问题!

当我使用style的setter属性为DP1设置一些值时,我收到了null引用异常,该异常表示myUserControl1属性在加载的事件中仍然为null。我该如何解决这个问题?-谢谢。

如何使用模板成员属性

我猜你对WPF还不是很清楚。

你遇到了这么多麻烦,因为你的方法更"像winforms",而不是功能。如果你坚持以命令式的方式使用WPF,你的生活会变得更加困难。

首先,模板表示一个函数,该函数指示WPF引擎如何在运行时创建实际的可视化树。你应该在宿主控件(即MyUserControl2)内的模板ONLY中使用该名称作为引用,并从OnApplyTemplate方法中获取实例引用。没有别的地方。

的例子:

private MyUserControl1 _myUserControl1;
public override void OnApplyTemplate()
{
  this._myUserControl1 = this.GetTemplateChild("myUserControl1") as MyUserControl1;
  //here you should check whether the instance is actually set
}

任何被托管的控件的引用都应该保持为私有:任何被托管的控件都不能被保护/内部/公开。

第二点:如何将两个属性绑定在一起

您的目标是将控件的一个属性与宿主控件公开的另一个属性"绑定"。这个任务是绝对正常的,它是WPF提供的最好的特性之一。

假设两个属性具有相同的类型,因此可以直接绑定。在xaml:

    <ControlTemplate TargetType="{x:Type UserControl}">
         ...
       <local:MyUserControl1 x:Name="myUserControl1" 
   SomeProperty="{Binding Path=DP1, RelativeSource={RelativeSource Mode=TemplatedParent}}"
   .../>
         ...
    </ControlTemplate>

注意:(1)SomeProperty必须是一个DependencyProperty,(2)必须是可写的,(3)DP1必须也是一个DP,或者-至少-通过INotifyPropertyChanged模式通知任何更改。

所描述的语法通常绑定:SomeProperty = DP1,但反之并非如此。如果你需要双向映射,你应该在"Binding"子句中添加"Mode=TwoWay"。

如果您想自定义映射这两个属性的函数,只需通过IValueConverter接口定义您自己的转换器,然后在xaml.

在这里你会发现一些有用的信息:http://msdn.microsoft.com/en-us/library/ms752347.aspx

欢呼