I am having some trouble with an editable ComboBox and the updating of a binding. Currently I have a ComboBox where its UpdateSourceTrigger=LostFocus this is because I need to wait for the user to finish inputting somthing before I decide if the value is a new value (and thus create a new one).
Unfortunately, I have another feature which requires the binding to update when the value has changed aswell. Aka, LostFocus is no good to me in this case. As selecting a new value within the ComboBox it doesn't cause the LostFocus to fire (obviously). So I need to find a way to force update the binding.
I have looked into the SelectionChanged and forcing the update on the binding:
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding ParentConversation.ViewModel.ComboSelectionChanged}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type controls:StoryForgeComboBox}}}"/>
</i:EventTrigger>
And updating the binding in code behind like so:
be = BindingOperations.GetBindingExpression(ele, ComboBox.TextProperty);
if (be != null)
{
be.UpdateSource();
}
Unfortunately I CANNOT update the binding at this point as the value has yet to change. See this stackoverflow topic: ComboBox- SelectionChanged event has old value, not new value
There is a trick where you can possibly use the DropDownClosed event and then update the binding, this works but does not work if you use the Up/Down arrow keys which never opens the ComboBox. Also hooking into KeyUp and KeyDown is too early. The binding cant be updated yet.
So my question is, when is a good time to say "Hey Mr Combo Box, You can update your bindings now".
Cheers.
You can change the SelectionChanged event trigger to LostFocus:
<ComboBox
IsEditable="True"
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem}"
Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Triggers>
<i:EventTrigger
EventName="LostFocus">
<i:InvokeCommandAction
Command="{Binding Command}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
When the user types, Text is updated.
When the user types and the ComboBox finds a match in the Items, SelectedItem is changed.
When the user types, the ComboBox does not find a match and a item was previously selected, SelectedItem is set to null.
When the user selects an item, both SelectedItem and Text are updated.
When the user leaves the ComboBox (losing focus), Command is triggered.
When the user has typed text and opens the drop down list, Command is triggered.
EDIT: strangely enough Command is also triggered when it receives focus.
Is this the behavior you want?
Related
I have data coming from the service that has 7 columns. I can show them all in the grid view but I like to know how to show 2 of those columns in another control may be textblock.
So when someone clicks on the row, the second control will be updated with information in the other two columns.
I tried to use this in my MVVM
</ListView.View>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding OnRowClickCommand}" CommandParameter="{Binding}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListView>
Has anyone tried to do this before ? Any examples would be great help.
Turns out it was very simple.. Here it is if anyone else wants to know. Did not need event handler etc.
<TextBlock Text="{Binding ElementName=ListViewName,Path=SelectedItem.Column}"/>
However I am not sure currently how I can conditionally show a label for this information..
I have a tabbed GUI with each tab containing a Frame. I use the EventToCommand with the SelectionChangedEvent whenever a new TabItem is selected. I do this to update the state of the app. This all works fine - a little bit too fine, the event gets fired too often. Here is my problem:
How can I prevent the event from bubbling up the visual tree by setting the Handled property on the event when using the mvvm light eventToCommand feature?
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseLeftButtonDown">
<mvvm:EventToCommand
Command="{Binding YourCommand}"
PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
Your command needs to provide parameter from method like RelayCommand . This parameter is event args providing Handled property. More here.
I have this element in my xaml (DevExpress item):
<dxe:ComboBoxEdit IsTextEditable="False" EditValue="{Binding IDTIPOCONN}"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window},Path=DataContext.ttc}" />
All the binding are correct, and when I change the value, I trigger some event from my ViewModel.
My problem is the update of the value is executed only when I leave the focus of my comboBox. I need, instead, to execute my action when the value is changed, before leaving its foucs.
How can I do it? I need this because selecting one or another from the list, I show to the user some hidden elements.
Try for Binding set UpdateSourceTrigger=PropertyChanged:
<dxe:ComboBoxEdit IsTextEditable="False"
EditValue="{Binding Path=IDTIPOCONN, UpdateSourceTrigger=PropertyChanged}" ... />
In this case, most likely the default value of UpdateSourceTrigger is LostFocus.
Let's say I currently have an ItemsControl whose DataTemplate is a bunch of buttons. I'm wiring up these buttons' click events, but how am I to know which button was clicked? Should I not use a ItemsControl?
I'm trying to have no code-behind, but being pragmatic may be necessary.
<ItemsControl>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Margin="10">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding ItemsControlButtonClicked, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If you want to know what Item was clicked, then pass {Binding } as the CommandParameter and it will pass the selected object to your Command
If you want to know what Button was clicked, I would do that in the code-behind since ViewModels do not need to know anything about the UI, and that includes buttons.
Also since your control is a Button, you should use the Command property instead of a Click trigger.
<Button Command="{Binding ItemsControlButtonClicked}" />
You can send parameters along with the command and based on these parameters you can find out which button was clicked
In my project I also use the MVVM Light I has an dropdown with collection of items, and a button which user press and action depend on selected item from drop down
you should create a Relay command with parameter look at the example from my code
public RelayCommand<Project> StartTimer { get; private set; }//declare command
StartTimer = new RelayCommand<Project>(OnStartTimer);
private void OnStartTimer(Project project)
{
if (project != null)
{
currentProject = project;
if (!timer.IsTimerStopped)
{
timer.StopTimer();
}
else
{
Caption = "Stop";
timer.StartTimer();
}
}
on the view I bind the drop down with collection of class Project
and for button command parameter I bind the selected item form drop down
look at the code
<ComboBox Name="projectcomboBox" ItemsSource="{Binding Path=Projects}" IsSynchronizedWithCurrentItem="True" DisplayMemberPath="FullName"
SelectedValuePath="Name" SelectedIndex="0" >
</ComboBox>
<Button Name="timerButton" Content="{Binding Path=Caption}" Command="{Binding Path=StartTimer}"
CommandParameter="{Binding ElementName=projectcomboBox, Path=SelectedItem}" ></Button>
pay attention to Command and CommandParameter binding
also you can use this approache not only for drop down
Well, you can use the Sender.DataContext which is the actual data.
Create command properties in your view model class (using Josh Smith's RelayCommand pattern is the simplest way to do this) and bind each button's Command to the appropriate one. Not only is this straightforward to do and simple to maintain, it also gives you an easy way of implementing the enable/disable behavior when you need to.
I am currently transforming a medium size WPF project to MVVM and I ran into a problem that I wasn't able to solve, yet. Maybe you could help me out?
The target framework is .NET 3.5.1.
I have a list view that gets its items from the underlying view model. That view model is exposing a command to remove the selected items from the list view. Therefore the command parameter is bound to the SelectedItems property of the list view.
<ListView ItemsSource="{Binding MyItems}"
x:Name="MyListView"
SelectionMode="Extended">
</ListView>
<Button x:Name="MyRemoveButton"
Content="Remove item"
Command="{Binding RemoveItemCommand}"
CommandParameter="{Binding ElementName=MyListView, Path=SelectedItems}">
My intention is to execute this command not only when pressing a button, but also when the KeyUp event is fired on the list view and the pressed key is "delete".
I was close to finding the solution when I stumbled upon interaction triggers in this example:
http://joyfulwpf.blogspot.com/2009/05/mvvm-invoking-command-on-attached-event.html?showComment=1250325648481#c3867495357686026904
Now the problem with this demo is that the command parameter is the pressed key, but in my case I need the command parameter to be the SelectedItems property and I need the command to execute only on a specific key.
Is there any way to do this without much overhead and in the MVVM way?
Something like this would be awesome:
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyUp">
<local:CommandAction Command="{Binding RemoveItemCommand}"
CommandParameter={Binding ElementName=MyListView, Path=SelectedItems}
EventArgument="Key.Delete"/>
</i:EventTrigger>
</i:Interaction.Triggers>
To do it in the MVVM way you need to bind "SelectedItems" property of the ListView to your ViewModel, so you could use it from your commands and wouldn't need to pass it via CommandParameter.
How strict is your separation requirement? If you don't have designers using Blend, then put a call to a ViewModel method into the KeyUp or PreviewKeyUp event handler in your code-behind.