【问题标题】:Bind to the reference, not the object绑定到引用,而不是对象
【发布时间】:2017-09-28 22:13:56
【问题描述】:

假设您有一个带有属性的对象,您将控件绑定到该对象。像这样:

MyClass MyObject = new MyClass();
MyObject.MyProperty = "Hello StackOverflow!";
MyTextBox.DataBindings.Add("Text", MyObject, nameOf(MyObject.MyProperty);

然后您将MyObject 更改为MyClass 的新实例,如下所示:

MyObject = new MyClass();
MyObject.MyProperty = "I've made a new instance of my class...";

然后MyTextBox 仍将绑定到MyClass 的实例,其中MyProperty 设置为“Hello StackOverflow!”。无论如何设置数据绑定以使其与类的新实例保持一致?我知道我可以简单地再次设置 DataBindings,但有时这并不像本例中那么简单。

【问题讨论】:

  • 没有。您正在绑定一个对象而不是变量名。
  • 是的,绑定到视图模型的属性。使您的视图模型成为绑定的源并为其提供属性的路径。确保您的视图模型正确执行 INotifyPropertyChanged。

标签: c# winforms data-binding


【解决方案1】:

数据绑定支持源属性的属性路径。因此,只要您将 MyObject 变量放在另一个可用于数据绑定的对象中并将其公开为属性,您就可以指定引用包含该值的属性的属性名称,然后是点,然后是您的属性真的想要。

例如,假设您有一个带有 MyClass 属性值的 Model 类:

class Model : INotifyPropertyChanged
{
    private MyClass _myClass;
    public MyClass MyClass
    {
        get { return _myClass; }
        set { _UpdateField(ref _myClass, value); }
    }
}

(以上假设有一个辅助方法_UpdateField() 处理更新字段并在必要时引发PropertyChanged 事件。)

然后你可以像这样定义你的绑定:

Model model = new Model(); // initialized somewhere you can access this reference later
model.MyClass.MyProperty = "Hello StackOverflow!";
MyTextBox.DataBindings.Add("Text", model,
    nameof(Model.MyClass) + "." +  nameof(MyClass.MyProperty);

然后,当您想要更新 MyClass 对象时,您可以更改 model.MyClass 属性值。绑定会相应地更新目标值。


这是一个完整的示例(除了 *.Designer.cs 文件……只需确保表单上有 LabelButton 及其默认名称,并将 Button.Click 事件订阅到下面代码中的处理程序):

public partial class Form1 : Form
{
    private readonly C2[] _rgc2 =
    {
        new C2 { Text = "First C2" },
        new C2 { Text = "Second C2" },
    };

    private readonly C1 _c1 = new C1();

    private bool _toggle = false;

    public Form1()
    {
        InitializeComponent();
        label1.DataBindings.Add("Text", _c1, nameof(C1.C2) + "." + nameof(C2.Text));
        _UpdateC2();
    }

    private void _UpdateC2()
    {
        _c1.C2 = _rgc2[_toggle ? 1 : 0];
    }

    private void button1_Click(object sender, EventArgs e)
    {
        _toggle = !_toggle;
        _UpdateC2();
    }
}

class C1 : NotifyPropertyChangedBase
{
    private C2 _c2;

    public C2 C2
    {
        get { return _c2; }
        set { _UpdateField(ref _c2, value); }
    }
}

class C2 : NotifyPropertyChangedBase
{
    private string _text;

    public string Text
    {
        get { return _text; }
        set { _UpdateField(ref _text, value); }
    }
}

class NotifyPropertyChangedBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void _UpdateField<T>(ref T field, T newValue,
        Action<T> onChangedCallback = null,
        [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, newValue))
        {
            return;
        }

        T oldValue = field;

        field = newValue;
        onChangedCallback?.Invoke(oldValue);
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

【讨论】:

    猜你喜欢
    • 2012-07-08
    • 2019-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-23
    • 2010-10-05
    相关资源
    最近更新 更多