如何将 UpdateSourceTrigger 的值移交给 UserControl 或在运行时更新?

Posted

技术标签:

【中文标题】如何将 UpdateSourceTrigger 的值移交给 UserControl 或在运行时更新?【英文标题】:How to hand over the value of UpdateSourceTrigger to UserControl or update it at runtime? 【发布时间】:2019-08-10 00:03:05 【问题描述】:

我遇到了 UpdateSourceTrigger 属性的问题。我有一个名为 LabelWithTextBox 的用户控件,其中未定义 UpdateSourceTrigger(文本属性)(因此具有默认值)。由于性能原因,这应该保持这种状态(当焦点离开文本框时,文本应该更新)。

但是现在我有一个应该使用 UserControl 并且更新应该在用户输入时发生的情况,因此我想将 UpdateSourceTrigger 设置为 PropertyChanged。

理想情况下,如果可以继承 UpdateSourceTrigger 属性,则最好的解决方案是。用户在他的视图中使用 UserControl 并定义 UpdateSourceTrigger = PropertyChanged,此信息被移交给我的 UserControl,一切都按预期工作。有谁知道我如何存档?

我还有什么其他选择?如何在运行时更改 UpdateSourceTrigger 属性?

这里是相关的 UserControl(代码隐藏)代码:

public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
    "Text",
    typeof(string),
    typeof(LabelWithTextBox),
    new FrameworkPropertyMetadata(string.Empty, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

public string Text

    get  return (string)this.GetValue(TextProperty); 
    set  this.SetValue(TextProperty, value); 

这里是 UserControl (Xaml) 代码:

<Grid Grid.Column="1">
            <telerik:RadWatermarkTextBox TextChanged="TextBoxBase_OnTextChanged"
                                         Name="TextBox"
                                         Text="Binding Text, Mode=TwoWay, ElementName=userControl"
                                         WatermarkContent="Binding Placeholder, Mode=TwoWay, ElementName=userControl"
                                         TextWrapping="Binding TextWrap, Mode=TwoWay, ElementName=userControl"
                                         AcceptsReturn="Binding AcceptsReturn, Mode=TwoWay, ElementName=userControl"
                                         VerticalScrollBarVisibility="Binding VerticalScrollBarVisibility, Mode=TwoWay, ElementName=userControl"
                                         MinLines="Binding MinLines, Mode=TwoWay, ElementName=userControl"
                                         MaxLines="Binding MaxLines, Mode=TwoWay, ElementName=userControl"
                                         IsReadOnly="Binding IsReadOnly, ElementName=userControl"/>
    ....

如果将 UpdateSourceTrigger = PropertyChanged 添加到 Text,一切都会按预期工作。但我不想那样。

这里举例说明某人如何在他的视图中使用 UserControl。我正在寻找一种将 UpdateSourceTrigger 的值移交给我的 UserControl 的方法,但是如何?

<controls:LabelWithTextBox
                    Grid.Row="1"
                    Margin="0,5,0,0"
                    Label="Excel Blattname:"
                    SharedSizeGroup="LabelsX"
                    Text="Binding SheetName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged" />

【问题讨论】:

你可以在你的控件中有一个DependencyProperty,然后使用后面代码中的值来设置TextBox。请记住,使用 Binding 时的 DependencyProperty 不会触发支持 CLR 属性。 @XAMlMAX 你能给我一个小例子吗?我现在有了依赖属性,我现在应该如何相应地更改 UpdateSourceTrigger ? 你为什么在你的用户控件中创建了TextDependencyProperty?如果它是“源”,那么它可以是通常的属性。你想达到什么目标? @Rekshino 显然是为了让它可绑定。在 UserControls 中拥有依赖属性是标准方法。 @Devid 你想要在这里做的事情很难通过 UserControl 中的“中间”依赖属性来实现。您可以改为从 RadWatermarkTextBox 派生,或声明 BindingBase 类型的 TextBinding 属性(这将是常规 CLR 属性而不是依赖项属性)。 Binding 将由 SetBinding(RadWatermarkTextBox.TextProperty, TextBinding) 传递给 RadWatermarkTextBox。 【参考方案1】:

UpdateSourceTrigger 是 Binding 的属性,而不是控件的属性。为了将它传递给控件,​​您可以将整个 Binding 传递给适当的属性。

您的控件可以公开一个TextBinding 属性:

public partial class LabelWithTextBox : UserControl

    public LabelWithTextBox()
    
        InitializeComponent();
    

    private BindingBase textBinding;

    public BindingBase TextBinding
    
        get  return textBinding; 
        set
        
            textBinding = value;
            TextBox.SetBinding(RadWatermarkTextBox.TextProperty, textBinding);
        
    

您将为其分配一个类似的绑定

<controls:LabelWithTextBox
  TextBinding="Binding SheetName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged"/>

然后直接传递给 RadWatermarkTextBox。

缺点当然是只能分配Binding,不能分配别的。


但是,您也可以使用 Text 依赖属性并在加载控件时检查其值。如果值是一个绑定,你可以这样使用它:

public override void OnApplyTemplate()

    base.OnApplyTemplate();

    var binding = GetBindingExpression(TextProperty)?.ParentBinding;

    if (binding != null)
    
        TextBox.SetBinding(RadWatermarkTextBox.TextProperty, binding);
    

【讨论】:

【参考方案2】:

我不太清楚你想达到什么目的

您可以在代码中将绑定设置为RadWatermarkTextBox,而不是在 XAML 中。

编辑:

现在我知道你想要什么了 :)

将其添加到您的用户控件中:

public bool UpdateOnPropChanged

    get
    
        return _updateOnPropChanged;
    
    set
    
        _updateOnPropChanged = value;
        this.TextBox.SetBinding(TextBox.TextProperty, new Binding("Text")  RelativeSource=new RelativeSource(RelativeSourceMode.FindAncestor)  AncestorType=typeof(LabelWithTextBox) , UpdateSourceTrigger = _updateOnPropChanged ? UpdateSourceTrigger.PropertyChanged : UpdateSourceTrigger.LostFocus );
    

private bool _updateOnPropChanged;

你可以这样使用它:

<controls:LabelWithTextBox UpdateOnPropChanged="false"/>

【讨论】:

当用户在 TextBox 中键入文本时,绑定应该立即更新,而不是在焦点丢失之后(这是默认情况下发生的)。这就是为什么我需要将 UpdateSourceTrigger 属性设置为 PropertyChanged。现在我创建了一个可重用的 UserControl,默认情况下 UpdateSourceTrigger 设置为 Default,这应该保持这样(性能原因)。我正在寻找一种按需更改此属性(UpdateSourceTrigger)的方法。没有TextChanged。 LostFocus 不适合举办此活动。 @Devid 用户是否在用户控件之外键入一些文本框并且您想要将数据传递给用户控件,或者用户是否在用户控件中键入并且您想要通过依赖属性? @Devid RadWatermarkTextBox好像是从TextBox派生的,所以肯定有TextChanged事件。 您必须想象用户出于某种原因在他们的视图中使用我的 UserControl。用户 A 想要在键入时立即更新,而用户 B 想要仅在失去焦点时更新。两者都使用相同的 UserControl(在我的示例 LabelWithTextBox 中,它在左侧提供一个标签,在右侧提供一个 TextBox)。 经过进一步检查,有一个 TextChanged 事件。但我不知道如何解决我的问题

以上是关于如何将 UpdateSourceTrigger 的值移交给 UserControl 或在运行时更新?的主要内容,如果未能解决你的问题,请参考以下文章

可以将UpdateSourceTrigger绑定到DependencyProperty吗?

Caliburn Micro:如何设置绑定 UpdateSourceTrigger?

WPF + DatePicker + UpdateSourceTrigger = 显式

自定义 UpdateSourceTrigger 延迟?

WPF UpdateSourceTrigger属性

背水一战 Windows 10 (20) - 绑定: DataContextChanged, UpdateSourceTrigger, 对绑定的数据做自定义转换