d--b
d--b

Reputation: 5779

Wpf Mouse event set on canvas, but targets child object

I have a Canvas that contains a Rectangle. On that canvas, I bind a mousedown event to a command on the ViewModel. In that command, I am being passed the MouseEventArgs, but there the Target element is either the Canvas or the Rectangle. Where can I find in the MouseEventArgs the Canvas this event was fired from?

My code is more or less:

<Canvas Background="White">
    <i:EventTrigger EventName="MouseLeftButtonDown">
        <local:InteractiveCommand Command="{Binding CmdMouseLeftButtonDown}"/>
    </i:EventTrigger>
    <Rectangle Width="50" Height="50" />
</Canvas>

And in the ViewModel:

ICommand CmdMouseLeftButtonDown => new DelegateCommand<MouseEventArgs>(e => 
{
    e.??? // <= Where do I find the Canvas here, whether I click on the Rectangle or Canvas?
}

Please do not answer with some hackish solution like e.MouseDevice.Target.Parent. This needs to work however complicated the element in the canvas is. It could contain another canvas for instance.

Upvotes: 0

Views: 2085

Answers (3)

DrMarbuse
DrMarbuse

Reputation: 870

Set <Canvas Background="Transparent" ... />

as answered in the following question by @Rob Fonseca-Ensor:

WPF: Canvas mouse events not firing on empty space

Upvotes: 0

mm8
mm8

Reputation: 169350

A view model is not supposed to have a reference to a UI element such as a Canvas or a Rectangle at all in the first place. This effectively breaks the MVVM pattern and that's why it makes no sense to pass the sender argument to the command.

You might as well get rid of the EventTrigger and invoke the command programmatically from the code-behind of the view:

<Canvas Background="White" MouseLeftButtonDown="Canvas_MouseLeftButtonDown">
    <Rectangle Width="50" Height="50" Fill="Red" />
</Canvas>

private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    var yourViewModel vm = DataContext as YourClass;
    vm.CmdMouseLeftButtonDown.Execute(sender as Canvas); //<-- pass the Canvas as a command argument or create a new command argument type that holds a reference to the Canvas
}

This is certainly not any worse than your current approach as far as the MVVM pattern is concerned. You are still invoking the very same command from the very same view and MVVM is not about eliminating code. It is about separation of concerns.

Upvotes: 1

Hamlet Hakobyan
Hamlet Hakobyan

Reputation: 33381

Your MouseEventArgs.Source will reference to the Canvas in any case but the MouseEventArgs.OriginalSource will referece to the Rectange if you have clicked on its area. It will be the control determined by pure hit testing.

Upvotes: 0

Related Questions