问题
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:
- Set UpdateSourceMode or some other stuff in the binding.
- Set an EventTrigger that updates source on button click.
Possible, or I have to do it with code?
回答1:
You'll have to use code. Specifically:
- Set
UpdateSourceTrigger=Explicit
on theTextBox
. - Call UpdateSource when the user clicks the
Button
.
However, you can put the code in the code behind or in an attached behavior.
回答2:
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;
}
回答3:
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).
来源:https://stackoverflow.com/questions/1317706/xaml-binding-updatesourcetrigger-when-a-button-click-is-fired