Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing object to viewmodel

Tags:

c#

mvvm

Question on the MVVM pattern where I think I have it wrong.

When a touchdown event occurs in a view I want to popup a message i.e.:

private void marker_TouchDown(MessageObject msgData)
{
    CustomMessageControl message = new CustomMessageControl() {Width = 610, Height = 332};
    CustomMessageViewModel messageVM = new CustomMessageViewModel(msgData);
    message.DataContext = messageVM;
    //Add to canvas
}

My viewmodel:

public class CustomMessageViewModel
{
    public MessageObject message { get; set; }

    public CustomMessageViewModel(MessageObject message)
    {
        this.MessageObject = message;
    }
}

This works but doesn't feel right. Is this an acceptable way to populate the view model?

like image 238
John Sourcer Avatar asked Nov 06 '12 19:11

John Sourcer


1 Answers

I believe that you are violating MVVM in creating the control in the view model. This isn't testable, your view model has to create the control now and that shouldn't be a requirement for testing (this emphasizes the lack of the separation of concerns between the UI and the view model).

Instead of creating the control, it is completely acceptable for your view model to fire an event of it's own. In this event, you'd pass the view model that you want the dialog/overlay/control to bind to, something like this:

public class CustomMessageControlEventArgs : EventArgs
{
    public CustomMessageViewModel CustomMessageViewModel { get; set; }
}

public event EventHandler<CustomMessageControlEventArgs> 
    ShowCustomMessageControl;

private void marker_TouchDown(MessageObject msgData)
{
    // Create the view model.
    var message = ...;

    // Get the events.
    var events = ShowCustomMessageControl;

    // Fire.
    if (events != null) events(this, 
        new CustomMessageControlEventArgs {
            MessageObject = new CustomMessageViewModel(msgData)
        });
}

Then, in your UI code, you would bind to the event and then show the appropriate user interface for that event.

Remember, MVVM isn't strictly about being able to declare everything in XAML or binding data to the UI through just data bindings, it's about proper separation of code.

You want to separate the what of what is displayed (the view model) from the how of what is displayed (the UI); in firing an event, you're maintaining that separation of concerns.

Yes, you'll have to write some code behind (or you could do it through property notification changes, but it's uglier, frankly), but it maintains the separation and allows for easy testability without having to bring in any user interface elements.

like image 68
casperOne Avatar answered Oct 25 '22 12:10

casperOne