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.
Related
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);
}
I'm currently learning to code WPF application after having used forms for a while.
I have a simple question, but can't seem to find an anwser anywhere.
Is it possible to automatically generate the 'private void eventName(...' code when creating an event ?
For example, if I create a WPF Form with a simple button and code :
Button x:Name = "mButton" Content = "Hello" Click = "mClick" /
Is there a trick to have the private void event handler create itself ? Cause right now, I either write it manually or double click in the event handler properties tab. In widowsForm, I could just double click and it would create itself.
This isn't a big issue for 1 or 2 but if I want to create a dozen buttons, it can become tedious.
I apologize if the question can seem obvious
Of-course, the more automated and lazier the better.
So a few tips:
You can generate a new event handler with an automated name like this:
Assign the x:Name before creating or assigning the event handler
Pick the default <New Event Handler> from the list of options IDE gives you for your event handler. it will generate something like:
MouseDoubleClick="mButton_MouseDoubleClick"
or Click="mButton_Click"
If the name is already taken, it will be prefixed with _1
If the x:Name is not assigned, it will be prefixed with Button_ instead of x:Name
You can generate any already-written event handler like this:
Right click on handler's name in XAML code ("mClick") and choose Go To Definition (The default shortkey is F12)
F12 does the same thing as double-clicking on an event handler value in properties window in WinForms. In case of default event (like Button's Click, it does the same as double-clicking directly on the control)
If you don't want the control to contain any code for event handler like:
<Button /> // handles the click event magically
Then you can add this to the container of all the buttons:
<Container.Resources>
<Style TargetType="Button">
<EventSetter Event="Click" Handler="mClick"/>
</Style>
</Container.Resources>
(obviously, I supposed the name of the container is Container. In your case it might be Window or Menu etc.)
Now every button inside this container has its Click handled by the same handler, in which you can redirect your logic to the right method:
Dictionary<string, Action> dic;
private void mClick(object sender, RoutedEventArgs e)
{
dic[(sender as Button).Name]();
}
These all still so tedious compared to MVVM pattern:
<ItemsControl ItemsSource="{Binding myButtons}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding ButtonText}" Command="{Binding ButtonAction}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If you want to do this rather than use a databinding/command pattern, you can use the XAML designer in Visual Studio. If you start typing Click=" you should be prompted with a list of possible event handlers or a new one - selecting one and pressing tab will create the event handler in the code behind for you (you might want to rename it, or make sure you name the button in XAML first).
For my current project I need to capture button pressed and release events in Xamarin.Forms. But I want to keep things loosely coupled using Prism.
At first I used the Command property of the , like so:
<Button x:Name="ButtonForward" Command="{Binding MoveUpCommand}" />
But the Command property only fires when the button is released. To make seperate pressed and released actions I used the events in XAML:
<Button x:Name="ButtonForward" Pressed="ButtonForward_Pressed" Released="ButtonMove_Released"/>
And called the Commands manually in the event handlers in code behind:
private void ButtonMove_Released(object sender, System.EventArgs e)
{
var vm = BindingContext as DirectControlViewModel;
if (vm.MoveStopCommand.CanExecute(null))
vm.MoveStopCommand.Execute(null);
}
private void ButtonForward_Pressed(object sender, System.EventArgs e)
{
var vm = BindingContext as DirectControlViewModel;
if (vm.MoveUpCommand.CanExecute(null))
vm.MoveUpCommand.Execute(null);
}
The problem is that it isn't loosely coupled anymore, since the View now has to know its ViewModel.
Is there a way to have a button that does have seperate commands for pressed and released events, keeping the View and ViewModel loosely coupled? Any help would be appreciated.
Use the EventToCommandBehavior on the Button. This will allow you take advantage of any Event on anything you're working with and Execute a Command when the event is fired.
<Button>
<Button.Behaviors>
<prism:EventToCommandBehavior EventName="Pressed"
Command="{Binding PressedCommand}" />
<prism:EventToCommandBehavior EventName="Released"
Command="{Binding ReleasedCommand}" />
</Button.Behaviors>
</Button>
Note there are additional properties that you can utilize if you have some sort of Parameter that you would like to pass the Command which may be a property in the EventArgs, or something else entirely that you'd like to bind to or specify.
I am making the close, maximize and minimize buttons in WPF C#. I tried two different methods and both seemed to work with me but I just want to know which approach in general is considered a better practice for this kind of implementation.
Method one:
in XAML:
<Window.CommandBindings>
<CommandBinding Command="{x:Static SystemCommands.CloseWindowCommand}" CanExecute="CommandBinding_CanExecute_1" Executed="CommandBinding_Executed_1" />
<CommandBinding ... />
<CommandBinding ... />
</Window.CommandBindings>
<Button Command="{x:Static SystemCommands.CloseWindowCommand}" Content ="close"/>
<Button ... />
<Button .../>
in C#:
private void CommandBinding_Executed_1(object sender, ExecutedRoutedEventArgs e)
{
SystemCommands.CloseWindow(this);
}
...
Method two:
in XAML:
<Button Content="X" Click="CloseButton_Click" />
<Button .../>
<Button ... />
in C#:
private void CloseButton_Click(object sender, RoutedEventArgs e)
{
Close();
}
...
Since the close, maximize and minimize buttons are typically part of a control, or a template of a control, you could handle the Click event of the buttons directly. There is no need nor reason to introduce any command bindings just to be able to handle the click of a Button internally in a control.
You could either hook up the event handlers in XAML or, if the buttons are defined in a ControlTemplate of a custom control, you could override the OnApplyTemplate() method of the control and hook up the event handlers programmatically as suggested here: https://blog.magnusmontin.net/2013/03/16/how-to-create-a-custom-window-in-wpf/.
Button click handler is simple and fast (to implement). If you are sure you are going to use just this button to close your window - click handler is good enough. If however there is possibility you are going to need more than one place to close the window (for example - you are going to use "close" menu option) - then it's better to not spread the same logic over multiple places and use a command, because command has all handling logic in one place (CommandBinding_Executed_1 in your case). Also, command has CanExecute logic so you will be able to automatically disable your close button (and all other "close" controls) in case window cannot be closed right now (with click handler you will have to code this logic yourself). Also, with command you can close your window from any control down the tree, even if that control has no reference to your window at all. This applies to "command vs click handler" in general, not specifically to the case with closing window where some of the above might seem a bit contrieved.
I want to use the C# System.Windows.Forms.SendKeys.SendWait() Method to send Keystrokes from an OnScreenKeyboard to a Textbox. Since I may use this OnScreenKeyboard at other places too I created a UserControl with View (for the Design of the Keyboard) and Viewmodel (basically for calling the Sendkeys.SendWait() Method) in an extra project.
Within this project I created a MainView where I included the UserControl via a ContentControl as you can see in the Code below. CurrentPage basically refers to the Viewmodel of the Keyboard.
<Window.Resources>
<DataTemplate DataType="{x:Type viewModel:KeyboardViewmodel}">
<view:KeyboardView/>
</DataTemplate>
</Window.Resources>
<Grid>
<Border Background="White">
<HeaderedContentControl Content="{Binding Path=CurrentPage}"/>
</Border>
<TextBox Width="120"/>
</Grid>
I now have the OnScreenKeyboard and a Textbox in my Window. Clicking into the Textbox and pressing buttons of my OnScreenKeyboard will result in text appearing in my Textbox. All Controls within the KeyboardView are set to avoid getting focus. This is necessary to maintain focus on the Textbox.
The Buttons in the KeyboardView all bind to the Command ClickCommandin my KeyboardViewmodel. Here is the code of the KeyboardViewmodel:
public class KeyboardViewmodel : BaseModel
{
public BaseCommand ClickCommand { get; set; }
public KeyboardViewmodel()
{
ClickCommand = new BaseCommand(PressAndRelease);
}
public void PressAndRelease(object key)
{
if (((string)key).Length <= 1)
SendKeys.SendWait((string)key);
else
SendKeys.SendWait("{" + (string)key + "}");
}
}
Now I did create a NuGet Package with these Files and imported them to the project where I want to use my OnScreenKeyboard.
I did do basically the same as when I tested the OnScreenKeyboard before.
But let me explain the structure of the project a little more:
I have a MainView + MainViewmodel. The MainViewmodel manages the navigation between available pages. To show these pages I have - as in the short example before - a ContentControl whose content is bound to a CurrentPage Property. The MainViewis a normal Window, all other Views are UserControls.
In one of these pages I need an OnScreenKeyboard (DetailsView + DetailsViewmodel). So it seemed logical to me to use another ContentControl within the DetailsView:
<Border Grid.Column="0" Grid.Row="4" Grid.ColumnSpan="3" Height="Auto" Width="Auto">
<ContentControl Content="{Binding Path=OnScreenKeyboard}"/>
</Border>
I create the KeyboardViewmodel in the constructor of the DetailsViewmodel. The constructor of the DetailsViewmodel is called in the MainViewmodel at startup.
So now everything works out fine so far, the OnScreenKeyboard is shown on the correct page in the correct place. If I click a button of the OnScreenKeyboard the proper bound command is called and the SendKeys.SendWait() Method is called.
But no text appears in the TextBox. I have a very bad understanding of the SendKeys.SendAwait() Method. Also, the MSDN Documentation seems to be not very exhaustive on this topic.
It states: "Sends the given keys to the active application, and then waits for the messages to be processed."
Now. The Active / Focused Application is my Application. So my guess is that the KeyStrokes should be processed by my Textbox.
My Questions:
Any guesses how to debug the 'SenWait()' Method further e.g. track where the strokes are really sent to or something like that?
Is this the correct way for sending KeyStrokes to an active Application? It seems like SendKeys comes from Windows Forms, I use WPF.
Should I just pass my Textbox as reference to the OnScreenKeyboard and write directly to the referenced Textbox? This would make me much less flexible in regards of reusability.
Update:
As pointed out in the comments this could probably be a duplicate question.
I am well aware of the various different solutions and have already considerd them:
http://wpfkb.codeplex.com/
http://www.codeproject.com/Articles/32568/A-Touch-Screen-Keyboard-Control-in-WPF
http://www.codeproject.com/Articles/145579/A-Software-Virtual-Keyboard-for-Your-WPF-Apps
But as one may understand these projects are looking all way too powerfull for my simple needs.
Here a screenshot to provide a better understanding of my needs:
It is really as simple as that. 4 rows of buttons that will never change, no other controls / functionality than sending the CommandParameter of the pressed button to the Textbox / Active Form.
Researching on that specific problem hasn't shown any problems like that. In most other SO Questions the problem is to send Data to another Window, not to send Data WITHIN the current Window.
So I don't consider this question as duplicate.