I'm working with the MVVM pattern in WPF (a bit new to both).
I'd like to set up an InputBinding on a CheckBox that corresponds to a Control + Click event, but do not see a Modifiers property on the MouseBinding element. This is what I'd like to achieve (fictitious code, obviously- Modifiers doesn't exist):
<CheckBox>
<CheckBox.InputBindings>
<MouseBinding MouseAction="LeftClick"
Command="{Binding CheckboxControlClickCommand}"
Modifiers="Control" />
</CheckBox.InputBindings>
</CheckBox>
Any ideas on how to accomplish this without using events?
Thanks!
Use it with keybinding too!
An old question but looks like the MouseBinding now provides a Gesture attribute just for this..
<CheckBox>
<CheckBox.InputBindings>
<MouseBinding Gesture="CTRL+LeftClick"
Command="{Binding CheckboxControlClickCommand}"/>
</CheckBox.InputBindings>
</CheckBox>
I ended up using Keyboard.Modifiers in the Execute() context of the ICommand, which seemed to work just fine.
if (Keyboard.Modifiers != ModifierKeys.Control) return;
...
I think a behavior would do the trick. You can take a look at this link.
Related
I have the following code which uses Microsoft's WPFToolkit AutoCompleteBox. I have tried adding an input binding inside it
xmlns:tk="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"
<tk:AutoCompleteBox IsTextCompletionEnabled="True" FilterMode="Contains" ItemsSource="{Binding DistinctItemNames, Mode=OneWay}"
SelectedItem="{Binding SelectedItemName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
x:Name="searchBox" Width="300" Height="23" VerticalContentAlignment="Center" >
<tk:AutoCompleteBox.InputBindings>
<KeyBinding Key="Return" Command="{Binding ShowSelectedItemsCommand}"/>
<tk:AutoCompleteBox.InputBindings>
</tk:AutoCompleteBox>
However, it doesn't work. I expect that the control itself handles the 'Enter' or 'Return' key so how can I override its default function?
I have also put that keybinding directly under the 'UserControl.InputBindings' and it also did not work. I hate to use Code Behind to handle the command logic.
You could try to handle the PreviewKeyDown event, either directly in the code-behind of the view:
private void AutoCompleteBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
AutoCompleteBox box = sender as AutoCompleteBox;
dynamic viewModel = box.DataContext;
viewModel.ShowSelectedItemsCommand.Execute(null);
}
}
...or by wrapping it in an attached behaviour: https://www.codeproject.com/Articles/28959/Introduction-to-Attached-Behaviors-in-WPF.
Neither approach breaks the MVVM pattern. In the first case you are just invoking the exact same view model command from the exact same view. But if you really "hate to use code-behind" for some strange reason, then create an attached behaviour.
Try having a look at this post: ReactiveCommand pass Command Parameter.
It uses Reactivity to accomplish the same thing you want.
Then, you can process the key received via KeyCode, and check if it is the key you want.
I am using MvvmLight toolkit for my event interactions, i have tried many solutions available but none worked. The combo box inside my data grid's Selection Changed event is not firing
Here is my xaml:
i used both InvokeCommandAction and EventToCommand:
EventToCommand Command="{Binding rlcCbSelectionChanged, Mode=OneWay}"
PassEventArgsToCommand="True"
InvokeCommandAction Command="{Binding rlcCbSelectionChanged, Mode=OneWay}"
Please tell me what am i missing??
Selection Changed event successfully fires on data grid with same procedure given above.
Well answer is quite simple i was missing an attribute that is optional that is why i leave this one previously but that causes selection change event not to fire. So i add my view model key as a static resource and it worked :)
So my working xaml look like :
<i:EventTrigger EventName="SelectionChanged">
<i1:InvokeCommandAction Command="{Binding Path=rlcCbSelectionChanged, Source={StaticResource dvm}}"/>
</i:EventTrigger>
I have a UserControl with some InputBindings. I wanted to make one of the input bindings (arrow key press) execute a command on a GUI control in my UserControl . So
e.g.
<UserControl.InputBindings>
<KeyBinding Key="Up" Command="{Binding ElementName=MyViewElement, Path=MoveUpCommand}"/>
<KeyBinding Key="Down" Command="{Binding ElementName=MyViewElement, Path=MoveDownCommand}"/>
</UserControl.InputBindings>
But, this fails because MyViewElement is not found because I assume it is declared later in the XAML. If I move my InputBindings to the end of the XAML file everything works as intended.
I kinda prefer my InputBindings to be at the top, is it possible to make it ignore the declaration order?
#Stewbob What are you talking about?
Take a look at this: http://msdn.microsoft.com/en-us/library/ms752308.aspx
<Window.CommandBindings>
<CommandBinding Command="ApplicationCommands.Open"
Executed="OpenCmdExecuted"
CanExecute="OpenCmdCanExecute"/>
</Window.CommandBindings>
According to what you said this should never work properly but it does:
<StackPanel>
<Menu>
<MenuItem Command="ApplicationCommands.Paste"
CommandTarget="{Binding ElementName=mainTextBox}" />
</Menu>
<TextBox Name="mainTextBox"/>
</StackPanel>
From what you said the binding comes first also it will be executed first and therefore the binding to mainTextBox should never work. Thats very not true.
Sure you can do everything in XAML, including such Binding at Window level. Show more code of your XAML/MyViewElement. Maybe we could tell you how to do it without errors. Also post your error here please.
But, this fails because MyViewElement is not found because I assume it is declared later in the XAML.
To avoid that, you can use the following in the code behind instead of the constructor:
protected override void OnInitialized(EventArgs e)
{
SomeCommand = new DelegateCommand(SomeExecuteMethod);
InitializeComponent();
base.OnInitialized(e);
}
This ensures the commands are already instantiated before you use them with:
Command="{Binding ElementName=MyUserCOntrol, Path=SomeCommand}"
I have a custom command and I try to execute them from the context menu, but they are always displayed as disabled unless I click any button on the UI (buttons do not have anything to do with commands).
After clicking a button, commands start to be displayed correctly (when they are unavailable they get disabled and enabled if available).
Edit: it turns out that it is not the button click which makes command work correctly, but button or other controls in focus (e.g. if I tab into a control this also enables my commands).
Here is the code for commands:
<Window.InputBindings>
<KeyBinding Command="{x:Static local:MainWindow.Quit}" Key="Q" Modifiers="Ctrl"/>
<KeyBinding Command="{x:Static local:MainWindow.Disconnect}" Key="D" Modifiers="Ctrl"/>
</Window.InputBindings>
<Window.ContextMenu>
<ContextMenu Opacity="95">
<MenuItem Header="Quit Application Ctrl + Q" Command="{x:Static local:MainWindow.Quit}"/>
<MenuItem Header="Disconnect from the pump Ctrl + D" Command="{x:Static local:MainWindow.Disconnect}"/>
</ContextMenu>
</Window.ContextMenu>
Here is the commands CanExecuteMethod:
public static RoutedCommand Quit = new RoutedCommand();
private void QuitCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
e.Handled = true;
}
This issue is due to the ContextMenu being on a separate Visual and Logical Tree to that of the Window and its Controls.
For anyone still looking for an answer to this issue - After trawling the internet I have found the most effective answer to be to include the following in any declaration of a MenuItem that needs its commands to be heard by it's "owner".
In layman's terms; if you want the commands of your context menu to be heard by the thing you're right clicking on. Add this code:
CommandTarget="{Binding Path=PlacementTarget,
RelativeSource={RelativeSource AncestorType=ContextMenu}
}"
Example:
<ContextMenu>
<MenuItem Header="Close" Command="Application.Close"
CommandTarget="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType=ContextMenu}}" />
</ContextMenu>
This will also work within Templates (something I found a lot of another solutions not to support). Here is an explanation of the meaning of the statement taken from elsewhere (I'm appalling at explaining things):
Every FrameworkElement has a DataContext that is an arbitrary object. The default source for a data binding is that DataContext. You can use RelativeSource.Self to change the source for a binding to the FrameworkElement itself instead of its DataContext. So the RelativeSource part just moves you "up one level" from the DataContext of the FrameworkElement to the FrameworkElement itself. Once you are at the FrameworkElement you can specify a path to any of its properties. If the FrameworkElement is a Popup, it will have a PlacementTarget property that is the other FrameworkElement that the Popup is positioned relative to.
In short, if you have a Popup placed relative to a TextBox for example, that expression sets the DataContext of the Popup to the TextBox and as a result {Binding Text} somewhere in the body of the Popup would bind to the text of the TextBox.
I honestly hope that this information saves someone who's new to WPF the headache I've gone through this weekend... though it did teach me a lot!
Completely different track, now:
there is indeed something special about the ContextMenu as the carrier for commands:
the menu is not regarded as part of the window and therefore does not behave like an element in its visual tree would.
There are different solutions for your problems defined here:
http://www.wpftutorial.net/RoutedCommandsInContextMenu.html
The easiest approach seems to be adding this to your XAML (for the window):
FocusManager.FocusedElement="{Binding RelativeSource={x:Static RelativeSource.Self}, Mode=OneTime}"
I just ran into this while trying to implement a custom context menu for AvalonDock. None of the solutions suggested above worked for me.
I got the context menu working by explicitly registering my command handlers on the ContextMenu class in addition to the main widow. The function below is a helper I used for command registration.
void RegisterCmd(RoutedCommand command, ExecutedRoutedEventHandler handler, CanExecuteRoutedEventHandler canExecute)
{
var binding = new CommandBinding(command, handler, canExecute);
this.CommandBindings.Add(binding);
CommandManager.RegisterClassCommandBinding(typeof(ContextMenu), binding);
}
There is probably some change "behind the scenes" that would normally enable the commands, but the view is not aware of this change.
One would need to see the Command-implementations to give more precise hints.
You can either make anything that changes your command-enable-state notify the view or manually trigger a command-refresh via CommandManager.InvalidateRequerySuggested(), for example when the context-menu opens.
WPF ICommands work that way; they requery their CanExecute function whenever something in the view changes (e.g. PropertyChanged-event is fired or a button is clicked), but they don't requery if they have no reason to.
This is a known bug. If there is no focused element in the window's main focus scope, the CanExecute routing will stop at the ContextMenu, so it will not reach to the CommandBinding on the Window, one workaround is to bind MenuItem's CommandTarget to the main window, as following code demonstrates:
<Window.ContextMenu>
<ContextMenu >
<ContextMenu.Items>
<MenuItem Command="ApplicationCommands.Open"
CommandTarget="{Binding Path=PlacementTarget,RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}"/>
</ContextMenu.Items>
</ContextMenu>
</Window.ContextMenu>
My control has a property that returns an ICommand object. Using XAML, how to I bind a button to it?
Without knowing anything about the relation of the two I would use element binding. E.g.
<YourControl x:Name="CmdSrc" />
<Button Command={Binding ElementName=CmdSrc, Path=CmdProperty} />
You should think about the approach that a control provides a command. It's seems to me some kind of weird. ;)
Regards
EDIT
Ah ok, it was just a hint. Just in case you didn't think about it.
Here is another way to bind your command. I've to admit that I didn't test it. But I think the following should work too.
When the Button is in the control you could also use relative binding.
<YourControl>
<Button Command={Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type YourControl}}, Path=CmdProperty} />
</YourControl>
Then you don't need a name for the control. I'm avoiding names when ever I can to prevent dirty workarounds in code behind.
Yes, I know it some kind of paranoid. ;)