【问题标题】:Can the binding source be updated manually from within the target control in WPF是否可以从 WPF 中的目标控件中手动更新绑定源
【发布时间】:2011-05-21 03:10:40
【问题描述】:

我有一个场景,我将提供一个简单的例子来帮助说明。

假设我正在编写一个类似 CheckBox 的自定义控件,该控件能够在特定事件触发时被选中。该事件可以是诸如 MouseEnter 之类的任何事件,或者甚至可能是其他一些非 UI 事件,例如当网络连接断开时。关键是在某些时候我需要手动设置绑定源的值。

我的假设是这种类型的功能必须是可能的,以便像 TextBox 这样的控件能够工作,因为它们可以以允许 Text 属性根据键盘输入的内容更新为值但无需清除的方式进行操作我存在于 Text 属性上的任何绑定。所以我试图找到实现这一目标的基本方法。

尝试#1

如下所示设置绑定的目标属性(例如 IsChecked)将导致绑定被清除。所以这个选项不起作用(更正!见下面的my answer)。

this.IsChecked = true;

或者:

this.SetValue(CheckBox.IsCheckedProperty, true);

尝试#2

BindingBase 类有一个名为 ProvideValue 的属性,如 MSDN documentation 中所述,“返回一个对象,该对象应在应用此绑定和扩展的属性上设置。”这听起来很有希望,所以我尝试通过以下两种方式实现我自己的IServiceProvider

实施 A:

public class CheckProvider : IServiceProvider
{
    public object Value { get; set; }

    public object GetService(Type serviceType)
    {
        return Value;
    }
}

实施 B:

public class CheckProvider : IServiceProvider
{
    public object Value { get; set; }

    public object GetService(Type serviceType)
    {
        return new ObjectProvider() { TargetObject = new TempDependencyObject() { IsSelected = Value }, TargetProperty = TempDependencyObject.IsSelectedProperty };
    }

    public class TempDependencyObject : DependencyObject
    {
        public object IsSelected
        {
            get { return (object)GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); }
        }

        public static readonly DependencyProperty IsSelectedProperty =
            DependencyProperty.Register("IsSelected", typeof(object), typeof(TempDependencyObject));
    }

    public class ObjectProvider : System.Windows.Markup.IProvideValueTarget
    {

        public object TargetObject { get; set; }

        public object TargetProperty { get; set; }
    }
}

这就是我尝试使用这些类手动更新绑定源的方式。

myControl.DataContext = obj;
myBinding.ProvideValue(new CheckProvider() { Value = true });

到目前为止,我还没有运气,所以如果有人能提供一些指点,我将不胜感激。

【问题讨论】:

    标签: data-binding binding dependency-properties


    【解决方案1】:

    几件事,你说...

    TextBox 可以工作,因为它们可以操作 以允许 Text 属性的方式 根据什么更新为值 键盘正在打字但没有 清除我存在的任何绑定 文本属性

    这是TextBox 相对于UpdateSourceTrigger 的行为方式。默认设置为LostFocus。一旦LostFocus 发生,实际值就会被推送到绑定到控件的对象上。如果将其设置为PropertyChanged,它将在每次击键后发生。

    要获得所需的行为,您可以在 XAML 中将 UpdatesourceTrigger 属性设置为 Explicit...

    <TextBox Name="MyTextBox"
             Text="{Binding Path=FirstName, UpdateSourceTrigger=Explicit}" />
    

    然后在您的代码后面的任何时候您都可以显式更新源...

    BindingExpression be = MyTextBox.GetBindingExpression(TextBox.TextProperty);
    be.UpdateSource();
    

    当某些随机事件发生或发生其他一些事件系列时,这将与您更新源的需求相关。

    如果您尝试设置控件外部的可绑定属性的值,并希望绑定到该属性的属性不会更改;开箱即用是不可能的。您需要派生自己的控制权并在内部对其进行管理,公开一个DependencyProperty,它可能采用您想要更新的类型。如果您进入 VS 并输入 propdp,则DependencyProperty 的代码为 sn-p。

    你会得到类似...

        public List<byte> Text
        {
            get { return (List<byte>)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }
    
        // Using a DependencyProperty as the backing store for Text.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TextProperty =
            DependencyProperty.Register("Text", typeof(List<byte>), typeof(RichTextBoxExtended), new UIPropertyMetadata());
    

    Text 是派生自RichTextBox 的此自定义类型的可绑定属性。因此,如果有人有这种类型的实例,他们可以调用属性本身来设置和更改值。执行此操作时,将通知所有使用此属性并可选绑定到它的对象。

    【讨论】:

    • 感谢 Aaron,我确实了解 TextBox 在外部的工作方式,但我感兴趣的是 TextBox 控件如何在内部将键盘输入转换为绑定上设置的值。换句话说,我正在寻找类似于 UpdateSource 方法的方法,该方法采用我想要设置的值的参数,例如 UpdateSource("Some new text")。
    • TextBox 的哪个属性?您是否正在寻找如何添加一个您在内部更新的 DependencyProperty 以允许您永久绑定?用另一条评论更新了答案...
    • 定义我自己的控件其实没问题,但是我还是不太明白如何在不清除绑定到那个DependencyProperty的情况下更新那个mater的绑定源或者目标上的值。也许我只是在某个地方忽略了一种方法。请参阅我的原始帖子,其中我声明“假设我正在编写一个自定义 CheckBox-like 控件”。
    • @jpierson 这就是 DependencyProperty 允许你做的事情。根据您想要的任何内容更新值,但仍可绑定。我将发布一个示例...
    • @jpierson 我重新阅读了有关 CheckBox 的示例,但没有发现问题。有多种方法可以更新源。你一直说更新绑定,但多个项目可以绑定到一个属性;该属性可以通过多种方式在后面的代码中更新。当您声明绑定正在重置时,您正在更改实际属性值,因为它之前正在评估绑定表达式。如果您希望更改该值,请更改基础对象。
    【解决方案2】:

    对我的问题的简短回答是肯定的!在查看 Reflector 中 CheckBox 的代码后,我意识到在该代码中,他们直接设置 IsChecked 以响应 Click 事件,并且它按预期工作。最初,我假设这会清除底层绑定,而是设置依赖属性而不是接缝来做我正在寻找的事情,因为它设置属性的目标值,然后如果绑定使用更新绑定的源TwoWay 或 OneWayToSource 绑定模式。

    所以要清楚下面的两个例子。

    因此,此选项应该可以更新依赖属性,从而更新可能在该属性上设置的绑定源。

    this.IsChecked = true;
    

    或者:

    this.SetValue(CheckBox.IsCheckedProperty, true);
    

    感谢 Aaron 在尝试解决此问题时提供的帮助。

    【讨论】:

    • 啊哈!感谢您发布您的答案。我意识到我的自定义依赖项的默认绑定模式是 OneWay,这就是我尝试设置值(使用 SetValue)导致绑定被删除的原因。我将模式更改为 TwoWay,一切都像宣传的那样工作。谢谢!
    • 我将我的答案标记为解决方案,以回应 Cyborgx37 的评论,即它可能是解决问题的最有用的解决方案。感谢所有帮助讨论这个问题的人。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-13
    • 2014-10-14
    相关资源
    最近更新 更多