WPF依赖属性优先级&引用类型默认值

时间:2012-11-01 16:50:38

标签: wpf silverlight xaml dependency-properties

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

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中绑定它,如下所示:

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

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

所以,我理解为什么这不起作用,但我想知道是否有解决方案。是否可以为MyControl的懒惰使用者提供一个默认值ItemsProperty,以便以编程方式添加Items,同时允许My Control的MVVM高级用户通过DataTemplate绑定到同一属性?

这适用于Silverlight&amp; WPF。一个样式的DynamicResource setter似乎是一个解决方案,但对Silverlight不起作用:(

更新:

我可以确认 SetCurrentValue(ItemsProperty, new ObservableCollection<object>()); 完全符合我的要求 - 在WPF中。它写入默认值,但可以通过模板绑定覆盖它。 任何人都可以建议Silverlight等效吗?说起来容易做起来难! :■

另一个更新:

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

SetCurrentValue workaround for .NET3.5 using Value Coercion
Value Coercion workaround for Silverlight

2 个答案:

答案 0 :(得分:0)

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

编辑:Blatantly偷走了SteveL的回答。我重新设计了一下触摸,这样你只需要一次GetValue调用就可以了。好的工作。

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 ......

答案 1 :(得分:0)

您不能只指定依赖项属性的默认属性:

  public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register(
        "Items",
        typeof(ObservableCollection<object>),
        typeof(CaseDetailControl),
        new PropertyMetadata(new ObservableCollection<object>()));

或者我错过了你的目标?

编辑:

啊......在那种情况下如何在getter上检查null?:

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

            return (ObservableCollection<object>)GetValue(ItemsProperty);
        }

        set
        {
            this.SetValue(ItemsProperty, value);
        }
    }