【问题标题】:Binding to an initially NULL property in the ViewModel doesn't rebind绑定到 ViewModel 中最初为 NULL 的属性不会重新绑定
【发布时间】:2013-01-31 21:55:20
【问题描述】:

我有一个包含 Telerik RadDataForm 的用户控件。表单的 ItemsSource 绑定到 UserControl 的 ViewModel 上的一个属性:

<telerik:RadDataForm
    ItemsSource="{Binding Path=viewModel.items, RelativeSource={RelativeSource AncesterType=local:MyUserControl}}"
    />

viewModel 在哪里:

public partial class MyUserControl: UserControl
{
    public MyUserControlVM viewModel
    { get { return this.DataContext as MyUserControlVM; } }
}

在视图模型中,items 是一个相当普通的集合:

public class MyUserControlVM : MyViewModelBase
{
    private ObservableCollection<AnItem> items_;
    public ObservableCollection<AnItem> items
    {
        get { return this.items_; }
        set
        {
            this.items_ = value;
            notifyPropertyChanged("items");
        }
    }

    ...
}

当然,MyViewModelBase 在哪里实现了 INotifyPropertyChanged。

用户控件有一个items依赖属性,设置时会在视图模型上设置匹配属性:

public partial class MyUserControl : UserControl
{
    public ObservableCollection<AnItem> items
    {
        get { return GetValue itemsProperty as ObservableCollection<AnItem>; }
        set { SetValue(itemsProperty, value); }
    }
    public static readonly DependencyProperty itemsProperty =
        DependencyProperty.Register("items",
        typeof(ObservableCollection<AnItem>), 
        typeof(MyUserControl), new PropertyMetadata(
                    new PropertyChangedCallback(itemsPropertyChanged)));
    private static void itemsPropertyChanged(DependencyObject d,
            DependencyPropertyChangedEventArgs e)
    {
        MyUserControl myUserControl = d as MyUserControl;
        ObservableCollection<AnItem> items = 
            e.NewValue as ObservableCollection<AnItem>;
        if (myUserControl != null && myUserControl.viewModel != null)
            myUserControl.viewModel.items = items;
    }
}

所有这些看起来都很简单,虽然有点乏味。

问题是 MyUserControl 上的 items 依赖属性绑定到另一个集合的当前项的属性,并且当前项最初为 null,因此当最初加载 MyUserControl 时,它的 items 属性为 null。因此,RadDataForm 绑定到的 MyUserControlVM 上的 items 属性也是如此。

稍后,当该外部集合中的项目变为当前项目时,将设置 MyUserControl 上的项目依赖属性,并设置 MyUserControlVM 上的项目属性。 MyUserControlVM 调用 notifyPropertyChanged 以便将更改通知侦听器。但这最后一个不起作用。

之后,如果我检查 RadDataForm,它的 ItemsSource 属性仍然为 null。

这就像 RadDataForm 没有监听 propertychanged 事件,因为它最初绑定的是 null。在绑定属性在开始时不为 null 的类似情况下,当当前项从一项更改为另一项时,此模式可以正常工作,但从没有当前项到有一项似乎不起作用。

那么,关于如何完成这项工作的任何想法?在这种情况下,我不能让它在表单加载时始终具有值 - 一开始它总是为空。当属性变为非空时,如何让 RadDataForm 注意到?

【问题讨论】:

  • DataContext 发生变化时,你会为"viewModel" 解雇PropertyChanged 吗?
  • 尝试将 Path=viewModel.itemsPath=DataContext.items 重调。
  • “当 DataContext 发生变化时,你会为“viewModel”触发 PropertyChanged 吗?” - DataContext 不会改变。它在 UserControl 的构造函数中设置并且永远不会改变。
  • “尝试将 Path=viewModel.items 与 Path=DataContext.items 相匹配” - 没有区别。
  • DependencyProperty.Register("itemsProperty" - 名称应该是 "items",而不是 "itemsProperty"

标签: wpf xaml binding


【解决方案1】:

当我想在我的UserControl 的根目录引用某些东西(例如,一个自定义属性,或者在你的情况下,DataContext),我通常给我的 UserControl 一个Name。然后我使用这个名称和Binding 上的 ElementName 属性来设置它。

<UserControl
    ...
    Name="TheControl">

    <Grid>
        <TextBlock Text={Binding Path=DataContext.items, ElementName=TheControl}" />
    </Grid>
</UserControl>

由于viewModel 属性,您可以使用它和DataContext 互换。

然而,在你的情况下,它实际上可能更简单。首先,您的代码中有一个错字。它应该是AncestorType(带有“o”)。其次,您可能想尝试仅使用{Binding Path=items} 设置绑定,因为我相信您的控件已经继承了正确的DataContext。 (但不确定最后一个。)

如果问题仍然存在,并且您怀疑它实际上与最初返回 nullitems 属性有关,您始终可以使用空集合初始化 items_ 以避免 null .

private ObservableCollection<AnItem> items_ = new ObservableCollection<AnItem>();

【讨论】:

  • 如果在使用用户控件时使用 XAML 指定了 x:Name,我希望 Name 会被覆盖。但在快速测试中,这似乎并没有发生。是时间问题吗?
  • 在 RadDataForm 的上下文中使用 {Binding Path=items} 会绑定到 RadDataForm 的 DataContext 中的一个属性,这与我的 UserControl 的 DataContext 不同。
  • 您说“表单的 ItemsSource 绑定到 UserControl 的 ViewModel 上的属性”,我将其解释为它们共享相同的数据上下文。我错过了什么?
  • 您对更改名称的评论是正确的!谢谢你指出这一点。但是,它不会影响行为。用户控件内的 ElementName 绑定即使在其名称更改后也能正常工作。我想这不是偶然的,而是设计使然。
  • 表单的 ItemsSource 不是它的 DataContext。我测试了重命名的东西,并注意到它有效。至少在最简单的情况下。
猜你喜欢
  • 2013-06-25
  • 2011-02-01
  • 2012-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多