Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
c#绑定到嵌套对象上的字段_C#_.net_Data Binding_.net 4.0_2 Way Object Databinding - Fatal编程技术网

c#绑定到嵌套对象上的字段

c#绑定到嵌套对象上的字段,c#,.net,data-binding,.net-4.0,2-way-object-databinding,C#,.net,Data Binding,.net 4.0,2 Way Object Databinding,对于如何使用数据绑定将WinForms应用程序中的控件绑定到嵌套对象,我似乎找不到一个简单、具体的解释。例如: class MyObject : INotifyPropertyChanged { private string _Name; public string Name { get { return _Name; } set { _Name = value;

对于如何使用数据绑定将WinForms应用程序中的控件绑定到嵌套对象,我似乎找不到一个简单、具体的解释。例如:

class MyObject : INotifyPropertyChanged
{
    private string _Name;
    public string Name 
    { 
        get { return _Name; } 
        set 
        { 
            _Name = value; 
            OnPropertyChanged("Name"); 
        }    
    }

    private MyInner _Inner;
    public MyInner Inner 
    { 
       get { return _Inner; } 
       set 
       { 
           _Inner = value; 
           OnPropertyChanged("Inner"); 
       } 
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

class MyInner : INotifyPropertyChanged
{
    private string _SomeValue;
    public string SomeValue 
    {
        get { return _SomeValue; } 
        set 
        { 
            _SomeValue = value; 
            OnPropertyChanged("SomeValue"); 
        } 
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
现在想象一个只有两个文本框的表单,第一个用于Name,第二个用于Inner.SomeValue。我可以很容易地获得绑定来对抗Name,但是Inner.SomeValue是脆弱的。如果我填充对象,然后设置绑定,它会在文本框中显示Inner.SomeValue,但我无法编辑它。如果我从一个新对象开始而没有初始化Inner,那么我似乎无法将数据保存在Inner.SomeValue中

我检查了整个MSDN、整个StackOverflow,以及数十个不同关键字的搜索。每个人都想谈论绑定到数据库或数据网格,大多数示例都是用XAML编写的


更新:我试过Marc的全套测试工具,部分成功。如果我点击“全部更改!”按钮,我似乎能够写回内部对象。但是,从MyObject.Inner null开始,它不知道如何创建内部对象。我想现在,我可以通过确保我的内部引用总是设置为有效对象来解决这个问题。尽管如此,我还是忍不住觉得自己错过了什么:)

嗯,这是一个很好的问题;我已经做了大量的数据绑定到对象,我发誓你所做的应该是有效的;但实际上,它很不愿意注意到内部对象的变化。我通过以下方式使其正常工作:

var outer = new BindingSource { DataSource = myObject };
var inner = new BindingSource(outer, "Inner");
txtName.DataBindings.Add("Text", outer, "Name");
txtSomeValue.DataBindings.Add("Text", inner, "SomeValue");
虽然不理想,但它确实有效。顺便提一下您可能会发现以下实用程序方法很有用:

public static class EventUtils {
    public static void SafeInvoke(this EventHandler handler, object sender) {
        if(handler != null) handler(sender, EventArgs.Empty);
    }
    public static void SafeInvoke(this PropertyChangedEventHandler handler,
               object sender, string propertyName) {
        if(handler != null) handler(sender,
               new PropertyChangedEventArgs(propertyName));
    }
}
然后你可以有:

class MyObject : INotifyPropertyChanged
{
    private string _Name;
    public string Name { get { return _Name; } set {
        _Name = value; PropertyChanged.SafeInvoke(this,"Name"); } }
    private MyInner _Inner;
    public MyInner Inner { get { return _Inner; } set {
        _Inner = value; PropertyChanged.SafeInvoke(this,"Inner"); } }
    public event PropertyChangedEventHandler PropertyChanged;
}

class MyInner : INotifyPropertyChanged
{
    private string _SomeValue;
    public string SomeValue { get { return _SomeValue; } set {
        _SomeValue = value; PropertyChanged.SafeInvoke(this, "SomeValue"); } }
    public event PropertyChangedEventHandler PropertyChanged;
}
在交易中,它修复了零异常(竞争条件)的可能性(很小)


全套试验台,以消除扭结(来自评论):


嘿,谢谢你,马克。我将在稍后添加SafeInvoke代码,但希望先让数据绑定工作起来。不幸的是,这似乎没有什么不同。关于我可能做错了什么,还有其他想法吗?@Matt-我将把我的测试设备添加到我的答案中-你能看看这是否有效吗?这可能是一个.NET版本的问题…谢谢Marc。我用你们试验台的最新结果更新了这个问题。似乎只要我从一个内在的对象开始,事情就会发生。如果Inner为null,则无法从控件获取任何要粘贴的内容。不管怎样,我把问题标记为已回答,非常感谢您的帮助!
using System;
using System.ComponentModel;
using System.Windows.Forms;
public static class EventUtils {
    public static void SafeInvoke(this PropertyChangedEventHandler handler, object sender, string propertyName) {
        if(handler != null) handler(sender, new PropertyChangedEventArgs(propertyName));
    }
}
class MyObject : INotifyPropertyChanged
{
    private string _Name;
    public string Name { get { return _Name; } set { _Name = value; PropertyChanged.SafeInvoke(this,"Name"); } }
    private MyInner _Inner;
    public MyInner Inner { get { return _Inner; } set { _Inner = value; PropertyChanged.SafeInvoke(this,"Inner"); } }
    public event PropertyChangedEventHandler PropertyChanged;
}

class MyInner : INotifyPropertyChanged
{
    private string _SomeValue;
    public string SomeValue { get { return _SomeValue; } set { _SomeValue = value; PropertyChanged.SafeInvoke(this, "SomeValue"); } }
    public event PropertyChangedEventHandler PropertyChanged;
}
static class Program
{
    [STAThread]
    public static void Main() {
        var myObject = new MyObject();
        myObject.Name = "old name";
        // optionally start with a default
        //myObject.Inner = new MyInner();
        //myObject.Inner.SomeValue = "old inner value";

        Application.EnableVisualStyles();
        using (Form form = new Form())
        using (TextBox txtName = new TextBox())
        using (TextBox txtSomeValue = new TextBox())
        using (Button btnInit = new Button())
        {
            var outer = new BindingSource { DataSource = myObject };
            var inner = new BindingSource(outer, "Inner");
            txtName.DataBindings.Add("Text", outer, "Name");
            txtSomeValue.DataBindings.Add("Text", inner, "SomeValue");
            btnInit.Text = "all change!";
            btnInit.Click += delegate
            {
                myObject.Name = "new name";
                var newInner = new MyInner();
                newInner.SomeValue = "new inner value";
                myObject.Inner = newInner;
            };
            txtName.Dock = txtSomeValue.Dock = btnInit.Dock = DockStyle.Top;
            form.Controls.AddRange(new Control[] { btnInit, txtSomeValue, txtName });
            Application.Run(form);
        }
    }

}