WPF Mvvm move mouse button event to Command - c#

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?

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 always be 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);
}

Related

Propagate shortcut from window to UserControls in WPF

I want to catch shortcuts at the window level with KeyBindings and then raise an event that all UserControls can somehow subscribe to in order to get notified when a shortcut has been issued.
I tried to do this on the window:
<Window.InputBindings>
<KeyBinding Key="M"
Command="{x:Static someNamespace:RoutedCommands.ShortcutSingleKeyM}" />
</Window.InputBindings>
And then add CommandBindings in the usercontrol to "catch" the command:
<UserControl.CommandBindings>
<CommandBinding Command="{x:Static someNamespace:RoutedCommands.ShortcutSingleKeyM}" Executed="OnShortcutSingleKeyM"></CommandBinding>
</UserControl.CommandBindings>
Method OnShortcutSingleKeyMin UserControl's is not getting hit. After some reading I now understand RouteCommands bubble up the tree and that might be the reason this approach didn't work.
I need the UserControl to be able to listen to "OnShortcut" events coming from the window. I'm currently implementing it this way:
Add an attached property to each user control that wants to listen to such events. Have the container pass a higher level delegate kind of thing to notify the Usercontrol.
Does this make sense? I'm getting the feeling that I'm overthinking this, it should be simpler to achieve.
Propagating from the Window down the tree to UserControls it's not going to work (at least not without major plumbing). I implemented it this way:
View listens to input (via both KeyBindings and KeyDown events).
View owns an object (ShortcutMcShortcutFace) that allows UserControls to subscribe to a OnShortcutEvent kind of thing.
UserControls expose DependencyProperties of type ShortcutMcShortcutFace. The view passes its ShortcutMcShortcutFace instance to them. They subscribe to OnShortcutEvent.
UserControls handle the OnShortcutEvent (args include a shortcut identifier) whichever way they want.

TouchEvents on Canvas in MVVM

I'm currently trying to implement a ImageViewer with the possibility to move and zoom with touch inputs.
I already implemented these functionalities in a recent project in the Code Behind, but I'm struggling to do so in a View Model in MVVM.
Problem is that for my code to work I have to know how many touch inputs are recognized at the same time.
In my Code-Behind I used:
canvas.TouchesCaptured.Count()
The ViewModel shouldn't not know any Controls of the View, so passing the Canvas as a Command Parameter is not the way to go.
Beside the canvas I need the TouchEventArgs of the triggered TouchEvent to determine the position of the TouchEvent on the canvas.
Using Prism I was able to get the TouchEventArgs into the ViewModel.
<i:Interaction.Triggers>
<i:EventTrigger EventName="TouchDown">
<prism:InvokeCommandAction Command="{Binding TouchDownCommand}"
</i:EventTrigger>
</i:Interaction.Triggers>
prism:InvokeCommandAction automatically sets the EventArgs as the CommandParameter for clarification.
To determine the position of the TouchEvent on the Canvas I need the canvas and the TouchEvent.
In my Code-Behind it looked like that:
startingPoint = e.GetTouchPoint(canvas);
Anyone has a idea how I can solve this problem without violating the MVVM Pattern?
You could try writing a Blend behavior that encapsulates the Canvas event handling and exposes commands (e.g. ManipulationDelta in particular). You could even add a property to the behavior that exposes the TouchesCaptured values (during the ManipulationDelta event).
e.g.
<Canvas>
<i:Interaction.Behaviors>
<bhv:CanvasBehavior ManipulationDeltaCommand="{Binding MyViewModelCommand}" TouchPointCount="{Binding MyViewModelTouchPointCount}" />
</i:Interaction.Behaviors>
</Canvas>

Pass Event from Main Page to element in User Control

I have MainPage in WPF Project. This page contains sidebar, which I want to move in UserControl. But this sidebar also has some elements such as Button that has click events. In codebehind this event is related to viemModel that are binded to MainPage. So I don't want to bind this viewModel to UserControl.
What I want to do - pass this event to user control on MainPage and then this event bind to Button in UserControl.
Is it possible to do or it is bad idea? Thanks
For example :
SideBar has button :
<Button Grid.Column="1" Width="44" Height="44" Style="{StaticResource SearchBtn}" Click="Search_TextChanged" >
<Button.Content>
<Image Height="15" Width="15" Source="/Assets/icon-search.png"/>
</Button.Content>
</Button>
Click event is related to ViewModel
private void Search_TextChanged(object sender, EventArgs e)
{
_resultViewModel.Search_TextChanged(tbSearch.Text);
}
First of all, it is better not to use the code behind especially not the click events. I would suggest to use MVVM pattern inside you application This way you can use commands for the click events this can also bubble up on the stack.
And you can also share the ViewModel over the mainpage and maybe your usercontrol
I agree with Jordy, you should implement a MVVM pattern inside your application. You could look at MVVM Light https://mvvmlight.codeplex.com/ or get from the nuget package manager. With MVVM Light you will be able to handle button click events using Relay Commands and able to communicate between user controls with their built in Messenger.

When to use event and command for WPF/MVVM?

I am practicing on how to write a WPF application with MVVM pattern. So far I haven't used command in my code. In my Viewmodel I implement INotifyPropertyChanged and used (event PropertyChangedEventHandler PropertyChanged) to fire events.
Why do I feel like I still miss some concept of WPF about how to use command?
When is it appropriate to use commands?
Commands in WPF are used to abstract an user-triggered action (such as clicking a Button or pressing a key.
here's a basic example:
Suppose you want to search for employees in your database when the user clicks the "Search" button, or hits the enter key while focusing the Search Box.
You might define your ViewModel like this:
public class MyViewModel: ViewModelBase
{
public string SearchText {get;set;} //NotifyPropertyChanged, etc.
public Command SearchCommand {get;set;}
public MyViewModel()
{
//Instantiate command
SearchCommand = new DelegateCommand(OnSearch);
}
private void OnSearch()
{
//... Execute search based on SearchText
}
}
And your View:
<StackPanel>
<TextBox Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}">
<TextBox.InputBindings>
<KeyBinding Key="Enter" Command="{Binding SearchCommand}"/>
</TextBox.InputBindings>
</TextBox>
<Button Content="Search" Command="{Binding SearchCommand}"/>
</StackPanel>
Notice how the KeyBinding and the Button's Command property are both bound to the same Command (SearchCommand) in the ViewModel. This facilitates reutilization, and also helps keep actual logic in the ViewModel, with all its goodness (testability, etc), while keeping the view clean and code-less.
The fun thing is that using original Commands concept from WPF is absolutely not required :). You could build large and complex applications with all that beauty of loosely coupled design (xaml) and business logic (c#/vb code) in place with just using MVVM all around and free open source application framework library Caliburn.Micro.
Disclaimer: I'm just a happy user of this library and have nothing to do with its creators, so this is not paid ads or something like that.
Please, just take a look over this very basic sample from official documentation:
--> Basic Configuration, Actions and Conventions <--
and you will fill the power of binding events from you XAML view directly to methods in your C# view-model without mess of proxy code for commands declaration and registration (like this is implemented in other similar application frameworks).
And never mind that this sample is Silverligh app - Caliburn.Micro support all major Xaml platforms almost the same way and the WPF sample will looks pretty like above Silverlight-based.
In addition to the mentioned major capability (buinding to methods) Caliburn.Micro have:
handy predefined naming conventions for binding that leaves your XAML files clean and readable (and yet still design-time friendly!)
base implementation of INotifyPropertyChanged so that you could just inherit from it all of your view-models
base classed for implementation of frequently used scenarios like:
master-details
parent-child
list-with-selected-items
EventAggregator for even more loosely coupled communication between view-models and other classes
loosely coupled support for things like keyboard focus and windows management (for WPF)
and a bit more :)
Just give it the chance and you will never need vanilla WPF Commands ;)

How to bind event to method on ViewModel with event args passing. Silverlight 4

I have seen somewhere this is 100% doable using blend behaviors, cannot find example.
Even better example would be to pass event args and/or sender as CommandParameter to specific command.
<i:Interaction.Triggers>
<i:EventTrigger EventName="SizeChanged">
<ei:CallMethodAction MethodName="WndSizeChanged"
TargetObject="{Binding}" />
</i:EventTrigger>
</i:Interaction.Triggers>
WndSizeChanged method should be public and have same signature as event delegte it subscribing to.
a comfortable way to create behaviors is to use the DelegateCommand approach as in Prism:
Read here: Prism behavior
Caliburn Micro has some nice ways to do this.
From the docs:
<Button Content="Remove"
cal:Message.Attach="Remove($dataContext)" />
$eventArgs – Passes the Trigger’s EventArgs or input parameter to your Action. Note: This will be null for guard methods since the trigger hasn’t actually occurred.
$dataContext – Passes the DataContext of the element that the ActionMessage is attached to. This is very useful in Master/Detail scenarios where the ActionMessage may bubble to a parent VM but needs to carry with it the child instance to be acted upon.
$source – The actual FrameworkElement that triggered the ActionMessage to be sent.
$view - The view (usually a UserControl or Window) that is bound to the ViewModel.
$executionContext - The actions's execution context, which contains all the above information and more. This is useful in advanced scenarios.
$this - The actual ui element to which the action is attached.

Categories