Как сделать привязку из ViewModel

Я пытаюсь зафиксировать нажатие клавиши Enter в текстовом поле, чтобы запустить обновление на сервере. Это не работает, поэтому я свел проблему к упрощенным элементам.

В этом примере кажется, что привязка происходит не по нажатию клавиши, а через какое-то время. Мне нужно, чтобы привязка была завершена к моменту нажатия клавиши ввода. Рассмотрим следующий XAML и функцию из виртуальной машины.

Вот XAML текстового поля

<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>

KeyDownCommand срабатывает, как и ожидалось, однако значение еще не находится в свойстве TextValue. Если я нажму Enter во второй раз, значение будет в свойстве? Вот команда KeyDown. Конструктор ViewModel правильно устанавливает keyDownCommand.

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);
    }
}

Кажется, мне нужен способ «отправить» текст TextBox обратно в свойство TextValue виртуальной машины при нажатии клавиши Enter. Или есть что-то еще, что мне не хватает.


person Ralph Shillington    schedule 24.11.2011    source источник


Ответы (2)


Попробуйте установить UpdateSourceTrigger в PropertyChanged при привязке, например:

<TextBox Text="{Binding TextValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Height="23" Width="300">

Теперь свойство модели представления будет обновляться каждый раз при изменении текста.

Обновление:

Для Silverlight в качестве альтернативы UpdateSourceTrigger можно использовать следующее простое поведение, которое обновляет источник привязки при каждом изменении текста:

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();
        }
    }
}

Используйте это так:

<TextBox Text="{Binding TextValue, Mode=TwoWay}" Height="23" Width="300">
    <i:Interaction.Behaviors>
        <b:TextChangedUpdateSourceBehavior />
    </i:Interaction.Behaviors>
</TextBox>
person Pavlo Glazkov    schedule 24.11.2011
comment
Как оказалось, UpdateSouceTrigger=PropertyChanged не подходит для Silverlight. Есть только два варианта: «По умолчанию» и «Явный». - person Ralph Shillington; 25.11.2011
comment
@Ralph - Извините, не заметил, что вопрос касается Silverlight. См. мой обновленный ответ для решения Silverlight. - person Pavlo Glazkov; 25.11.2011

Не успел я задать вопрос, как наткнулся на ответ.

Вот исправленный 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);
    }
}

Теперь, когда я печатаю это, я понимаю, что я «нарушу» шаблон, поскольку теперь моя ViewModel знает о представлении больше, чем должна.

person Ralph Shillington    schedule 24.11.2011