【问题标题】:How to bind to child view model property in WPF application?如何在 WPF 应用程序中绑定到子视图模型属性?
【发布时间】:2017-06-21 12:47:03
【问题描述】:

我正在使用 Prism MVVM 框架开发 WPF 应用程序。而且我不知道如何正确地在父视图模型和子视图模型之间传递数据。

我有 2 个视图模型 - ParentViewModel 和内部 ChildViewModel。

public class ParentViewModel
{
    public ParentViewModel
    {
        ChildViewModel = new ChildViewModel(params);
    }

        private ChildViewModel _childViewModel;
        public ChildViewModel ChildViewModel
        {
            get { return _childViewModel; }
            set
            {
                SetProperty(ref _childViewModel, value);
            }
        }

        //This is does not work
        public int SelectedChildNumber
        {
            return _childViewModel.SelectedNumber;
        }
}

public class ChildViewModel
{
    public ChildViewModel
    {
        _numbers = new List<int>();
    }

    private List<int> _numbers;
    public List<int> Numbers
    {
        get { return _numbers; }
        set
        {
            SetProperty(ref _numbers, value);
        }
    }

    private int _selectedNumber;
    public int SelectedNumber
    {
        get { return _selectedNumber; }
        set
        {
            SetProperty(ref _selectedNumber, value);
        }
    }
}

我想从子视图模型中获取和使用选定的值。我的方法不起作用 - 如果 ChildViewModel 中的 SelectedNumber 发生变化,SelectedChildNumber 不想刷新。

更新: 好的,如果我在 ParentViewModel 中有 ChildViewModel 集合怎么办。此 ChildViewModel 之一的属性 IsSelected 等于 true。如何从集合中获取这个选定的视图模型?

public class ParentViewModel
{
    public ParentViewModel
    {
        Items = GetItems();
    }

    private ObservableCollection<ChildViewModel> _items;
    public ObservableCollection<ChildViewModel> Items
    {
        get
        {
            return _items;
        }
        set
        {
            SetProperty(ref _items, value);
        }
    }
}

public class ChildViewModel
{
    public ChildViewModel
    {
    }

    private bool _isSelected;
    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            SetProperty(ref _isSelected, value);
        }
    }
}

如何获取选定的视图模型?也许使用转换器?

<someUserControl DataContext="{Binding ParentViewModel.Items, Converter={x:Static c:GetSelectedItemConverter.Instance}}" />

在转换器中,我可以找到选定的项目。或者这是个坏主意?

更新 2:

好的,我在 Ed Plunkett 的帮助下解决了这个问题。最终版本应该是:

public class ParentViewModel
{
    public ParentViewModel
    {
        Items = GetItems();
        foreach (var item in Items)
        {
            item.PropertyChanged += ChildViewModel_PropertyChanged;
        }
    }

    private ObservableCollection<ChildViewModel> _items;
    public ObservableCollection<ChildViewModel> Items
    {
        get
        {
            return _items;
        }
        set
        {
            SetProperty(ref _items, value);
        }
    }

    private ChildViewModel _selectedChild;
    public ChildViewModel SelectedChild
    {
        get { return _selectedChild; }
        set
        {
            SetProperty(ref _selectedChild, value);
        }
    }

    private void ChildViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        var child = (ChildViewModel)sender;
        if (e.PropertyName == nameof(ChildViewModel.IsSelected) && child.IsSelected)
        {
            SelectedChild = child;
        }
    }
} 

【问题讨论】:

  • 您是否在 SelectedNumber 设置器中引发 PropertyChanged 事件?
  • 因为我使用的是 Prism 框架,所以我不需要手动引发 PropertyChanged 事件。
  • @taquion SetProperty() 这样做。他很好。
  • 我没有意识到这一点。我的道歉

标签: c# wpf mvvm prism


【解决方案1】:

直接绑定子属性:

<ListBox 
    ItemsSource="{Binding ChildViewModel.Numbers}"
    SelectedItem="{Binding ChildViewModel.SelectedNumber}"
    />

<Label Content="{Binding ChildViewModel.SelectedNumber}" />

这是绑定路径中父级的ChildViewModel 属性 的名称,而不是类型。 Binding 现在知道要收听ChildViewModel 对象以获取有关SelectedNumberNumbersPropertyChanged 通知。

您的版本不起作用的原因是当SelectedChildNumber 更改时,父级不会引发PropertyChanged。事实上,父母并不知道它什么时候改变,就像 UI 一样。父级可以处理子级的PropertyChanged 事件,有时这已经完成。

public ParentViewModel()
{
    ChildViewModel = new ChildViewModel(params);

    //  Handle child's PropertyChanged event
    ChildViewModel.PropertyChanged += ChildViewModel_PropertyChanged;
}

private void ChildViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    var child = (ChildViewModel)sender;

    if (e.PropertyName == nameof(ChildViewModel.SelectedNumber))
    {
        //  Do stuff
    }
}

但是对于这种情况,您不需要这样做。

ChildViewModel.Numbers 应该是ObservableCollection&lt;int&gt;,而不是List&lt;int&gt;。这样,如果您向其添加更多数字或删除任何数字,UI 将自动收到集合通知,ListBox 将自动相应地更新自身。

【讨论】:

  • 太棒了!如果我在 ParentViewModel 中有 ChildViewModel 集合怎么办。此 ChildViewModel 之一的属性 IsSelected 等于 true。如何从集合中获取这个选定的视图模型?
  • 在这种情况下,父母可能想要处理每个孩子的PropertyChanged 事件。有趣的是,当我看到你的评论时,我只是在更新中添加了这个想法。
  • 我不知道如何从每个孩子那里引发事件。你能举个例子吗?
  • @Oblomingo 孩子对SetProperty() 的调用引发了事件。您正在处理该事件。查看更新。
  • Ed Plunkett,看看更新后的帖子。我不知道如何为每个项目添加句柄。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-28
  • 1970-01-01
  • 1970-01-01
  • 2022-01-17
  • 2013-11-21
  • 1970-01-01
相关资源
最近更新 更多