Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/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#_Oop_Events - Fatal编程技术网

C# 响应类对象层次结构中的对象属性更改

C# 响应类对象层次结构中的对象属性更改,c#,oop,events,C#,Oop,Events,我正在开发一个应用程序,它使用分层对象结构,并在DataGridView的主GUI上显示这些对象的一些关键对象属性。这些值必须在基础数据更改时更新。我考虑过几个选择: 将各个DataGridView单元格绑定到相关的对象属性。我知道这是不可能的,DGV绑定要么全有要么全无 动态地将文本框放置在网格单元上并绑定它们,但这看起来很混乱 创建一个只引用相关对象属性的中间列表/数组/集合,然后将该列表用作DataGridView的数据源 响应PropertyChanged事件。复杂的是我上了多节课。顶层

我正在开发一个应用程序,它使用分层对象结构,并在DataGridView的主GUI上显示这些对象的一些关键对象属性。这些值必须在基础数据更改时更新。我考虑过几个选择:

  • 将各个DataGridView单元格绑定到相关的对象属性。我知道这是不可能的,DGV绑定要么全有要么全无
  • 动态地将文本框放置在网格单元上并绑定它们,但这看起来很混乱
  • 创建一个只引用相关对象属性的中间列表/数组/集合,然后将该列表用作DataGridView的数据源
  • 响应PropertyChanged事件。复杂的是我上了多节课。顶层对象存在于UI范围内,并且有一个子对象,而子对象又可能有自己的多个子对象,以此类推。UI可以访问所有对象的属性,但不能访问它们的事件
  • 我一直在考虑将PropertyChanged事件从链上发生的任何级别传递,以便可以在UI中处理它。因此,在一个特定的类中,我希望响应该类中以及任何子类中的OnPropertyChanged,并使父类可以使用任何引发的事件。因此,事件将沿着树向上流动到顶部

    我理解如何根据以下内容分别完成这两个步骤:

    然而,尽管我认为两者可以结合,但我不太确定如何做到这一点。在UI中,我得到了以下信息:

    project.PropertyChanged += new PropertyChangedEventHandler(ProjectPropertyChanged);
    
    private void ProjectPropertyChanged(object sender, PropertyChangedEventArgs e) {
        MessageBox.Show("In main UI. Project property changed!");
    }
    
    再往下一层,我得到了这样的东西:

    public class Project : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        public Project() {
            childObject.PropertyChanged += new PropertyChangedEventHandler(ProjectPropertyChanged);
        }
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
            ProjectPropertyChanged(sender, e); // this doesn't work due to different parameters
        }
        private void PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            // Event available to parent class
        }
    }
    
    其思想是,每个类都将自己的OnPropertyChanged()事件传递给其PropertyChanged()方法,并响应其子类的OnPropertyChanged()事件,并将所有事件公开给父类

    如果这样做,理想情况下,我希望保留哪些属性发生了变化的知识,以便做出相应的响应

    最直接的问题是由于参数不同,ProjectPropertyChanged和OnPropertyChanged之间缺乏兼容性。但更根本的是,我不确定这种方法是可行的还是最佳的


    如何最好地做到这一点?

    回答我自己的问题:

    我尝试使用一个中间绑定源,使用一个DataTable(如所示),但没有成功。问题是我无法创建对数据对象的引用。DataTable似乎包含值

    所以我最终使用了一种我更确定但不那么优雅的方法,这就是我上面问题中的选项2。我将标签放置在需要绑定数据值的位置,并绑定到这些标签。这很有效

    经过一些简化,并假设我们的物体是动物,我的解决方案是:

    Label[,] dashboardLabels = new Label[3,14];
    
    private void Form1_Shown(object sender, EventArgs e)
    {
      CreateLabels(); // create and position labels (no binding yet)
    }
    
    public void CreateLabels(int cols = 3, int rows = 14)
    {
    
        for (int col = 0; col < cols; col++)
        {
            for (int row = 0; row < rows; row++)
            {
                // Create label...
                Label l = new Label();
                l.Text = "N/A";
                l.ForeColor = Color.Red
                dashboardLabels[col, row] = l;
                this.Controls.Add(l);
    
                // Position label over DGV cell...
                Point dgvCell = dataGridView1.GetCellDisplayRectangle(col + 2, rowNumbersLabel[row], false).Location;
                Point dgvGrid = dataGridView1.Location;
                l.Left = dgvGrid.X + dgvCell.X;
                l.Top = dgvGrid.Y + dgvCell.Y;
    
            }
        }
    }
    private void UpdateLabels(List<Dog> dogs)
    {
        for (int i = 0; i < dogs; i++)
        {
            if (!dashboardLabels[i, 0].Visible) dashboardLabels[i, 0].Visible = true;
            if (dogs[i].IsSetUp) BindLabel(dashboardLabels[i, 0], dogs[i],"Name");
        }
    }
    private void BindLabel(Label l, Dog dog, string observation)
        {
            Binding b = new Binding("Text", dog, observation);
            l.DataBindings.Add(b);
            l.ForeColor = Color.Green;
        }
    }
    
    Label[,]仪表板标签=新标签[3,14];
    显示私有void Form1_(对象发送方,事件参数e)
    {
    CreateLabels();//创建和定位标签(尚未绑定)
    }
    公共void CreateLabels(int cols=3,int rows=14)
    {
    for(int col=0;col
    然后在创建对象时,我调用
    UpdateLabels()
    。如果未初始化,此时标签将以红色显示“不适用”。如果初始化,标签将变为绿色,并将绑定到对象的名称,以便从该点起自动更新


    我做了很多搜索,发现的信息表明DataGridView不支持复杂的数据绑定,即它几乎是一个类到一个DGV,或者根本不支持。我找不到替代的类似网格的控件来执行此操作。

    子对象是否修改主对象的属性?--DataGridView不能显示嵌套的对象值,所有对象都必须位于同一层次结构级别。将对象绑定到BindingSource(此类处理属性更改通知)并将DGV绑定到BindingSource。或者使用DataTable来表示数据:此类本身会引发通知更改(您可以将DataTable绑定到BindingSource以获得更多导航选项)。正如我所说的,我不认为数据绑定到DGV是显而易见的解决方案,因为其中的属性属于多个对象。您是否建议我使用包含不同对象属性的中间列表并将其用作数据源?DGV中的数据只能以列和行的形式显示,因此没有嵌套对象,您必须展平层次结构。你计划怎么做,你想在DGV中展示什么,你没有说。无论如何都需要一个表示层。如果表示层引发通知更改,UI要求得到满足,BindingSource可以处理类对象和UI(在本例中是DGV,但处理数据绑定的任何其他控件)之间的事务