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

查看:323
本文介绍了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>

然后,绑定永不起作用!这是由于依赖属性优先级导致放置CLR集值,而不是模板绑定!

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

因此,我知道为什么这行不通,但是我想知道是否有解决方案。是否有可能为MyControl的懒惰使用者提供新的ObservableCollection的ItemsProperty的默认值,这些使用者仅希望以编程方式添加Items,同时允许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< object>()); 确实符合我的要求-在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,并且可以模拟值强制

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.

使用Value Coercion进行.NET3.5的SetCurrentValue解决方法

Silverlight的Value Coercion解决方法

推荐答案

如果ObservableCollection属性行为不当,我会尝试抛出分配到那个财产。我发现参考文献翻译不正确,并且绑定以某种方式丢失。结果,我实际上避免了 setting ObservableCollection属性(而是希望清除现有属性并向其中添加元素)。由于您将在setter中多次调用getter,因此使用DependencyProperty变得确实很草率。您可能需要考虑使用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(即,新的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依赖项属性优先级参考类型默认值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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