Please see mockup code here
I am creating an interactive search page that fetches data as the user inputs criteria. To make a long story short I have several combo boxes that have their SelectionChanged
event handled by EventToCommand
.
EventToCommand
calls a method on my ViewModel
that, among other things, changes the selected item for several combo boxes. Of course that triggers EventToCommand
and the whole process happens again... and again... and again....
So my question is, is there a way to make 开发者_Python百科the binding to EventToCommand
truly OneWayToSource
so that an update from the source does not trigger the event?
Method 1 below shows a perhaps valuable illustration of a technique, but most applications will probably be best served by Method 2.
Method 1
As a first approach, I took the approach suggested by jberger. However, since I am relying upon values contained in the event args, and I want to maintain the separation of concerns between my View and ViewModel as per MVVM goals and principles, I placed this added logic in my code-behind to keep the dependency in the View code.
I used a hash of the AddedItems contents of the event args to distinguish "repeat" calls due to property binding on another ComboBox from new calls to the event handling method due to user interaction.
int hashCode = 0;
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string addedItemsCatString = "";
foreach (string item in e.AddedItems) addedItemsCatString += item;
int newHashCode = addedItemsCatString.GetHashCode();
if ( newHashCode == hashCode) return;
hashCode = newHashCode;
// execute Command code here
}
Concatenating the contents of AddedItems is not strictly necessary for a ComboBox where only one item can be selected at a time, but it allows for a similar approach on multi-select controls.
Method 2
Since I was not completely satisfied with Method 1, I kept thinking about a better solution. The insight that came to me was that I really was only looking to issue the command once, based upon a user interaction. What looks like a good flag to distinguish a SelectionChanged event due to a user interaction from those due to a property binding is keyboard focus.
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!(sender as FrameworkElement).IsKeyboardFocusWithin) return;
// execute Command code here
}
As such the above test may be the best solution for the bulk of cases, including ones where a SelectionChanged event is initiated by another mode of input not involving any of your GUI selectors, such as a keyboard shortcut or an internal change in state of your program - or any place you might execute a Command which would result in multiple SelectionChanged events firing if you used multiple controls to control a setting. The instance property FrameworkElement.IsKeyboardFocused property and the static Keyboard.Focus(frameworkElementInstance) method may also be useful for different controls or scenarios.
More on Keyboard focus can be found on msdn here.
精彩评论