Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Microsoft (or other) ribbon with large project and MVVM

Tags:

mvvm

wpf

ribbon

Our application is a large project with many modules and view. The main window has a ribbon in it, and we are looking for the best way to integrate the ribbon in the application.

I've created a service which modules a views can register to add ribbon items relevant for them, and, in addition, any main view instance can provide its own ribbon items relevant to the that instance. a RibbonItem is a small class which abstract the options of a ribbon item, and mainly have Title, Description, Command, UIType and ChildItems. The service is in charge to rebuild the ribbon when the main view changes.

A colleague of mine thinks this is bad MVVM, as users need to design their ribbon view in C# code and not in XAML, and he also say it would be hard in this way to make a group of items disabled or enabled at once, as each command of these items will need to update its CanExecute separately. Instead, he suggested to have a main Ribbon View and ViewModel files, where each developer that want to add a ribbon button for her module or view would need to add them in the View XAML and add a relevant command in the ViewModel. In addition, VisualStates will be used to determine what items will be displayed or enabled based on changes in the ViewModel (such as view change, or selection change). I really don't like this solution, mainly because all developers will have to put their modules knowledge in once big file.

Note that some items in the ribbon (e.g. Options, Exit) are common to the entire application, while some are relevant to a specific application domain and some are only relevant for a specific view.

Edit: I guess my main question is what is the recommended way to allow multiple development teams integrate on a single ribbon? Should we have a single RibbonView and single RibbonViewModel which will contain all of the possible items in a ribbon, and each team will add its items to these V/VM and also define the logic on when to show them (probably by using visual state)? Or do we allow every view, view-model or module register ribbon items (within their own C# code) against a service, and have the service then render the ribbon as needed when the active view changes with all items registered to that type? Or is there any better way to achieve this integration?

What do you think? Do you have a better idea or an opinion about how to manage the single ribbon resource which is common to multiple developers?

Thanks, splintor

like image 916
splintor Avatar asked Apr 06 '11 17:04

splintor


1 Answers

I agree with Will's comment, your viewmodel should not care or know how it is being rendered or if the designers ever decide to change how it's rendered.

A ViewModel should only contain all required information for the presentation layer to render it.

So the ViewModel should have all the properties that the Ribbon bar needs bind to in order to function. Then you can use a Resources.xaml or some other strategy to present it.

Taking a shot in the dark I would try something like this for the ViewModels:

public interface IMenuViewModel : INotifyPropertyChanged
{
  ICommand Command {get;}
  string Title {get;}
  string Description {get;}
  UIType Type {get;}
  IList<IMenuViewModel> ChildItems {get;}
}

I would then probably create an abstract class that provides implements INotifyPropertyChanged with a collection class the implements INotifyCollectionChanged to take care of the plumbing code.

I would then probably do something like this in the Resources.xaml

<DataTemplate DataType="{x:Type vm:IMenuViewModel}">
  <StackPanel>
    <Button Command="{Binding Command}" Content="{Binding Type}"/>
    <ItemsControl ItemsSource="{Binding ChildItems}"/>
  </StackPanel>
</DataTemplate>

to provide a default view for your viewmodels

and then all someone has to do to create an entry into your ribbon bar is

1) Implement IMenuViewModel

2) Optionally add another DataTemplate entry into your resources.xaml if they want their widget rendered differently like so:

<DataTemplate DataType="{x:Type vm:FooViewModel}">
    <v:FooView />
</DataTemplate>

I hope I didn't dig to deep on how I would implement.

The main point is that a ViewModel should only expose properties required for the view to do it's job(which is rendering the ViewModel), not for the ViewModel to do the job or care how it's done.

like image 157
Jose Avatar answered Nov 15 '22 04:11

Jose