可以从WPF中的目标控件中手动更新绑定源

时间:2010-12-06 17:36:51

标签: data-binding binding dependency-properties

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

让我们说我正在编写一个类似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 });

到目前为止,我没有运气,所以如果有人可以提供一些指示,我将非常感激。

2 个答案:

答案 0 :(得分:2)

一些事情,你说过......

  

TextBox可以运行,因为它们可以运行   以允许Text属性的方式   根据什么更新为值   键盘输入但没有   清除我存在的任何绑定   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的代码段。

你会得到类似......

    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。因此,如果某人有这种类型的实例,他们可以调用属性本身来设置和更改该值。执行此操作时,将通知所有使用此属性并且可选地绑定到它的对象。

答案 1 :(得分:1)

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

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

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

this.IsChecked = true;

或者:

this.SetValue(CheckBox.IsCheckedProperty, true);

感谢Aaron在尝试解决这个问题时的帮助。