2
votes

I'm doing some research on WPF and MVVM to evaluate if this is something we wish to implement in a project.

There is one particular thing that I quite cannot understand (my book on WPF hasn't arrived yet).

I've read Josh Smith's article 'WPF Apps With The Model-View-ViewModel Design Pattern' and also his article 'Using RoutedCommands with a ViewModel in WPF'.

My demo application is somewhat different from Josh Smith's demo in that I have menu items that aren't directly bound to the main view model, but would rather be handled by other view-models.

My main window is bound to a MainViewModel object which exposes a object called View (derived from a ViewModelBase class and bound to the Main Window through a ContentControl). This View object is replaced with different ViewModel's such as CustomerViewModel, CustomersViewModel etc. (these are rendered using views defined in my resource dictionary: ).

All this is well and find, but since I wan't menu items in my main window (such as New, Save etc.) that should be enabled, disabled based on the view I found Josh Smith's article on the CommandSink pattern(?) but he states that it is obsolete, and one should rather use the RelayCommand.

Now I am confused, as I cannot figure out how to implement this functionality using this approach.

Thanks, Vincent

1

1 Answers

0
votes

A simple way to do this is to have each view expose a property of type MenuItem, which contains its local menu. (The menu itself can live in the view's resource dictionary; you just implement a property getter that retrieves it using FindResource.)

Then make your main menu look something like this:

<Menu>
   <MenuItem Header="File">
      <!-- content for your application's File menu goes here -->
   </MenuItem>
   <MenuItem Header="Edit">
      <!-- content for your application's Edit menu goes here -->
   </MenuItem>
   <MenuItem Header="{Binding SelectedView.MenuItem.Header}"
             ItemsSource={Binding SelectedView.MenuItem.Items}/>
   <MenuItem Header="Help">
      <!-- content for your application's Help menu goes here -->
   </MenuItem>
</Menu>

Edit

I think I misunderstood your question, but in part that's because I think your question's much easier to answer than the one I thought you were asking.

Create a RoutedCommand property in your application view model called DisabledCommand that is always disabled. Then bind your application menus to commands like this:

public RoutedCommand SaveCustomerCommand
{
    get
    {
       CustomerView cv = SelectedView as CustomerView;
       return cv == null
          ? DisabledCommand;
          : ((CustomerViewModel)cv.DataContext).SaveCommand;
    }
}

The casting is a little awkward looking, but other than that this is straightforward, elegant even. The only implementation detail your application view needs to know about the customer view is that there's a SaveCommand on its view model.