8

I am building an application that uses quite a few commands, and they are cluttering up my viewmodel. MVVM is new to me, so sorry if this question is a bit stupid. Is there a way to reduce the clutter? For example here you can see the a part of the clutter..

    private void InitializeCommands()
    {
        LogoutCommand = new RelayCommand(Logout);
        OpenCommand = new RelayCommand(SetImage);
        SaveCommand = new RelayCommand(SaveImage, SaveImageCanExecute);
        UploadToFlickrCommand = new RelayCommand(UploadToFlickr);
        CropCommand = new RelayCommand(SetCropMouseEvents);
        RemoveRedEyeCommand = new RelayCommand(SetRemoveRedEyeMouseEvents);
        TextInputCropCommand = new RelayCommand(CropFromText);
        ReloadImageCommand = new RelayCommand(ReloadImage);
        FlipYCommand = new RelayCommand(FlipY);
        Rotate90RCommand = new RelayCommand(Rotate90R);
        FlipXCommand = new RelayCommand(FlipX);
        ToGrayscaleCommand = new RelayCommand(ToGrayscale);
        ToSepiaCommand = new RelayCommand(ToSepia);
        WindowClosingCommand = new RelayCommand(WindowClosing);
        EffectsViewCommand = new RelayCommand(() => CurrentToolView = new EffectsView());
        AddTextCommand = new RelayCommand(() => CurrentToolView = new AddTextView());
        ResizeCommand = new RelayCommand(() => CurrentToolView = new ResizeView());
        CropViewCommand = new RelayCommand(() => CurrentToolView = new CropView());
        RedEyeCommand = new RelayCommand(() => CurrentToolView = new RedEyeView());
        RotateViewCommand = new RelayCommand(() => CurrentToolView = new RotateView());
        ExitCommand = new RelayCommand(() => Application.Current.Shutdown());
        FullscreenCommand = new RelayCommand(() =>
                                                 {
                                                     var fs = new FullscreenView
                                                                  {FullscreenImage = CurrentImage.LoadedImage};
                                                     fs.Show();
                                                 });
        HandleDropCommand = new RelayCommand<DragEventArgs>(e => OnFileDrop(this, e));
        Messenger.Default.Register<User>(this, "UserLogin", SetUser);
        Messenger.Default.Register<FlickrAccount>(this, "AddedAccount", AddAccount);
        Messenger.Default.Register<string>(this, "INeedAUser", SendUser);
        Messenger.Default.Register<string>(this, "INeedAImage", SendImage);
    }
Iris Classon
  • 5,752
  • 3
  • 33
  • 52
  • I 'd also be interested in seeing a good answer to this, but AFAIK this is the price to pay for having all the loose coupling goodness. – Jon Dec 18 '11 at 15:08

3 Answers3

5

So you have commands for:

  1. File operations (Open, Save, Upload to Flicker)

  2. Window operations (Full screen, Close)

  3. Editing (Rotating, Resizing, Colour, etc)

Consider grouping (composing) related commands together in a custom class called for example FileCommands. Create a multi-level hierarchy if applicable. If you have a hierarchical menu in your view, You'll likely want similar Command Hierarchy.

Then, create one Controller per command group (for example FileController) and in the controller create method that will register the commands from the FileCommands group with the associated service.

See http://waf.codeplex.com/ sample applications (for example BookController.cs) for some ideas on how to actually implement Controller/ViewModel mapping. Note however that it's not exact same scenario (no breaking of Commands into groups).

surfen
  • 4,644
  • 3
  • 34
  • 46
  • Very interesting, I like the idea. Seems a bit complicated (for me as a newbie) but I will have a look at it and let you know how I went! Thank you for your answer :) – Iris Classon Dec 18 '11 at 16:23
  • If you don't want to the Controller yet then just group related commands as suggested and split InitializeCommands method into InitializeFileCommands, InitializeWindowCommands etc. – surfen Dec 18 '11 at 16:40
1

Use Caliburn Micro. For a button named name="Logout" the only thing needed in the ViewModel is a public method named Logout.

And without convetion bindings:

<Button Content="Remove"
        cal:Message.Attach="[Event Click] = [Action Remove($dataContext)]" />

Then on the ViewModel add a method named Remove and in that sample the DataContext is passed to the method.

Derek Beattie
  • 9,429
  • 4
  • 30
  • 44
  • What is Caliburn Micro, and how easy is it to get started with it? We are currently using MVVM light , can they be used together? Thank you for your response :) – Iris Classon Dec 18 '11 at 16:22
  • CM is a convention based MvvM framwork for WPF & SL. http://caliburnmicro.codeplex.com/. Getting started isn't bad but I don't think you'd use both at the same time. – Derek Beattie Dec 18 '11 at 16:35
0

Your ViewModel is meant to be the glue between the View and the Model. This implies that, unless you can generically iterate the Model, it will always consist of an enumeration of 'glue-lines'.

The only clutter I can imagine you could get rid of is in case you don't need the XXXCommand properties literally; in that case, you could create a collection of property-like, structures like (pseudo-code)

private void createCommands() {
   var commands={
      "Logout"=>new RelayCommand(Logout),
      "Exit"=>new RelayComand( ()=>Application.Current.Shutdown() ),
     ....
   };
   foreach( var key,cmd in commands ){
      glue(key,cmd);
   }
};

There's no other reason to keep references to the objects you create in here except for glueing them to the correct View binder.

But then again, why not use the Property idiom for this? Again: the amount of clutter, as I see it, is reasonably limited.

xtofl
  • 40,723
  • 12
  • 105
  • 192
  • Thank you for your answer, I'll look over the code again as well as ask my teacher tomorrow. I'll re-post the code later and you can see the result :) – Iris Classon Dec 18 '11 at 15:30
  • Just one note: Having names in strings makes them invisible to the compiler (i.e. it cannot check consistency). On the other hand; it also cannot check whether a property is used or not... – FrankB Sep 24 '12 at 10:28