WPF: How to redefine CanExecute method of ApplicationCommands - c#

I use standard Cut, Copy and Paste commands (which is part of ApplicationCommands class). Is it possible to redefine CanExecute method?
Here is my code:
XAML:
<Window.CommandBindings>
<CommandBinding Command="Copy"
CanExecute="CopyCanExecute" Executed="CopyExecuted"/>
</Window.CommandBindings>
<StackPanel>
<TextBox Name="txt"></TextBox>
<Button Command="Copy" CommandTarget="{Binding ElementName=txt}">copy</Button>
</StackPanel>
Code-behind:
private void CopyCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = false;
}
private void CopyExecuted(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Copy Executed");
}
The button still behave like its command is standard Copy command.

You do this via a CommandBinding. The local CommandBinding can specify a CanExecuteHandler.
For details and a working example, see this blog post.

The copy command will not work when the focus is on a textbox where the commands have already been handled, but it will work on elements like CheckBox etc.

In the CanExecute handler you might need to add `e.Handled = true; also, so that it doesnt go and execute the standard Copy.CanExecute()

You can set the commandbinding to the textbox directly instead of to the window.

Related

WPF: simplest way to call some method by shortcut

I checked a lot of of answers here about shortcuts bindings, but did not find the simple way to execute some method from the C# code.
First, in the following classic example I don't understand what actually we are binding. What the meaning of Command attribute? What is the ApplicationCommands? Where is ApplicationCommands.Open has been declared?
<Window.InputBindings>
<KeyBinding Command="ApplicationCommands.Open"
Gesture="CTRL+R" />
</Window.InputBindings>
In the one of answer of question similar to my one, "XAML is the markup language, so we could not call the method from there" has been told. OK, in this case, WHY we can call the method OnClickBtn1 from the code below?
<Button
x:Name="SomeButton"
Click="OnClickBtn1"/>
Finally, my problem. All I need is to execute OnClickBtn1 method by Ctrl+H (for example) shortcut same as effect when the button Btn1 clicked. I understand that following code is not enough.
XAML:
<Window x:Name="MainDisplay"
<!-- ... --->
>
<Window.InputBindings>
<KeyBinding Gesture="Ctrl+H" Command="{Binding OnClickBtn1}" />
</Window.InputBindings>
<!-- ... -->
<Button x:Name="Btn1"
Width="70"
Content="Button"
Click="OnClickBtn1"/>
C#:
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void OnClickBtn1(object sender, RoutedEventArgs e) {
System.Diagnostics.Debug.WriteLine("Btn1 has been clicked or Ctrl+H had been inputed");
}
}

How to build my own close button?

I have a wpf application with a MVVM. I am trying here to build my own close button. Based on this answer Creating a custom Close Button in WPF I added a button event handler in the View(xaml.cs) code. However, it is not recognizing the Close(); call (doesn't exist in the context - Can't resolve symbol).
Also I tried the other answer and added Command and CommandParameter into my button's xaml. But the function behind is not getting hits. In How to bind Close command to a button using the RelayCommand also my wpf is not recognizing RelayCommand. Then How can I use the RelayCommand in wpf said that I have to write it myself(really?). I remember there was a simple way similar to just set an event handler for the button and call Close();. But, how can I do that or why it is not working for me?
View code:
private void closeButton_Click(object sender, RoutedEventArgs e)
{
// I want to call close the whole app on button click
//Close(); is not recognized
}
private void performMainCloseButtonCommand(object Parameter)
{
// This doesn't get hits on button click
Window objWindow = Parameter as Window;
objWindow.Close();
}
Button XAML:
<Button x:Name="closeButton" RenderTransformOrigin="0.5,0.5" Padding="0" Margin="701,0,0,0" BorderThickness="0" Click="closeButton_Click" Command="{Binding MainCloseButtonCommand}" CommandParameter="{Binding ElementName = mainWindow}" Height="45" Width="45" >
<StackPanel Height="45" Width="45">
<Image x:Name="closeButtonImage" Margin="0" Source="/ProjectName;component/Resources/x.fw.png" Height="33"/>
<TextBlock Text="Close" Width="36" Padding="6,0,0,0" HorizontalAlignment="Center" Height="13" FontSize="10"/>
</StackPanel>
</Button>
Close isn't recognized in your event handler because there is probably no method called Close in your current class. If you want to call main window's close method you can use:
private void closeButton_Click(object sender, RoutedEventArgs e)
{
Application.Current.MainWindow.Close();
}
Above is not a good way to do this and does not align with MVVM pattern. Which relates to your second question. Without seeing remaining part of your code, its hard to say why command binding isn't working. My guess you haven't wired up the commands properly for it to fire. You will need to ensure that you have created your RelayCommand instance and your command properties are correctly set.

Ignore repetition in KeyBinding (holding the key - execute command just once)

I have keyboard shortcuts declared in my xaml using KeyBindings.
I would like to ignore repetitions due to key holding in few of them.
I have found only solutions using events and checking "IsRepetition", which doesnt really fit in my declaration of the keybindings.
Of course I could do it in the Command definition itself and measure a time difference between 2 last executes, but this gives me no way to differentiate multiple presses and 1 key holding.
What would be the best way to execute only on the first press and ignore the rest if the key is hold?
You are trying to change a behavior of the button. Better to use code for that.
The easiest way is to attach a preview event to the window like that:
<Window
...
PreviewKeyDown="HandlePreviewKeyDown">
Then in code handle it like that:
private void HandlePreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.IsRepeat)
{
e.Handled = true;
}
}
Sadly this would disable any repeat behavior, even in a textbox hosted by the form. This is an interesting question. If I find a more elegant way of doing this, I will add to the answer.
EDIT:
OK there are two ways to define Key Binding.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.InputBindings>
<KeyBinding x:Name="altD" Gesture="Alt+D" Command="{Binding ClickCommand}"/>
</Window.InputBindings>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Content="_Click" Command="{Binding ClickCommand}" />
<TextBox Grid.Row="1"/>
</Grid>
</Window>
The above button will generate a click because you implicitely requested the Alt-C gesture via the underscore: _Click content. Then the window has an explicit keybinding to Alt+D.
This code behind should now work for both cases and should not interfere with regular repeat:
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
base.OnPreviewKeyDown(e);
if (e.IsRepeat)
{
if (((KeyGesture)altD.Gesture).Matches(this, e))
{
e.Handled = true;
}
else if (e.Key == Key.System)
{
string sysKey = e.SystemKey.ToString();
//We only care about a single character here: _{character}
if (sysKey.Length == 1 && AccessKeyManager.IsKeyRegistered(null, sysKey))
{
e.Handled = true;
}
}
}
}
I would say if you create a very simple state machine of sorts that would take action on the KeyBinding on a KeyDown event and would ignore all other input until a KeyUp event is fired to give the KeyBinding a "one-shot" behavior.
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keyup.aspx
Use the keyUp method instead of KeyDown.

Can't wrap my head around implementing KeyBindings

I want to handle hotkeys in my application. Writing a keybinding requires a command, which is fine, but it's not clear to me what is the minimum amount of work needed to implement that command. All the examples I seem to find are over-engineered, unclear or assume I'm using the MVVM pattern which I am not.
So what are the basics to getting a keybinding to work?
Thanks!
The minimum amount of work needed to implement a command is simply a class that implements ICommand. RoutedCommand is a simplistic implementation that provides the basic functionality.
Once you have that command set up, the KeyBinding is quite simple. You simply provide a Key, and optional Modifiers for that key. A number of common commands have been included in .NET. For example, you can bind the Copy command to Ctrl+C using this mark-up:
<Window.InputBindings>
<KeyBinding Command="ApplicationCommands.Copy" Key="C" Modifiers="Ctrl"/>
</Window.InputBindings>
You can check out ApplicationCommands, ComponentCommands, and NavigationCommands for some other built-in commands.
The easiest way to make a Keybinding I know of is doing something like this
in XAML
<Window.CommandBindings>
<CommandBinding Command="MyCommand"
CanExecute="MyCommandCanExecute"
Executed="MyCommandExecuted" />
</Window.CommandBindings>
<Window.InputBindings>
<KeyBinding Command="MyCommand" Key="M" Modifiers="Ctrl"/>
</Window.InputBindings>
in code behind
private void MyCommandCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
e.Handled = true;
}
private void MyCommandExecuted(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Executed!");
e.Handled = true;
}
It's pretty readable in my opinion, but if you have any questions leave a comment!

WPF Listbox style with a button

I have a ListBox that has a style defined for ListBoxItems. Inside this style, I have some labels and a button. One that button, I want to define a click event that can be handled on my page (or any page that uses that style). How do I create an event handler on my WPF page to handle the event from my ListBoxItems style?
Here is my style (affected code only):
<Style x:Key="UsersTimeOffList" TargetType="{x:Type ListBoxItem}">
...
<Grid>
<Button x:Name="btnRemove" Content="Remove" Margin="0,10,40,0" Click="btnRemove_Click" />
</Grid>
</Style>
Thanks!
Take a look at RoutedCommands.
Define your command in myclass somewhere as follows:
public static readonly RoutedCommand Login = new RoutedCommand();
Now define your button with this command:
<Button Command="{x:Static myclass.Login}" />
You can use CommandParameter for extra information..
Now last but not least, start listening to your command:
In the constructor of the class you wish to do some nice stuff, you place:
CommandBindings.Add(new CommandBinding(myclass.Login, ExecuteLogin));
or in XAML:
<UserControl.CommandBindings>
<CommandBinding Command="{x:Static myclass.Login}" Executed="ExecuteLogin" />
</UserControl.CommandBindings>
And you implement the delegate the CommandBinding needs:
private void ExecuteLogin(object sender, ExecutedRoutedEventArgs e)
{
//Your code goes here... e has your parameter!
}
You can start listening to this command everywhere in your visual tree!
Hope this helps
PS You can also define the CommandBinding with a CanExecute delegate which will even disable your command if the CanExecute says so :)
PPS Here is another example: RoutedCommands in WPF
As Arcturus posted, RoutedCommands are a great way to achieve this. However, if there's only the one button in your DataTemplate then this might be a bit simpler:
You can actually handle any button's Click event from the host ListBox, like this:
<ListBox Button.Click="removeButtonClick" ... />
Any buttons contained within the ListBox will fire that event when they're clicked on. From within the event handler you can use e.OriginalSource to get a reference back to the button that was clicked on.
Obviously this is too simplistic if your ListBoxItems have more than one button, but in many cases it works just fine.
You could create a user control (.ascx) to house the listbox. Then add a public event for the page.
Public Event btnRemove()
Then on the button click event in the usercontrol
RaiseEvent btnRemove()
You can also pass objects through the event just like any other method. This will allow your user control to tell your page what to delete.

Categories

Resources