问题
I'm trying to capture the Enter key being pressed on a text box, so that I can kick off an update to the server. It's not working, and so I've reduced the problem to it's simplist elemetns.
In this example, it seems that the binding is not happening per keystroke, but at sometime later. I need to the binding to be completed by the time the enter key is pressed. Consider the following XAML and function from the VM.
Here's the XAML of the textbox
<TextBox Text="{Binding TextValue, Mode=TwoWay}" Height="23" Width="300">
<i:Interaction.Triggers>
<i:EventTrigger EventName="KeyDown">
<cmd:EventToCommand Command="{Binding KeyDownCommand}"
PassEventArgsToCommand="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
The KeyDownCommand fire as expected, howerver the value is not yet in the TextValue property. If I hit enter a second time then the value is in the property? Here's the KeyDownCommand. The constructor of the ViewModel sets the keyDownCommand correctly.
public RelayCommand<RoutedEventArgs> KeyDownCommand { get; private set; }
private void KeyDownAction(RoutedEventArgs eventArg)
{
var source = eventArg.OriginalSource as FrameworkElement;
var e = eventArg as KeyEventArgs;
if (source != null && e != null && e.Key== Key.Enter)
{
e.Handled = true;
MessageBox.Show(TextValue);
}
}
It seems that what I need is a way to "post" the Text of the TextBox back to the TextValue property of the VM when the Enter key is pressed. Or is there something else I'm missing.
回答1:
Try setting UpdateSourceTrigger
to PropertyChanged
on binding, like this:
<TextBox Text="{Binding TextValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Height="23" Width="300">
Now the view model property will be update every time the text is changed.
Update:
For Silverlight, as an alternative to UpdateSourceTrigger
, you can use the following simple behavior that updates binding source whenever text changes:
public class TextChangedUpdateSourceBehavior : Behavior<TextBox>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.TextChanged += OnTextChanged;
}
private void OnTextChanged(object sender, TextChangedEventArgs e)
{
var bindingExpression = AssociatedObject.GetBindingExpression(TextBox.TextProperty);
if (bindingExpression != null)
{
bindingExpression.UpdateSource();
}
}
}
Use it like this:
<TextBox Text="{Binding TextValue, Mode=TwoWay}" Height="23" Width="300">
<i:Interaction.Behaviors>
<b:TextChangedUpdateSourceBehavior />
</i:Interaction.Behaviors>
</TextBox>
回答2:
No sooner did I post the question, than I hit upon the answer.
Here's the corrected KeyDownAction
private void KeyDownAction(RoutedEventArgs eventArg)
{
var source = eventArg.OriginalSource as FrameworkElement;
source.GetBindingExpression(TextBox.TextProperty).UpdateSource();
var e = eventArg as KeyEventArgs;
if (source != null && e != null && e.Key== Key.Enter)
{
e.Handled = true;
MessageBox.Show(TextValue);
}
}
Of now as I type this I realize that I'm "breaking" the pattern, in as much as now my ViewModel knows more about the View that it should.
来源:https://stackoverflow.com/questions/8261673/how-to-make-the-binding-happen-from-the-viewmodel