Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 来自DataTemplate的自定义DependencyProperty集_C#_Wpf_Xaml_Datatemplate - Fatal编程技术网

C# 来自DataTemplate的自定义DependencyProperty集

C# 来自DataTemplate的自定义DependencyProperty集,c#,wpf,xaml,datatemplate,C#,Wpf,Xaml,Datatemplate,我正在使用一个自定义控件,该控件具有多个用户定义的依赖属性。我遇到了中描述的相同问题 我的控件正在其构造函数中设置自定义依赖项属性的默认值。在数据模板中使用控件时,始终使用构造函数中设置的值,即使我尝试在XAML中设置它 链接问题的答案解释了C#代码中设置的值具有更高的优先级,更好的方法是在dependency属性的元数据中指定默认值 在我的例子中,我不能指定默认值,因为dependency属性没有一个适用于所有情况的默认值。默认值依赖于另一个属性,因此我必须在创建控件时查找它们,而不是在注册属

我正在使用一个自定义控件,该控件具有多个用户定义的依赖属性。我遇到了中描述的相同问题

我的控件正在其构造函数中设置自定义依赖项属性的默认值。在
数据模板
中使用控件时,始终使用构造函数中设置的值,即使我尝试在XAML中设置它

链接问题的答案解释了C#代码中设置的值具有更高的优先级,更好的方法是在dependency属性的元数据中指定默认值

在我的例子中,我不能指定默认值,因为dependency属性没有一个适用于所有情况的默认值。默认值依赖于另一个属性,因此我必须在创建控件时查找它们,而不是在注册属性时查找它们

下面是一些代码来帮助说明我的问题:

public partial class MyControl : UserControl
{
    public static readonly DependencyProperty MyProperty = 
            DependencyProperty.Register(
                "MyProperty",
                typeof(int),
                typeof(MyControl),
                new FrameworkPropertyMetadata(
                    int.MinValue,
                    FrameworkPropertyMetadataOptions.None,
                    new PropertyChangedCallback("OnMyPropertyChanged")));

    public MyControl() : base()
    {
        InitializeComponent();
        this.MyProperty = GetDefaultPropertyValue();
    }

    public int MyProperty
    {
        get { return (int)GetValue(MyProperty); }
        set { SetValue(MyProperty, value); }
    }

    private int GetDefaultPropertyValue()
    {
        // look up the appropriate default based on some other criteria
        return 42;

        // (in reality, the default value for "MyProperty"
        // depends on the value of a "Mode" custom DependencyProperty.
        // this is just hard coded for testing)
    }   
}
XAML的用法如下所示:

<!-- View displays 4 (desired) -->
<local:MyControl MyProperty="4" />

<!-- View displays default of 42 (desired) -->
<local:MyControl />

<!-- View displays default of 42 (wanted 4) -->
<DataTemplate x:Key="MyTemplate">
    <local:MyControl MyProperty="4"/>
</DataTemplate>

总结如下:

所需的行为是首先使用XAML中的值。如果没有在XAML中指定该值,那么我想退回到控件构造函数中设置的默认值

如果我只是将控件直接包含在视图中,我将获得预期的行为。如果控件在
数据模板
中使用,那么我总是在构造函数中获得默认设置(即使数据模板显式设置了另一个值)


在模板中使用控件时,是否有其他方法指定默认值?我能想到的唯一选择是将控件拆分为几个单独但相似的控件,每个控件都使用一个默认值,该值是在dependency属性中注册的(这就不需要基于a
模式
属性设置默认值).

在应用程序模板的
中设置默认值,同时添加一个小的检查应该可以解决以下问题:

public override void OnApplyTemplate()
{
    base.OnApplyTemplate();

    // Only set the default value if no value is set.
    if (MyProperty == (int)MyPropertyProperty.DefaultMetadata.DefaultValue)
    {
        this.MyProperty = GetDefaultPropertyValue();
    }
}
请注意,尽管这会起作用,但这并不理想,因为通过代码设置属性的值实际上会清除此属性的任何数据绑定。例如,一旦在代码中调用
MyProperty=42
,以下绑定将不再工作:

<local:MyControl MyProperty="{Binding SomeProperty}" />

这确实有效,谢谢!既然我只是在XAML中没有设置属性的情况下通过代码设置属性,那么假设没有要破坏的数据绑定是安全的吗?(我们从不在代码中创建绑定)在您的示例中,您展示了如何在xaml中设置属性:
如果这是设置属性的唯一方法,并且永远不要使用绑定(请参见我的编辑),那么您不必担心,尽管覆盖绑定被认为不是一个好的实践将破坏任何绑定。如果我使用的是您在编辑中添加的绑定,那么只要该绑定的计算结果不是
MyProperty.DefaultMetadata.DefaultValue
,就不会调用该绑定,也不会破坏该绑定,对吗?您能否详细介绍一下您推荐的具有只读属性的解决方案?我不确定我是否明白。我找到了更好的解决方案,并接受了你的答案。我不知道这是怎么回事。添加只读依赖项属性对原始属性有何影响?另请参阅中有关
SetValue
SetCurrentValue
之间差异的详细信息
private static readonly DependencyPropertyKey MyCalculatedPropertyPropertyKey =
    DependencyProperty.RegisterReadOnly("MyCalculatedProperty", typeof(int), typeof(MyControl),
    new PropertyMetadata(int.MinValue));

public static readonly DependencyProperty MyCalculatedPropertyProperty = MyCalculatedPropertyPropertyKey.DependencyProperty;

public int MyCalculatedProperty
{
    get { return (int)GetValue(MyCalculatedPropertyProperty); }
    private set { SetValue(MyCalculatedPropertyPropertyKey, value); }
}

private static void OnMyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ((MyControl)d).MyCalculatedProperty = (int)e.NewValue;
}

public MyControl()
    : base()
{
    InitializeComponent();
    MyCalculatedProperty = GetDefaultPropertyValue();
}