C# 如何使用模板成员属性

C# 如何使用模板成员属性,c#,wpf,user-controls,C#,Wpf,User Controls,首先,我为下面这个冗长的问题道歉。因为我是WPF的新手,所以我决定做更多的解释,以获得更多的提示 我有一个用户控件,如: <UserControl x:Class="MyNamespace.MyUserControl2"... xmlns:local="clr-namespace:MyNamespace" Style="{DynamicResource ResourceKey=style1}"> <UserContr

首先,我为下面这个冗长的问题道歉。因为我是WPF的新手,所以我决定做更多的解释,以获得更多的提示


我有一个用户控件,如:

<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>
(这是访问模板成员的好方法吗?)

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

当我尝试运行上述代码时,我注意到instance.myUserControl1为null。所以我就这样对待它:

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);
}
在那之后,我遇到了另一个问题


当我使用样式的setter属性将某个值设置为
DP1
时,我收到一个null引用异常,该异常表示
myUserControl1
属性在加载的事件中仍然为null。我怎样才能解决这个问题-谢谢。

我想你对WPF还不太清楚

您遇到了很多麻烦,因为您的方法更像“winforms”,而不是功能性的。如果你坚持以一种强制性的方式使用WPF,它会让你的生活更加艰难

首先,模板表示一个函数,用于指示WPF引擎如何在运行时创建实际的可视化树。您应该仅在宿主控件(即MyUserControl2)内的模板中将名称用作引用,并从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中声明它

在这里,您可以找到一些有用的信息:


干杯

谢谢@Mario。这是非常有用的。
private MyUserControl1 _myUserControl1;

public override void OnApplyTemplate()
{
  this._myUserControl1 = this.GetTemplateChild("myUserControl1") as MyUserControl1;
  //here you should check whether the instance is actually set
}
    <ControlTemplate TargetType="{x:Type UserControl}">
         ...
       <local:MyUserControl1 x:Name="myUserControl1" 
   SomeProperty="{Binding Path=DP1, RelativeSource={RelativeSource Mode=TemplatedParent}}"
   .../>
         ...
    </ControlTemplate>