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
Related
I have a user control that use another user control. The child user control has a combobox and the click event works because i can open the combobox, but the double click it doesn't work.
My code is this:
Main user control:
<StackPanel>
<views:ucMyChildUserControl/>
</StackPanel>
My child user control:
<StackPanelOrientation="Horizontal">
<StackPanel Orientation="Vertical">
<Label Content="Content" Style="{StaticResource LabelDefault}"/>
<ComboBox Name="cmbMyCombobox"/>
</StackPanel>
<!--More related controls-->
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding MyCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</StackPanel>
But I have realized that if the comand of mouse double click is set in the parent user control, it works:
<views:ucChildUserControl>
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding MyCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</views:ucChildUserControl>
So I guess the problem is about the handling of the event, but I don't know how to catch it in the child user control.
Thanks.
The issue is that the MouseDoubleClick event and the PreviewMouseDoubleClick are defined on Control. Since UserControl is a derivative of Control, the event is available and can be handled. However, StackPanel is not a derivative of Control so the event is not available, therefore the trigger does not work.
There are workarounds to this in code-behind that you can eventually turn into a behavior for MVVM, but simple workarounds like using input bindings on the left mouse click action only work on some elements, as others like ComboBox will already handle it and then the input bindings are not triggered.
<StackPanel Orientation="Horizontal">
<StackPanel.InputBindings>
<MouseBinding MouseAction="LeftDoubleClick"
Command="{Binding MyCommand}"/>
</StackPanel.InputBindings>
<StackPanel Orientation="Vertical">
<Label Content="Content"/>
<ComboBox Name="cmbMyCombobox"/>
</StackPanel>
<!--More related controls-->
</StackPanel>
The most simple solution without creating additional code is to wrap the StackPanel in a control that is a derivative of Control, e.g. a ContentControl, like this.
<ContentControl>
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical">
<Label Content="Content"/>
<ComboBox Name="cmbMyCombobox"/>
</StackPanel>
<!--More related controls-->
</StackPanel>
<b:Interaction.Triggers>
<b:EventTrigger EventName="MouseDoubleClick">
<b:InvokeCommandAction Command="{Binding MyCommand}" />
</b:EventTrigger>
</b:Interaction.Triggers>
</ContentControl>
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.
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"}">
I have a popup with a TextBox that the user should enter a ticket number into, and then when the user presses the enter key I want the ticket number to be passed to the ViewModel which will retrieve the ticket.
Here's the xaml for the TextBox:
<TextBox x:Name="TicketNumber">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown">
<i:InvokeCommandAction Command="{Binding OpenTicketCommand}"
CommandParameter="{Binding ElementName=TicketNumber,
Path=Text}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
The above works on any keypress, but I really only want it to happen when the enter key is pressed. How would I go about doing that?
EDIT: I am assuming it would have to be done programmatically (hence the title), but if not that's okay too.
You could use InputBindings - KeyBinding as alternative approach.
Something like this:
<TextBox x:Name="TicketNumber">
<TextBox.InputBindings>
<KeyBinding Key="Enter"
Command="{Binding OpenTicketCommand}"
CommandParameter="{Binding ElementName=TicketNumber,
Path=Text}"/>
</TextBox.InputBindings>
</TextBox>
Trying to bind the click or checked event on a WPF chekbox to a command in my viewmodel, but im unsure on the technique and the event names, can anyone point me in the right direction?
For now the code compiles but the the trigger does not call the FooCommand
<CheckBox IsChecked="{Binding PartData.ReportIncluded, Mode=TwoWay}"
VerticalAlignment="Center">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown" >
<i:InvokeCommandAction Command="{Binding FooCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
Looks like you're missing the "On" prefix of your event, i.e. OnMouseLeftButtonDown or OnPreviewMouseLeftButtonDown