WPF TextBox EventTrigger sequence of events

拜拜、爱过 提交于 2021-02-07 21:45:54

问题


I have a dynamic WPF input form, whereby a list of input text boxes is displayed based on the contents of a collection of data. The text of each text box is bound to a Value field in the data, when any of these fields changes I am using firing a Command which then executes a calculation in a script (also dynamically provided) using the values of the input field.

My question is how I can get the Command to execute after the field value has changed. At the moment I am firing the Command based on an event trigger using the TextChanged property.

The issue is that the TextChanged property seems to fire before the value of the bound property is set. This means that although the command fires and executes the script, the field which is currently being editing will have the 'old' data in it still because of the sequence of events.

The relevant bit of XAML code I am using is:

<Label Visibility="{Binding HasInputFieldsSection, Converter={StaticResource visibilityConverter}}">Input parameters</Label>

<ItemsControl Visibility="{Binding HasInputFieldsSection, Converter={StaticResource visibilityConverter}}"
              ItemsSource="{Binding Path=SelectedQualificationType.QualificationTypeInputFields.QualificationTypeFields}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <Label Content="{Binding Label}" Visibility="{Binding Label, Converter={StaticResource stringVisibilityConverter}}"/>

                <TextBox Text="{Binding Value, UpdateSourceTrigger=PropertyChanged, Delay=250}">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="TextChanged">
                            <cmd:EventToCommand Command="{Binding DataContext.ExecuteExpressionsCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}}}" />
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </TextBox>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

I was hoping there would be a different event I could trigger the command on but after looking through the documentation for a WPF textbox and trying some alternative none of them seem appropriate.

I could change the binding to be based on LostFocus rather than PropertyChanged but for a better user experience I would rather not. Likewise I could remove the delay on the input TextBox binding but ideally I would want this delay to remain, again for user experience.

So in short the current sequence seems to be:

  1. user types something
  2. text changed gets fired
  3. command is fired
  4. bound field gets updated

but I need it to be more like:

  1. user types something
  2. text changed gets fired
  3. bound field gets updated
  4. command is fired

Is there a better event to fire off or way to accomplish what I am trying to do?


回答1:


You can use the Binding.SourceUpdated Attached Event instead of the TextChanged event.

Set the Binding.NotifyOnSourceUpdated property on your Binding to true and listen to the attached event:

<TextBox Text="{Binding Value, NotifyOnSourceUpdated=True}">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SourceUpdated">
            <!--...-->
        </i:EventTrigger>
    </i:Interaction.Triggers>
</TextBox>

With this approach, your command will be triggered just after the Binding data transfer back to the model layer.




回答2:


My question is how I can get the Command to execute after the field value has changed. At the moment I am firing the Command based on an event trigger using the TextChanged property.

Fire the command in the view model when the Value property of any item in the QualificationTypeFields collection is set.

You simply could simply hook up an event handler for the PropertyChanged event for each item in the collection like this:

foreach(var item in SelectedQualificationType.QualificationTypeInputFields.QualificationTypeFields)
{
    item.PropertyChanged += item_PropertyChanged;   
}

...

private void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if (e.PropertyName == "Value")
    {
        ExecuteExpressionsCommand.Execute(null);
    }
}

If QualificationTypeFields is an ObservableCollection<T> you should also remember to add the event handler to each new item that you add to the collection. You could easily do this by handling the CollectionChanged event:

private void QualificationTypeFields_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    if (e.NewItems != null)
    {
        foreach (object item in e.NewItems)
        {
            (item as INotifyPropertyChanged).PropertyChanged
                += new PropertyChangedEventHandler(item_PropertyChanged);
        }
    }

    if (e.OldItems != null)
    {
        foreach (object item in e.OldItems)
        {
            (item as INotifyPropertyChanged).PropertyChanged
                -= new PropertyChangedEventHandler(item_PropertyChanged);
        }
    }
}


来源:https://stackoverflow.com/questions/44238222/wpf-textbox-eventtrigger-sequence-of-events

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