How to make the binding happen from the ViewModel

落花浮王杯 提交于 2019-12-25 05:08:18

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!