MVVM Execute Command on ViewModel from other ViewModel

sinkien picture sinkien · Apr 8, 2012 · Viewed 11.7k times · Source

I'm struggling for about 14 days now with a simple task: In database, I have definitions for hardware categories. For example :

  1. HDD
    • Internal
    • External
    • Flash

This list is in database defined like this:

    [ID - ParrentID - Name] : 1 - 0 - HDD, 2 - 1 - Internal, 3 - 1 - External, 4 - 1 - Flash.        

Through Entity Framework I get these rows into my application. From this flat data I then create structured object which is my DataModel. This model is defined as follows :

public class Category
{
   private int _id = -1;
   private string _name = "";
   private List<Category> _subCategories = null;
// property getters and setters, constructors, and bool HasSubCategories
}  

Now, from these I create ViewModel called SubCategoryViewModel to which is binded my TreeView. So, I can view my categories in treeview and with my defined and maintained hierarchy. This works just fine. In SubCategoryViewModel is defined a Command through Attached Behavior for MouseDoubleClick which is also binded to TreeView. So, when user doubleclicks on Item, in SubViewCategoryModel defined method will execute particular code. List of SubCategoryViewModel is nested in HWDocumentViewModel which is a main ViewModel for my window. What I need now is obvious : When user doubleclicks on item in TreeView, I need to load items from database and show them in ListView. My opinion is, that in HWDocumentViewModel I need to define an collection of Items and load them accordingly to selected category in ListView. But, I don't know how to execute a method on HWDocumentViewModel from SubCategoryViewModel. Because : TreeView is binded to list of SubCategoryViewModel items, so when DoubleClick occurs, the method on SubCategoryViewModel is executed. I'm searching for a way, how to execute a method on main ViewModel (HWDocumentViewModel).

I tried this approach :
I created a property : public static SubCategoryViewModel SelectedCategory on HWDocumentViewModel. When doubleclick occurs, I set this property from SubCategoryViewModel as this. So, in this property is object, which executed doubleclick event delegate. Great, now I have in HWDocumentView model an object, which user selected.
So, I need to load items to ListView. But, will I load them from method in SubCategoryViewModel ? I don't think so. Instead I should load them from Main View Model by creating a ViewModel for them and bind it to ListView, right ? But, how can I from SubCategoryViewModel call a method in HWDocumentViewModel ? Should I write a static method on a HWDocumentViewModel which will be accessible from SubCategoryViewModel ?
Or is there a way, how to call Command defined on HWDocumentViewModel from SubCategoryViewModel ?

Or generally, did I take a right approach to create a Warehouse-like application in WPF ?

Thanks a lot.

EDIT: XAML for my TreeView looks like this :

<TreeView x:Name="tvCategories" Background="White" ItemsSource="{Binding Categories}">
                    <TreeView.ItemContainerStyle>
                        <Style TargetType="{x:Type TreeViewItem}">
                            <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
                            <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                            <Setter Property="FontWeight" Value="Normal" />
                            <Setter Property="behaviors:MouseDoubleClick.Command"  Value="{Binding MouseDoubleClickCommand}" />
                            <Setter Property="behaviors:MouseDoubleClick.CommandParameter" Value="{Binding}" />
                            <Style.Triggers>
                                <Trigger Property="IsSelected" Value="True">
                                    <Setter Property="FontWeight" Value="Bold" />
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </TreeView.ItemContainerStyle>
                    <TreeView.Resources>
                        <HierarchicalDataTemplate DataType="{x:Type localvm:SubCategoryViewModel}" ItemsSource="{Binding Children}">
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding CategoryName}" />
                            </StackPanel>
                        </HierarchicalDataTemplate>
                    </TreeView.Resources>

                </TreeView>

Answer

GazTheDestroyer picture GazTheDestroyer · Apr 9, 2012

I'm not sure I see the problem. You have a tree of subcategories and when one is selected, the appropriate SubCategoryViewModel sets itself as SelectedCategory on the main HWDocumentViewModel. That seems like a reasonable approach.

So why do you need to call a command? Why can't you just load the new list in HWDocumentViewModel in response to a change of its SelectedCategory property (ie in the setter)?

If you really must use a command to invoke the load, then simply keep a reference to your main HWDocumentViewModel in each SubCategoryViewModel, and invoke the command with a simple:

_mainViewModel.LoadCategoryCommand.Execute();