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

时间:2020-01-04 22:15:44

标签: c# oop events

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

  1. 将各个DataGridView单元绑定到相关的对象属性。我知道这是不可能的,并且DGV绑定是全部还是全部。
  2. 动态地将文本框放置在网格单元上并绑定它们,但这看起来很混乱。
  3. 创建一个仅引用相关对象属性的中间列表/数组/集合,然后将该列表用作DataGridView的数据源。
  4. 响应PropertyChanged事件。复杂的是,我有多个班级。顶级对象存在于UI范围内,并且具有一个子对象,该子对象又可以具有其自己的多个子对象,依此类推。 UI可以访问所有对象的属性,但不能访问它们的事件。

我一直在考虑从链上发生的任何级别传递PropertyChanged事件,以便可以在UI中进行处理。因此,在一个特定的类中,我想响应该类中以及所有子类中的OnPropertyChanged,并使引发的所有事件对父类可用。这样事件就会从树上流到顶部。

我认为,我参考以下内容了解如何分别执行两个步骤:

Handling OnPropertyChanged

Pass click event of child control to the parent control

但是,尽管我认为两者可以结合使用,但是我不确定如何做到这一点。在用户界面中,我得到了这个:

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之间缺乏兼容性。不过,从更根本上来说,我不确定此方法是否可行或最佳。

如何最好地做到这一点?

1 个答案:

答案 0 :(得分:0)

要回答我自己的问题:

我尝试使用DataTable(根据this question.)对中间绑定源执行此操作,但未成功。问题是我无法创建对数据对象的引用。 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;
    }
}

然后在创建对象时,我叫UpdateLabels()。如果未初始化,标签此时将以红色显示“ N / A”。如果初始化,标签将变为绿色,并绑定到对象的名称,因此它将从该点开始自动更新。

我做了很多搜索,发现的信息表明DataGridView不支持复杂的数据绑定,即,一个DGV几乎是一个类,或者根本不支持。我也找不到能做到这一点的类似网格的控件。