c# - 从 DataTemplate 设置的自定义 DependencyProperty

标签 c# wpf xaml datatemplate

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

我的控件正在其构造函数中设置自定义依赖属性的默认值。当我在 DataTemplate 中使用该控件时,始终使用在构造函数中设置的值,即使我尝试在 XAML 中设置它也是如此。

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

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

这里有一些代码可以帮助说明我的问题:

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 中未指定该值,那么我想回退到控件构造函数中设置的默认值。

如果我直接将控件包含在 View 中,我会得到预期的行为。如果控件在 DataTemplate 中使用,那么我总是在构造函数中获取默认设置(即使数据模板明确设置了另一个值)。

在模板中使用控件时,有没有其他方法可以指定默认值?我能想到的唯一选择是将控件分成几个独立但相似的控件,每个控件都使用一个在依赖属性中注册的默认值(这样就不需要根据 Mode 属性)。

最佳答案

OnApplyTemplate 中设置默认值,同时添加一个小检查应该可以解决这个问题:

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();
    }
}

请注意,虽然这可行,但并不理想,因为通过代码设置属性的值实际上会清除该属性的所有数据绑定(bind)。例如,在代码中调用 MyProperty = 42 后,以下绑定(bind)将不再有效:

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

通过使用 SetCurrentValue(MyPropertyProperty, GetDefaultPropertyValue()); 修改属性而不是 MyProperty = GetDefaultPropertyValue(),应该可以在保持任何绑定(bind)的同时设置值>,但我也不确定我是否太喜欢它。

更好的解决方案

我要做的是在现有属性之外引入一个新的只读属性,它将充当计算属性。例如:

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();
}

关于c# - 从 DataTemplate 设置的自定义 DependencyProperty,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26106598/

相关文章:

c# - 在后台线程中创建元素,然后添加到主界面

c# - C# 中的 using(){...} 与 Cocoa 中的 autoreleasepool{...} 的用途相同吗?

c# - 在 Prism 6 中加载所有模块后使用 ViewModel 初始化 Shell

.net - 在ListView中同步IsSelected和SelectedItem

c# - TimeZoneInfo.ConvertTimeFromUtc 返回 1972 年的奇怪输出

c# - 为什么 C# 不允许将 using 变量作为 ref 或 out 传递给函数

c# - Preview Mouse Down 事件在第一次调用时返回带有空引用 CurrentColumn 的发件人

c# - WPF 如何从 ViewModel 访问控件

wpf - Mahapps Metro 窗口标题在任务栏中不可见

wpf - 列表框选定文本颜色