【问题标题】:Make binding work on property in a different class对不同类中的属性进行绑定
【发布时间】:2018-02-23 22:11:52
【问题描述】:

所以我有一个类MainViewModel,其中有一个按钮。该按钮导航到具有自己的视图模型的视图,让我们调用ListViewModel。它位于 MainViewModel 中。它有一个名为WorkOrdersObservableCollection

在我的主视图模型中,我的 ListViewModel 的列表中有一个属性,它返回项目数。但是,如果我将按钮文本绑定到此属性 (NumberOfWorkOrders),那么当 WorkOrders.Count() 更改时,什么也不会发生。即使我打电话给OnPropertyChanged("NumberOfWorkOrders")

但是,如果我绑定到 ListViewModel 中的相同属性,它确实有效。 MainViewModel中的属性怎么不起作用?是不是因为来自 INotifyPropertyChanged 的​​通知在不同的视图模型中不起作用?

不起作用的按钮绑定(使用 MainViewModel 的属性)

<Button 
    Content="{Binding NumberOfWorkOrders}" 
    ContentStringFormat="WorkOrders ({0})" />

可以工作的按钮绑定(使用来自 ListViewModel 的属性)

<Button 
    DataContext="{Binding LVM}"
    Content="{Binding NumberOfWorkOrders}" 
    ContentStringFormat="WorkOrders ({0})" />

MainViewModel.cs

public class MainViewModel : BindableBase
{
    // INotifyPropertiesChanged is implemented in BindableBase

    private ListViewModel listViewModel = new ListViewModel();

    // This is where I would like to bind my button text to
    public int NumberOfWorkOrders
    {
        get { return listViewModel.WorkOrders.Count(); }
    }

    // I would prefer not to have this
    public ListViewModel LVM
    {
        get { return listViewModel; }
    }
}

ListViewModel.cs

public class ListViewModel : BindableBase
{
    // INotifyPropertiesChanged is implemented in BindableBase

    public ObservableCollection<WorkOrder> WorkOrders
    {
        get; set;
    }

    // I would prefer to use the version of this in the MainViewModel
    public int NumberOfWorkOrders
    {
        get { return listViewModel.WorkOrders.Count(); }
    }

    public void RefreshWorkOrders()
    {
        (...) // Load work orders and add them to collection

        OnPropertyChanged("NumberOfWorkOrders");
    }
}

【问题讨论】:

  • Here你需要实现INotifyPropertyChanged
  • @Decoder94 我已经在我的BindableBase 类中实现了INotifyPropertyChanged,它被两个视图模型继承。我还应该在哪里实现它?
  • 它是绑定的来源,即 NumberOfWorkOrders 属性定义的类,需要引发 PropertyChanged 事件。

标签: c# wpf xaml binding


【解决方案1】:

你遇到this problem ,您有需要额外工作的聚合属性:您必须订阅ListViewModel.PropertyChanged 并针对MainViewModel.NumberOfWorkOrders 属性提出通知:

public class MainViewModel : BindableBase
{
    readonly ListViewModel listViewModel = new ListViewModel();
    public int NumberOfWorkOrders => listViewModel.WorkOrders.Count();

    public MainViewModel()
    {
        // since you already rise notification in ListViewModel
        // listen to it and "propagate"
        listViewModel.PropertyChanged += (s, e) =>
        {
            if(e.PropertyName == nameof(ListViewModel.NumberOfWorkOrders))
                OnPropertyChanged(nameof(NumberOfWorkOrders));
        };
    }
}

第一个按钮(不起作用)将MainViewModel 作为数据上下文,绑定只会监听此类中的通知。

作为一个简单的修复,您可以在绑定的Path 中包含LVM。绑定是智能的,将开始监听两个事件:主视图模型和LVM 属性给出的实例:

<Button Content="{Binding LVM.NumberOfWorkOrders}" ... />

然后您可以从MainViewModel 中删除NumberOfWorkOrders

【讨论】:

  • 谢谢,它有效。除了一件事。我不允许在MainViewModel() 的构造函数中使用nameof()(什么鸭子?)。我可以通过将属性名称输入为字符串来解决问题,所以唯一真正的问题是我的困惑......
【解决方案2】:

您的MainViewModel 绑定不起作用的原因是您从ListViewModel 上下文调用OnPropertyChanged("NumberOfWorkOrders")。 我建议在MainViewModel 中签署listViewModel.WorkOrders 中的更改,并在WorkOrders 更改时从MainViewModel 触发OnPropertyChanged("NumberOfWorkOrders")。您需要查看 ObservableCollection 的文档以了解如何签署收集更改通知。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-17
    • 2011-05-02
    相关资源
    最近更新 更多