WPF: Resetting a ComboBox after change
I' using the MVVM pattern to build an application. In this application I have a ComboBox that is bound to a colletion of items and to a property containing the selected item:
<ComboBox ItemsSource="{Binding Path=Persons, Mode=OneTime}"
SelectedValue="{Binding Path=SelectedPerson, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
The collection with the items for this ComboBox is initialized with an "instruction text" as the first item, and then a bunch of ordinary items:
Persons.Add("Open Person...");
Persons.Add("Anders Andersson");
Persons.Add("Bengt Bengtsson");
Persons.Add("Carl Carlsson");
Persons.Add("Daniel Danielsson");
The behavior I'd like to have for this ComboBox is that it initially shows the instruction text (this is of course easily accomplished). When the user selects a person in the ComboBox, the application takes some action (opens the selected person) and then resets to the instruction text.
As first thought this would be easy by having this property for the selected item:
private string _selectedPerson = "Open Person...";
public string SelectedPerson
{
get
{
return _selectedPerson;
}
set
{
if (value != _selectedPerson)
{
OpenPerson(value);
OnPropertyChanged("SelectedPerson");
}
}
}
My idea was that when the user selects anything else than the instruction text in the ComboBox, OpenPerson() will be called with the selected value, but the selected value will not be stored in the private field (_selectedPerson). Then I trigger the PropertyChanged event that will make the ComboBox read the value of the property SelectedPers开发者_JS百科on and update itself (SelectedValue). Because the _seletedPerson field is still the instruction text, the ComboBox will reset itself to that.
This does NOT work.
Actually, everything seem to happen as I expected. OpenPerson() is called with the right parameter and then the PropertyChanged event is triggered. However, the action of the GUI to change the value shown by the ComboBox is actually performed AFTER all this. This means that whatever I set SelectedPerson to, the ComboBox will show the item that was selected in the GUI.
Is there an elegant way to get around this?
Actually, I have gotten around this myself. But it involved code in CodeBehind, two flags in the ViewModel and some nasty code in the SelectedPerson-property. The solution is, well, not satisfying to say the least... ;) So, I was hoping someone smarter than me could come up with a better solution! :)
Have you tried creating a SelectionChanged handler for the Combobox and changing back to "Open Person..." there instead?
Or even a Trigger for the combobox that set's it to Index=0 or something?
I just found this looking for something else, I Hope I can still help.
I bind a command to the selectionchanged event, that command is defined in the Viewmodel and thus follows the MVVM pattern(no code behind).
I use the MVVM-Light framework so you need to include the following which includes a blend interactivity reference:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:cmd="http://www.galasoft.ch/mvvmlight"
the following is how I declare it in my xaml:
<ComboBox Name="idClient" Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="2"
Style="{StaticResource FTC_DetailComboBox}"
ItemsSource="{Binding ClientViewSource.View}"
SelectedItem="{Binding client}"
SelectedValuePath="idClient"
SelectedValue="{Binding idClient, Mode=TwoWay, ValidatesOnDataErrors=True}"
DisplayMemberPath="chrCompany"
>
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<cmd:EventToCommand Command="{Binding LostFocusValidateCommand}" CommandParameter="idStatus"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
Here is the code from my viewmodel(in vb.net). RelayCommand is a simple implementation of ICommand
Private _LostFocusValidateCommand As RelayCommand(Of String)
Public ReadOnly Property LostFocusValidateCommand() As RelayCommand(Of String)
Get
If _LostFocusValidateCommand Is Nothing Then
_LostFocusValidateCommand = New RelayCommand(Of String)(AddressOf LostFocusValidateExecute)
End If
Return _LostFocusValidateCommand
End Get
End Property
Private Sub LostFocusValidateExecute(sParam As String)
''perform commands here
End Sub
精彩评论