WPF 依赖属性优先级 &引用类型默认值 [英] WPF dependency property precedence & reference type Default Values

查看:35
本文介绍了WPF 依赖属性优先级 &引用类型默认值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我创建一个这样的自定义控件:

If I create a custom control like this:

public class MyControl : ContentControl
{
   public static readonly DependencyProperty ItemsProperty =               
         DependencyProperty.Register(
                "Items", 
                typeof(ObservableCollection<object>), 
                typeof(MyControl), 
                new PropertyMetadata(null));

   public MyControl()
   {   
       // Setup a default value to empty collection
       // so users of MyControl can call MyControl.Items.Add()
       Items = new ObservableCollection<object>();
   }

   public ObservableCollection<object> Items
   { 
      get { return (ObservableCollection<object>)GetValue(ItemsProperty); } 
      set { SetValue(ItemsProperty, value); } 
   } 
}

然后允许用户像这样在 Xaml 中绑定到它:

And then allow the user to bind to it in Xaml like this:

<DataTemplate>
    <MyControl Items="{Binding ItemsOnViewModel}"/>
</DataTemplate>

然后绑定永远不会起作用!这是由于 Dependency Property Precedence 将 CLR Set值高于模板绑定!

Then the binding never works! This is due to the Dependency Property Precedence, which puts CLR Set values above Template bindings!

所以,我明白为什么这不起作用,但我想知道是否有解决方案.对于只想以编程方式添加项目的 MyControl 的懒惰消费者,是否可以为新的 ObservableCollection 提供 ItemsProperty 的默认值,同时允许 My Control 的 MVVM 高级用户通过 DataTemplate 绑定到相同的属性?

So, I understand why this isn't working, but I wonder if there is a solution. Is it possible to provide a default value of ItemsProperty to new ObservableCollection for lazy consumers of MyControl that just want to add Items programmatically, while allowing MVVM power-users of My Control to bind to the same property via a DataTemplate?

这是为了 Silverlight &WPF.样式中的 DynamicResource setter 似乎是一个解决方案,但不适用于 Silverlight :(

This is for Silverlight & WPF. DynamicResource setter in a style seemed like a solution but that won't work for Silverlight :(

更新:

我可以确认 SetCurrentValue(ItemsProperty, new ObservableCollection()); 完全符合我的要求 - 在 WPF 中.它写入默认值,但它可以被模板绑定覆盖.谁能推荐一个等效的 Silverlight?说起来容易做起来难!:s

I can confirm SetCurrentValue(ItemsProperty, new ObservableCollection<object>()); does exactly what I want - in WPF. It writes the default value, but it can be overridden by template-bindings. Can anyone suggest a Silverlight equivalent? Easier said than done! :s

另一个更新:

显然,您可以使用值强制在 .NET3.5 中模拟 SetCurrentValue,并且您可以使用这些技术在 Silverlight 中模拟值强制.也许这里有一个(冗长的)解决方法.

Apparently you can simulate SetCurrentValue in .NET3.5 using value coercion, and you can simulate value coercion in Silverlight using these techniques. Perhaps there is a (long-winded) workaround here.

使用值强制为 .NET3.5 设置当前值解决方法
Silverlight 的值强制转换方法

推荐答案

当 ObservableCollection 属性出现异常时,我会尝试丢弃对该属性的赋值.我发现引用没有正确翻译并且绑定丢失了,不知何故.因此,我实际上避免了设置 ObservableCollection 属性(相反,我更喜欢清除现有属性并向其添加元素).这在使用 DependencyProperty 时真的变得很草率,因为您将在 setter 中多次调用 getter.您可能要考虑改用 INotifyPropertyChanged.无论如何,这就是它的样子:

When ObservableCollection properties misbehave, I try throwing out assignments to that property. I find that the references don't translate right and bindings get lost, somehow. As a result, I avoid actually setting ObservableCollection properties (preferring, instead, to clear the existing property and add elements to it). This becomes really sloppy with a DependencyProperty because you're going to call your getter multiple times in your setter. You might want to consider using INotifyPropertyChanged instead. Anyway, here's what it'd look like:

公然从 SteveL 的回答中偷走了吸气剂.我对其进行了修改,以便您只需调用一次 GetValue,就可以了.很好的解决方法.

Blatantly stole the getter from SteveL's answer. I reworked it a touch so that you only have a single call to GetValue, is all. Good work around.

public ObservableCollection<object> Items
{ 
    get
    {
        ObservableCollection<object> coll = (ObservableCollection<object>)GetValue(ItemsProperty);
        if (coll == null)
        {
            coll = new ObservableCollection<object>();
            this.SetValue(ItemsProperty, coll);
        }

        return coll;
    }
    set 
    {
        ObservableCollection<object> coll = Items;
        coll.Clear();
        foreach(var item in value)
            coll.Add(item);
    }
} 

请注意,这取决于您的默认设置是否正确.这意味着将静态 ItemsProperty 默认更改为正确类型的新 ObservableCollection(即 new PropertyMetadata(new ObservableCollection()).您还必须在构造函数中删除该 setter.请注意,我不知道是否那样'会实际工作.如果没有,你肯定想改用 INotifyPropertyChanged...

Note that this is depending on your default to set correctly. That means changing the static ItemsProperty default to be a new ObservableCollection of the correct type (i.e. new PropertyMetadata(new ObservableCollection()). You'll also have to remove that setter in the constructor. And note, I've no idea if that'll actually work. If not, you'll want to move to using INotifyPropertyChanged for sure...

这篇关于WPF 依赖属性优先级 &amp;引用类型默认值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆