MVVM Light слишком быстрый :) - PullRequest
4 голосов
/ 02 мая 2010

У меня есть простая страница WM7 с TextBox. Далее я присвоил EventToCommand (RelayCommand<string>) этому TextBox, реагируя на событие TextChanged. Для проверки исходов я сделал дополнительный метод TextBox_TextChanged в коде страницы. Обе команды и TextBox_TextChanged распечатывают окно сообщения с содержимым текстового поля.

Начальное значение TextBox равно "ABC". Затем я нажимаю D и:

  1. TextBox_TextChanged отпечатки ABCD.
  2. Команда печатает ABC. D отсутствует.

Почему команда такая быстрая?

Объявление команды:

public RelayCommand<string> TextChanged {get; private set;}

Инициализация команды:

TextChanged = new RelayCommand<string>((s) => MessageBox.Show(s));

Привязка команды:

<TextBox x:Name="SearchTextBox" Margin="10,0" TextWrapping="Wrap" Text="{Binding SearchString, Mode=TwoWay}" FontStyle="Italic" TextChanged="SearchTextBox_TextChanged" >
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="TextChanged">
            <GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding TextChanged, Mode=OneWay}" CommandParameter="{Binding Text, ElementName=SearchTextBox}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</TextBox>

Ответы [ 4 ]

6 голосов
/ 02 мая 2010

Я не могу воспроизвести это поведение. Я пытался использовать EventToCommand и поведение (которое просто слушает событие TextChanged).

Не подозревая код, я подозреваю, что это может быть связано с тем, как вы получаете текст поля поиска или с логической ошибкой в ​​другом месте.

Это фрагмент того, как я использую EventToCommand:

<TextBox Name="SearchTextBox">
  <i:Interaction.Triggers>
    <i:EventTrigger EventName="TextChanged">
      <cmd:EventToCommand Command="{Binding TestTextChangedCommand,Mode=OneWay}" CommandParameter="{Binding Path=Text, ElementName=SearchTextBox}"/>
    </i:EventTrigger>
  <i:Interaction.Triggers>
</TextBox>

В виде модели

m_TestTextChangedCommand = new RelayCommand<string>(val => System.Diagnostics.Debug.WriteLine(val));

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

Альтернативой этому подходу может быть использование поведений и привязки TwoWay для обновления свойства:

<TextBox Name="SearchTextBox" Text="{Binding TextInViewModel, Mode=TwoWay}" >
  <i:Interaction.Behaviors>
    <sc:UpdateOnTextChangedBehavior/>
  </i:Interaction.Behaviors>
</TextBox>

UpdateOnTextChangedBehavior class:

    public class UpdateOnTextChangedBehavior : Behavior<TextBox>
    {
        protected override void OnAttached()
        {
            base.OnAttached();

            this.AssociatedObject.TextChanged += 
                new TextChangedEventHandler(AssociatedObject_TextChanged);
        }

        void AssociatedObject_TextChanged(object sender, TextChangedEventArgs e)
        {
            System.Diagnostics.Debug.WriteLine(((TextBox)sender).Text);
            BindingExpression binding = 
                this.AssociatedObject.GetBindingExpression(TextBox.TextProperty);
            if (binding != null)
            {
                binding.UpdateSource();
            }
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();

            this.AssociatedObject.TextChanged -= 
                new TextChangedEventHandler(AssociatedObject_TextChanged);
        }
    }

То, что сделано выше, имитирует поведение рабочего стола WPF Binding с UpdateSourceTrigger=PropertyChanged, которого нет в Silverlight. Так что произойдет, когда вы введете в текстовое поле, свойство TextInViewModel будет обновлено. Это свойство не обязательно должно быть DependencyProperty, оно может быть просто обычным свойством CLR.

1 голос
/ 10 декабря 2011

У меня была похожая проблема, и я обнаружил, что операция привязки данных не всегда срабатывает, пока TextBox не потеряет фокус. Тем не менее, командование будет стрелять немедленно.

Если вы хотите гарантировать, что привязка данных произошла до того, как вы используете значение, вы можете вызвать метод BindingExpression.UpdateSource() на вашем контроле. Попробуйте что-то вроде этого:

var bindTarget = SearchTextBox.GetBindingExpression(TextBox.TextProperty);
bindTarget.UpdateSource();

Чтобы не ссылаться на ваш TextBox непосредственно в ViewModel (как вы должны делать с MVVM), вы можете использовать FocusManager.GetFocusedElement(). Это особенно полезно при работе с кнопками ApplicationBar, так как они, кажется, не получают фокус при использовании.

1 голос
/ 15 ноября 2010

Это работает с TextBox через параметр для RelayCommand. IOW - RelayCommand<TextBox>

    <TextBox Height="72" HorizontalAlignment="Left" Margin="8,136,0,0" Name="txtFilter" Text="" VerticalAlignment="Top" Width="460" >
        <interactivity:Interaction.Triggers>
            <interactivity:EventTrigger EventName="TextChanged">
                <cmd:EventToCommand Command="{Binding SearchedTextChanged}" CommandParameter="{Binding ElementName=txtFilter}" />
            </interactivity:EventTrigger>
        </interactivity:Interaction.Triggers>
    </TextBox>

public RelayCommand<TextBox> SearchedTextChanged { get; set; }

SearchedTextChanged = new RelayCommand<TextBox>(OnSearchedTextChanged);

private void OnSearchedTextChanged(TextBox val)
    {
        if (val != null)
        {
            System.Diagnostics.Debug.WriteLine(val.Text);
        }
    }
0 голосов
/ 03 мая 2010

Какой-то код, который я подал в суд (похож на ваш пример команды):

Объявление команды:

    public RelayCommand<string> TextChanged {get; private set;}

Инициализация команды:

TextChanged = new RelayCommand<string>((s) => MessageBox.Show(s));

Привязка команды:

<TextBox x:Name="SearchTextBox" Margin="10,0" TextWrapping="Wrap" Text="{Binding SearchString, Mode=TwoWay}" FontStyle="Italic" TextChanged="SearchTextBox_TextChanged" >
<i:Interaction.Triggers>
    <i:EventTrigger EventName="TextChanged">
        <GalaSoft_MvvmLight_Command:EventToCommand Command="{Binding TextChanged, Mode=OneWay}" CommandParameter="{Binding Text, ElementName=SearchTextBox}"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

По некоторым причинам в окне сообщений отображается строка с задержкой в ​​один символ.

...