如何绑定到WPF应用程序中的子视图模型属性?

时间:2017-06-21 12:47:04

标签: c# wpf mvvm prism

我正在使用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);
        }
    }
}

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

更新 好的,如果我在ParentViewModel中有ChildViewModel集合怎么办?其中一个ChildViewModels的属性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;
        }
    }
} 

1 个答案:

答案 0 :(得分:1)

直接绑定到子属性:

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

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

这是绑定路径中父级ChildViewModel 属性的名称,而不是类型。 Binding现在知道收听有关ChildViewModelPropertyChanged的{​​{1}}通知的SelectedNumber对象。

您的版本不起作用的原因是,当Numbers更改时,父级不会引发PropertyChanged。事实上,父母不知道它何时发生变化比UI更多。父可以处理孩子的SelectedChildNumber事件,有时候已完成。

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<int>。这样,如果您向其添加更多数字或删除任何数字,该集合将自动通知UI,List<int>将自动相应地更新自身。