Home > Enterprise >  WPF Mvvm move mouse button event to Command
WPF Mvvm move mouse button event to Command

Time:09-30

I am starting to use MVVM but I'm finding difficult to replicate simple things that I do with events: I have a canvas and I want to get the position of the mouse click so I did a command and the xaml is this

<Canvas x:Name="cnvLeft">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="PreviewMouseDown">
                <cmd:EventToCommand Command="{Binding CanvasClick}" 
                                    PassEventArgsToCommand="True"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
        
    </Canvas>

However it pass only the mouse arguments, which is not enough because i need the sender, how can i fix this?

CodePudding user response:

As recommended already: register a common event handler for the mouse click event.

MVVM is not concerned with code-behind. It's absolutely fine and even necessary to use code-behind.
Code-behind files are a compiler feature i.e. language feature (partial classes). They have nothing to do with application architecture. MVVM does not care about compilers - no design pattern does.

MVVM is also not concerned with commands (or data binding or any framework concept in general). Commanding is part of the framework's infrastructure and MVVM does not care about frameworks - no design pattern does.
MVVM does not mean to use commands. Events are usually just as good. So don't force commands. Instead of using interaction behaviors to convert an input event to a command, simply handle the event directly (of course in the view).

Controls must be always handled in the View of an MVVM application. The code-behind file of a control is a partial class. It's part of the control and therefore part of the View.

Implement the user input event handler in the hosting control's code-behind. Here you must implement the Canvas related logic (UI logic).
If you want to encapsulate the logic, you can move it along with the Canvas to a new custom Control (or UserControl).

MainWindow.xaml

<Window>
  <Canvas PreviewMouseDown="OnCanvasePreviewMouseDown" />
</Window>

MainWindow.xaml.cs

private void OnCanvasePreviewMouseDown(object sender, MouseButtonEventArgs e)
{
  var canvas = sender as Canvas;
  Point canvasClickPosition = e.GetPosition(canvas);
}

CodePudding user response:

In MVVM, You ought to do the View business out of the ViewModel..

You can still bind a command in xaml like this

<Canvas x:Name="cnvLeft">
    <b:Interaction.Triggers>
        <b:EventTrigger EventName="PreviewMouseDown">
            <b:InvokeCommandAction
                Command="{Binding CanvasClick}"
                EventArgsConverter="{StaticResource GetPositionConverter}"
                PassEventArgsToCommand="True" />
        </b:EventTrigger>
    </b:Interaction.Triggers>
</Canvas>

Where GetPositionConverter will do the View business to get the click position and pass it to the Command..

public class GetPositionConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value is MouseButtonEventArgs args)
        {
            var pos = args.GetPosition((IInputElement)args.Source);
            return new Tuple<double, double>(pos.X, pos.Y);
        }

        return new Tuple<double, double>(-1, -1);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

CanvasClick command will recieve a Tuple<double, double> that has (x,y) of the click.

  • Related