Updating a reference to a command of a nested ViewModel?

安稳与你 提交于 2019-12-04 21:58:08

I think the path you are going down is quickly going to end up complex and tightly coupled. You should probably take a look at using the Mediator Pattern to facilitate communication of changes in your SummaryFilterViewModel to your MainViewModel.

Using the mediator pattern, you can implement a means of subscribing to and publishing messages that allows one view model to communicate with another view model without ending up with tightly coupled view models.

Basically, when your tab selection changes, the summary view model would publish the change with the message payload containing the reference object or other data. The main view model would be subscribed to publication of this message and modify its state accordingly.

Some resources on the Mediator Pattern you can take a look at:

I've made some changes to my sample solution in response to some suggestions that were made by Kent Boogaart. Kent, thank you again for your reply it gave me a new direction to move.

I'll try to keep this as short as possible.

  • The MainView is basically a frameset that houses the application's main command interface. In the sample the SummaryView is embedded directly in MainView's XAML. In the real solution it's a content control that may contain different types of child views. Each type of child view may or may not implement the command.
  • I was able to wire the SelectedIndex to a property so that I wouldn't need a dependency on the System.Windows.Control library. When that property changes, I also call OnPropertyChanged for the ShoutCommand property.
  • This, however, did not relay that change to the MainView object. So, in MainViewModel, I listen for the _SummaryViewModel.PropertyChanged event.
  • When MainView hears that the _SummaryViewModel.PropertyChanged event fired, I call OnPropertyChanged(this, "ShoutCommand") which propagates the change to the MainView.

So, I guess I want to know if it's necessary for the MainViewModel to listen to the _SummaryViewModel's PropertyChanged event like I'm doing, or if there is a cleaner way to do it.

My code is listed below: (I tried to take out as much as I could)

Thanks!

MainView

<v:SummaryView Grid.Row="0"
               DataContext="{Binding SummaryViewModel}" />
<Button Content="Shout Command"
        Grid.Row="1"
        Command="{Binding ShoutCommand}" />

MainViewModel

public MainViewModel()
{
    _SummaryViewModel = new SummaryViewModel();
    _SummaryViewModel.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(_SummaryViewModel_PropertyChanged);
}

void _SummaryViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
    switch (e.PropertyName)
    {
        case "ShoutCommand":
            OnPropertyChanged(this, "ShoutCommand");
            break;
    }
}

private SummaryViewModel _SummaryViewModel;
public SummaryViewModel SummaryViewModel {...}

public ICommand ShoutCommand
{
    get { return _SummaryViewModel.ShoutCommand; }
}

SummaryView

<TabControl SelectedIndex="{Binding SelectedTabIndex}">
    <TabItem DataContext="{Binding Filters[0]}" Header="{Binding FilterName}">
        <ListBox ItemsSource="{Binding ListData}" />
    </TabItem>
    <!-- TabItem repeated two more times -->
</TabControl>

SummaryViewModel

private List<SummaryFilterViewModel> _Filters;
public List<SummaryFilterViewModel> Filters {...}

private int _SelectedTabIndex;
public int SelectedTabIndex 
{
    get { return _SelectedTabIndex; }
    set
    {
        _SelectedTabIndex = value;
        OnPropertyChanged(this, "SelectedTabIndex");
        OnPropertyChanged(this, "ShoutCommand");
    }
}

public ICommand ShoutCommand
{
    get {
        int selectedTabIndex = SelectedTabIndex;

        return (selectedTabIndex == -1) ? null : Filters[SelectedTabIndex].ShoutCommand; 
    }
}
Kent Boogaart

Your post was long and I confess I didn't fully read it. However, I don't understand the purpose of CommandReference. Why not just bind directly to MainViewModel.ShoutCommand? Consider:

  • Bind the ItemsSource of the TabControl to the collection of child view models
  • Bind the SelectedItem of the TabControl to another property that tracks the selected child view model
  • When the aforementioned property changes, raise the PropertyChanged event for the ShoutCommand property, too
  • In the getter for ShoutCommand property, simply return the ShoutCommand of the selected child view model
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!