XAML Binding.UpdateSourceTrigger when a Button.Cli

2019-05-11 04:37发布

I want to set the UpdateSourceTrigger to an event of a control:

<TextBox Text="{Binding Field, UpdateSourceMode=btnOK.Click}">
<Button Name="btnOK">
    <Button.Triggers>
        <Trigger>
            <!-- Update source -->
        </Trigger>
    </Button.Triggers>
</Button>

I thought about two ways:

  1. Set UpdateSourceMode or some other stuff in the binding.
  2. Set an EventTrigger that updates source on button click.

Possible, or I have to do it with code?

3条回答
不美不萌又怎样
2楼-- · 2019-05-11 05:02

I know it's been a while, but I came across the same issue and want to share my solution. Hope it will be helpful for somebody.

public class UpdateSourceBehavior : Behavior<System.Windows.Interactivity.TriggerBase>
{
    internal const string TargetElementPropertyLabel = "TargetElement";


    static UpdateSourceBehavior()
    {
        TargetElementProperty = DependencyProperty.Register
        (
            TargetElementPropertyLabel,
            typeof(FrameworkElement),
            typeof(UpdateSourceBehavior),
            new PropertyMetadata(null)
        );
    }


    public static readonly DependencyProperty TargetElementProperty;


    [Bindable(true)]
    public FrameworkElement TargetElement
    {
        get { return (FrameworkElement)base.GetValue(TargetElementProperty); }
        set { base.SetValue(TargetElementProperty, value); }
    }

    public PropertyPath TargetProperty { get; set; }


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

        this.InitializeMembers();
        base.AssociatedObject.PreviewInvoke += this.AssociatedObject_PreviewInvoke;
    }

    protected override void OnDetaching()
    {
        base.AssociatedObject.PreviewInvoke -= this.AssociatedObject_PreviewInvoke;
        base.OnDetaching();
    }


    private void AssociatedObject_PreviewInvoke(object sender, PreviewInvokeEventArgs e)
    {
        this.m_bindingExpression.UpdateSource();
    }


    private void InitializeMembers()
    {
        if (this.TargetElement != null)
        {
            var targetType = this.TargetElement.GetType();
            var fieldInfo = targetType.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
                                      .FirstOrDefault(fi => fi.Name == this.TargetProperty.Path + "Property");

            if (fieldInfo != null)
                this.m_bindingExpression = this.TargetElement.GetBindingExpression((DependencyProperty)fieldInfo.GetValue(null));
            else
                throw new ArgumentException(string.Format("{0} doesn't contain a DependencyProperty named {1}.", targetType, this.TargetProperty.Path));
        }
        else
            throw new InvalidOperationException("TargetElement must be assigned to in order to resolve the TargetProperty.");
    }


    private BindingExpression m_bindingExpression;
}
查看更多
Bombasti
3楼-- · 2019-05-11 05:15

Here is my solution:

XAML:

<StackPanel>
  <i:Interaction.Triggers>
    <i:EventTrigger SourceName="submit" EventName="Click">
      <behaviours:TextBoxUpdateSourceAction TargetName="searchBox"></behaviours:TextBoxUpdateSourceAction>
    </i:EventTrigger>
  </i:Interaction.Triggers>
  <TextBox x:Name="searchBox">
    <TextBox.Text>
      <Binding Path="SomeProperty" UpdateSourceTrigger="Explicit" NotifyOnValidationError="True">
        <Binding.ValidationRules>
          <DataErrorValidationRule ValidatesOnTargetUpdated="False"/>
        </Binding.ValidationRules>
      </Binding>
    </TextBox.Text>
  </TextBox>
  <Button x:Name="submit"></Button>
</StackPanel>

Behaviour definition (inherited from TargetedTriggerAction):

public class TextBoxUpdateSourceAction : TargetedTriggerAction<TextBox>
{
    protected override void Invoke(object parameter)
    {
        BindingExpression be = Target.GetBindingExpression(TextBox.TextProperty);
        be.UpdateSource();
    }
}

Please note that it's important to attach TextBoxUpdateSourceAction to parent container (StackPanel in example code).

查看更多
贼婆χ
4楼-- · 2019-05-11 05:17

You'll have to use code. Specifically:

  1. Set UpdateSourceTrigger=Explicit on the TextBox.
  2. Call UpdateSource when the user clicks the Button.

However, you can put the code in the code behind or in an attached behavior.

查看更多
登录 后发表回答