tags:

views:

157

answers:

3

In my view, I have:

<UserControl x:Class ... MouseDown="UserControl_MouseDown"> 
    <Viewport3D Name="Viewport" Grid.Column="0">
        ...
    </Viewport3D >
</UserControl>

In my code-behind, I have:

private void UserControl_MouseDown(object sender, MouseButtonEventArgs e)
{
    ((MapPanelViewModel)DataContext).OnMouseDown(e, Viewport);
}

And in my view-model, I have:

public void OnMouseDown(MouseEventArgs e, Viewport3D viewport)
{
    var range = new LineRange();
    var isValid = ViewportInfo.Point2DtoPoint3D(viewport, e.GetPosition(viewport), out range);
    if (!isValid)
        MouseCoordinates = "(no data)";
    else
    {
        var point3D = range.PointFromZ(0);
        var point = ViewportInfo.Point3DtoPoint2D(viewport, point3D);
        MouseCoordinates = e.GetPosition(viewport).ToString() + "\n" + point3D + "\n" + point;
    }
}

I really don't have a good sense of how to handle mouse events with MVVM. I always just end up putting them in the code-behind and casting the DataContext as SomeViewModel, then passing the MouseEventArgs on to a handler in my view-model. That's bad enough already, but in this case, I'm actually passing in a control (a Viewport3D), which is necessary for translating coordinates between 2D and 3D.

Any suggestions on how to make this more in tune with MVVM?

+2  A: 

I think this is a case of taking MVVM too far. MVVM is not precisely defined, of course, but I think of it in terms of trying to separate my applications high-level mechanics and behaviors from the details of how those mechanics and behaviors get implemented using a particular UI technology (it's just WPF these days, of course, but I find it useful to pretend there might be something else).

Without knowing how your application is supposed to react to the mouse events, it's hard to give specific advice or opinion. Based on what I do see, I think the coordinate translation is best left in the UI layer and then the translated coordinates would get passed to the ViewModel via a method call.

Daniel Pratt
@DanM We have been taking the approach that the logic that goes into the ViewModel should work outside of a UI host. If you were to run Tests on that particular code, would it excute, or fail because there is not ViewportInfo? If it fails, that logic should go back to the UI as Daniel suggests. Remember one of the major advantages of MVVM is Automated Unit Testing.
Agies
+1  A: 

If you are worried about breaking testability by passing a View object through to your ViewModel, create a interface for converting between 3D and 2D points and pass that through instead. In your code behind, you then pass the Viewport3D object through in a wrapper which implements that interface.

Other than that I wouldn't worry about the event handlers in code behind. Use bindings for everything that is easy, use the code behind for the really tricky parts.

Jamie Penney
A: 

I ended up using the MVVM Messenger. So, the mouse event gets handled in the code behind, then it sends a message that the event occurred. Then, my ViewModel can subscribe to this message and receive notification. Works like a charm and keeps everything decoupled.

DanM