WinRT DependencyProperty with IEnumerable 根本不会触发



自从我知道有很多关于依赖项属性的帖子以来,我已经搜索了又搜索,但我只是还没有看到任何具有有效解决方案的东西。我正在尝试将 ViewModel 中的 ObservableCollection 绑定到我的 AutoCompleteBox。我的视图模型正在返回数据,Getter 被击中。但是,在此之后,控件的 SetValue 或 OnItemsSourcePropertyChanged 不会触发。关于可能出现的问题的任何想法?

我有一个这样的控件:

[ContentProperty(Name = "ItemsSource")]
public partial class AutoCompleteBox : Control
{
    //local stuff
    private ListBox lb;
    private List<Person> _items;
    private ObservableCollection<Person> _view;
    public AutoCompleteBox() : base()
    {
        DefaultStyleKey = typeof(AutoCompleteBox);
        Loaded += (sender, e) => ApplyTemplate();
    }
    protected override void OnApplyTemplate()
    {
        this.lb = this.GetTemplateChild("Selector") as ListBox;
        base.OnApplyTemplate();
    }
    #region ItemsSource
    public IEnumerable ItemsSource
    {
        get { return GetValue(ItemsSourceProperty) as ObservableCollection<Person>; }
        set { SetValue(ItemsSourceProperty, value); } //Never gets called
    }
    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register(
            "ItemsSource",
            typeof(IEnumerable),
            typeof(AutoCompleteBox),
            new PropertyMetadata(null, OnItemsSourcePropertyChanged));
    private static void OnItemsSourcePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
       //Never gets called :(
    }
    #endregion
    public String SearchText
    {
        get { return GetValue(SearchTextProperty) as String; }
        set
        {
            SetValue(SearchTextProperty, value);
        }
    }

    public static readonly DependencyProperty SearchTextProperty =
        DependencyProperty.Register(
            "SearchText",
            typeof(String),
            typeof(AutoCompleteBox),
            new PropertyMetadata(null, OnSearchTextPropertyChanged));
    private static void OnSearchTextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
         //gets fired when loaded, with data being bound
    }
}

下面是控件的使用方式:

<toolkit:AutoCompleteBox Grid.Row="5" Grid.Column="2" ItemsSource="{Binding Persons,Mode=TwoWay}" SearchText="WhatTheHell"/>

作为测试和简单起见,我为 SearchText 创建了一个字符串依赖属性。如果我绑定搜索文本,它工作正常,OnSearchTextPropertyChanged 被调用:

<toolkit:AutoCompleteBox Grid.Row="5" Grid.Column="2" ItemsSource="{Binding Persons,Mode=TwoWay}" SearchText="{Binding SearchText}"/>

还有其他人在使用 WinRT 时遇到这些问题吗?或者发现我正在做的事情有什么问题?

有 2 个快速解决方案

(例如,这里的 BaseClass 是一个抽象类或接口,您从中派生,并且您尝试将其实例绑定到依赖项属性(

解决方案 1:

注册依赖项属性时,需要将typeof(BaseClass)更改为typeof(object)。Getter 和 setter 可以继续使用 BaseClass,但如果为此依赖项属性设置了不同类型的实例,请注意 InvalidCastException。

        public BaseClass Item
        {
            get { return (BaseClass)GetValue(ItemProperty); }
            set { SetValue(ItemProperty, value); }
        }
        public static readonly DependencyProperty ItemProperty =
            DependencyProperty.Register("Item", typeof(object), typeof(MyUserControl), new PropertyMetadata(null));

解决方案 2:

在代码中的某处创建一个虚拟依赖项属性(例如,紧跟在您尝试创建的依赖项属性之后(,该属性将具有所有派生类型的类型。喜欢这个:

#region DummyProperty
public DerivedClass1 Dummy
{
    get { return (DerivedClass1)GetValue(DummyProperty); }
    set { SetValue(DummyProperty, value); }
}
public static readonly DependencyProperty DummyProperty =
    DependencyProperty.Register("Dummy", typeof(DerivedClass1), typeof(MyUserControl), new PropertyMetadata(default(DerivedClass1)));
#endregion

这里 DerivedClass1 派生自 BaseClass

为什么?

我想原因是 XAML 对您的派生类型一无所知,只知道基类。因此,为每种类型创建一个虚拟依赖项属性应该可以解决问题。

我会尝试检查绑定是否曾经使用 DebugConverter 触发 - 检查 WinRT XAML 工具包中的 BindingDebugConverter - 将其设置为绑定的转换器,并查看它是否以及何时中断(它是在转换还是转换回来中,正在设置什么值等(。

如果这没有帮助 - 请检查您的数据上下文设置是否正确。

*编辑 1

如果您正在查找的是绑定集合的项中的更改 - 您可以检查 ItemsSource 是否为 INotifyCollectionChanged,如果为 true,则订阅 CollectionChanged 事件以查看更改。否则 - 您可以修改控件以从 ItemsControl 继承,并重写 GetContainerForItemOverride 和 IsItemItsOwnContainerOverride 等方法。

*编辑2

Windows 8 消费者预览版中的框架中似乎存在与使用 IEnumerable 作为依赖项属性类型相关的错误。使用 object 作为类型可以解决问题。如果启用本机代码调试,您将看到以下绑定异常:

错误:转换器无法转换类型为"System.Collections.ObjectModel.ObservableCollection"1[[ACBDP.人员、ACBDP、版本=1.0.0.0、区域性=中性、公钥令牌=空]]、系统、版本=4.0.0.0、区域性=中性、公钥令牌=b77a5c561934e089"以键入"IEnumerable";BindingExpression: Path='Persons' DataItem='ACBDP.BlankPageViewModel, ACBDP, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null';目标元素是"ACBDP"。AutoCompleteBox' (Name='null'(;目标属性是"ItemsSource"(类型"IEnumerable"(。

将 typeof(IEnumerable( 更改为 typeof(object(

相关内容

  • 没有找到相关文章

最新更新