InputBinding CommandParameter Binding to a collection - wpf

For KeyBinding I am setting up the CommandParameter in Xaml using Binding. In the Binding has a Converter setup.
When I bind the parameter to a property (INPC) the binding system re-evaluates using the Converter.
However, when I the parameter to observable collection, on CollectionChanged the binding system does not re-evaluate. Hence I receive the initial converted value.
Is there way I trigger CommandParameter to re-evalaute on CollectionChanged.
<TextBox Grid.Row="0" Text="{Binding MyParameter}">
<TextBox.InputBindings>
<KeyBinding Gesture="CTRL+D"
Command="{Binding MyCommand}"
CommandParameter="{Binding MyParameter,
Converter={StaticResource converter}}">
</KeyBinding>
<KeyBinding Gesture="CTRL+T"
Command="{Binding MyCommand}"
CommandParameter="{Binding ChangedValuesCollection,
Converter={StaticResource CollectionConverter}}">
</KeyBinding>
</TextBox.InputBindings>
</TextBox>
In the above code, I have setup a viewmodel (datacontext). But I intend to bind the command parameter to Grid's SelectedRows collection.

If you just want the selected items of DataGrid as your command parameter you can directly bind to it. Assuming Datagrid and Textbox are in same visual tree
<KeyBinding Gesture="CTRL+T"
Command="{Binding MyCommand}"
CommandParameter="{Binding SelectedItems, ElementName="myDataGrid"}">

Related

How can I disable combobox before button clicked in WPF MVVM

In my project I have a "Generate Reports" Button and a "Select Location" ComboBox. I want the user to be unable to choose a location before clicking
"Generate Report" Button.
the xaml containing the combobox and the button:
<Button Content="Generate Reports" Command="{Binding GenerateReportsCommand}" Height="36" Margin="4" />
<ComboBox Grid.Column="2" ItemsSource="{Binding Locations}" SelectedItem="{Binding SelectedLocation}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding LocationFilterCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
What can I do in the ViewModel or UI? Thank you for all your helps.
I'm going to assume you know how to use data binding (based on your post you already use it).
Create a new Boolean in your ViewModel and bind the ComboBox's IsEnabled to it. (Something like IsEnabled="{Binding YOURBOOLEAN}")
Update that Boolean from your GenerateReportsCommand after the user successfully generated the report. If you set that variable to true, the ComboBox's IsEnabled will also be set to true.
You should have an additional property inside the ViewModel.
private bool _areReportsGenerated = false;
public bool AreReportsGenerated
{
get => _areReportsGenerated;
set
{
_areReportsGenerated = value;
OnPropertyChanged(); // you method's implementation of INotifyPropertyChanged
}
}
If you don't have an implementation of INotifyPropertyChanged you can take a look at Microsoft one.
Inside GenerateReportsCommand you should set AreReportsGenerated to true.
In the xaml then you only have to bind the newly created property to the IsEnabled property of the ComboBox
<ComboBox Grid.Column="2" ItemsSource="{Binding Locations}" SelectedItem="{Binding SelectedLocation}" IsEnabled="{Binding AreReportsGenerated}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding LocationFilterCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
It should work.
I hope I was helpful.

How to pass textbox KeyEventArgs and textbox value in command wpf

I am struggling with a thing like i have a textbox
<TextBox Name="FilterInputText" Visibility="{Binding VisibiltyAttr}" Width="500" Height="30" Text="{Binding InputText}" HorizontalAlignment="Left" Margin="5">
<TextBox.InputBindings>
<KeyBinding Command="{Binding EnterCommand}" Key="Enter" />
<KeyBinding Command="{Binding DownSelectionCommand}" Key="Down" />
</TextBox.InputBindings>
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyUp">
<i:InvokeCommandAction Command="{Binding CompleteCommand}" CommandParameter="{Binding Text, ElementName=InputText}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
i have a event triggered here with something input inside textbox with "KeyUp" event. now i am working for autocomplete textbox so i showed suggestions on typing in a list box that is working fine. so i need to bind down key to bind with this text box so that after showing suggestions user can press down key and select his desired option from there.
It will work fine for keybinding for down key.
The problem is with event keyup because any key press inside textbox then this event triggerd. now i am sending textbox value as command parmeter but i also need to send keyeventargs with comamnd pararmter so that i can findout which key is pressed and when downkey comesup i will not further execute the method.
So how i can i pass both textbox value and keyeventargs as command parameter, i am strictly following mvvm pattern.
By default, InvokeCommandAction passes the event args if you do not specify a command parameter. Also, you're textbox is bound to a property on your view model. So, if you change the the code as follows:
<TextBox Name="FilterInputText" Visibility="{Binding VisibiltyAttr}" Width="500" Height="30" Text="{Binding InputText, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left" Margin="5">
<TextBox.InputBindings>
<KeyBinding Command="{Binding EnterCommand}" Key="Enter" />
<KeyBinding Command="{Binding DownSelectionCommand}" Key="Down" />
</TextBox.InputBindings>
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyUp">
<i:InvokeCommandAction Command="{Binding CompleteCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
And then make sure your command's execute method has the right event args type for a parameter, then when the CompleteCommand is invoked you should have the event args as the parameter, and you should be able to check the InputText property on your view model for the text value.
Notice that I added "UpdateSourceTrigger=PropertyChanged" to the binding on the TextBox Text property. That will cause the property to be updated in the view model every single time the user types.
See the following link for my source on InvokeCommandAction's default behavior:
https://github.com/Microsoft/XamlBehaviors/issues/126

Can a WPF DataTrigger Deactivate a KeyBinding?

I've got a ListView with some KeyBindings that let the user move and delete entries with keyboard shortcuts. However, I don't want the bindings to be accessible all the time.
The button controls to add, remove, and move entries have their visibility tied to the selection of a ComboBox (only certain users can edit). I want the keyboard shortcuts to deactivate based on the box selection as well.
I haven't been able to find any info on whether or not this is possible yet. What do you guys think?
<ComboBox x:Name="TesterIdentityBox" ItemsSource="{Binding Path=TesterIdentityList, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Name" SelectedItem="{Binding Path=TesterIdentitySelection, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="{Binding TesterIdentityIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<ListView ItemsSource="{Binding TestViewList, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedIndex="{Binding SelectedTestIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedItem="{Binding Path=SelectedTest}">
<ListView.InputBindings>
<KeyBinding Key="Up" Command="{Binding Path=MoveTestUpCommand}" CommandParameter="{Binding Path=SelectedTest.Description}" />
<KeyBinding Key="Down" Command="{Binding Path=MoveTestDownCommand}" CommandParameter="{Binding Path=SelectedTest.Description}" />
<KeyBinding Key="Delete" Command="{Binding Path=RemoveTestCommand}" />
</ListView.InputBindings>
I used Style Setters with DataTriggers to alter the command buttons' visibility, but I don't know what (if anything) is the equivalent for a non-visual element like a KeyBinding.
The simplest way in this case would be to implement the CanExecute() methods in your MoveTestUpCommand, MoveTestDownCommand and RemoveTestCommand. This methods should return false when you don't want the user to be able to do those things. So, your KeyBindings will have no effect since the commands will not be executed.
If your buttons' Command properties are also bound to these commands, these buttons will then update their availability (IsEnabled property) automagically according to the CanExecute() return values. To update the view state from the viewmodel, simply call the RaiseCanExecuteChanged() methods on corresponding commands (this depends on your ICommand implementation however).
To set the button's visibility according to its availability, you could use something like:
<Button
Command = "{Binding SampleCommand}"
Visibility = "{Binding IsEnabled, RelativeSource = {RelativeSource Self}, Converter = {StaticResource BooleanToVisibilityConverter}}"/>
There is an implementation of the BooleanToVisibilityConverter in System.Windows.Controls.

Implementing EventHandlers within ViewModel with MVVM WPF

I have a ComboBox:
<ComboBox x:Name="cbConnection"
ItemsSource="{Binding Source={StaticResource XmlConnectionList}, XPath=//ComboItem}"
DisplayMemberPath="Key"
SelectedValuePath="Value"
SelectedValue="{Binding Path=ConnectionString,ValidatesOnDataErrors=True,UpdateSourceTrigger=PropertyChanged}"
Margin="{StaticResource ConsistentMargins}"
Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate}" Width="120"
LostFocus="{Binding Path=cbConnection_LostFocus}"/>
I am trying to get the LostFocus event handler moved to the ViewModel because I do some error handling within the setter for the SelectedValue binding "ConnectionString" found in the ViewModel. I want this to happen if a user reselects the same ComboBoxItem, which does fire OnPropertyChanged unless a different list item is selected.
The above binding results in error
A 'Binding' cannot be set on the 'AddLostFocusHandler' property of
type 'ComboBox'. A 'Binding' can only be set on a DependencyProperty
of a DependencyObject.
How can I fire repeatable code within the ViewModel on selection of any item within a ComboBox, regardless of the user's selection?
You'll need to include a reference to the System.Windows.Interactivity dll, but it will look something like this:
xmlns:b="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
<ComboBox>
<b:Interaction.Triggers>
<b:EventTrigger EventName="LostFocus">
<b:InvokeCommandAction Command="{Binding cbConnection_LostFocus}" CommandParameter="{Binding}"/>
</b:EventTrigger>
</b:Interaction.Triggers>
</ComboBox>
Josh's answer worked for me with a different namespace:
xmlns:b="http://schemas.microsoft.com/expression/2010/interactivity"
<ComboBox>
<b:Interaction.Triggers>
<b:EventTrigger EventName="LostFocus">
<b:InvokeCommandAction Command="{Binding cbConnection_LostFocus}" CommandParameter="{Binding}"/>
</b:EventTrigger>
</b:Interaction.Triggers>
</ComboBox>

Treeview context menu command not firing

I have a treeview bound to a Observable collection of some property type. There is a HierarchicalDataTemplate that shows the data in treeview. Now i need to show specific context menu for each HierarchicalDataTemplate item.
I am using the following XAML to show context menu:
<HierarchicalDataTemplate ItemsSource="{Binding Collections}">
<TextBlock Text="{Binding Path=Name}">
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="Create" Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.AddCommand}" CommandParameter="{Binding}"/>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</HierarchicalDataTemplate>
Here the AddCommand is written in the view model that is bound to this under control..
I am able to see the context menu, but event is not firing on click on menu item.
Please help..
Your command binding will not work because the ContextMenu is not on the same logical tree as your UserControl is, therefore it will not find the UserControl ancestor. However your ContextMenu should inherit its container's datacontext automatically.
So this should work -
<ContextMenu>
<MenuItem Header="Create" Command="{Binding AddCommand}" CommandParameter="{Binding}"/>
</ContextMenu>
However the AddCommand property should exist on your HierarchicalDataTemplate bound item.
EDIT:
If your Command is not defined in your HierarchicalDataTemplate's bound item and instead in your UserControl. Then another think you may try is giving your UserControl a name, and then bind the command to it by ElementName. Like this
Updated again:
<ContextMenu>
<MenuItem Header="Create" Command="{Binding ElementName="MyUserControl" Path="DataContext.AddCommand"}" CommandParameter="{Binding}"/>
</ContextMenu>

Resources