响应类对象层次结构中的对象属性更改 [英] Responding to object property changes within a class object hierarchy

查看:84
本文介绍了响应类对象层次结构中的对象属性更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am developing an application which uses a hierarchical object structure and displays a few key object properties from those objects on the main GUI within a DataGridView. Those values must update when the underlying data changes. I have considered a few options:

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

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

I have been looking at passing the PropertyChanged event from whichever level it occurs up the chain so that it can be handled within the UI. So within a particular class I want to respond to OnPropertyChanged within that class, and within any children, and make any events raised available to the parent class. Thus events would flow up the tree to the top.

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

I understand how to do the two steps individually, I think, with reference to the following:

处理OnPropertyChanged

将子控件的click事件传递给父控件控制

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

However, although I presume the two can be combined, I am not quite sure how to do this. In the UI I have got this:

project.PropertyChanged += new PropertyChangedEventHandler(ProjectPropertyChanged);

private void ProjectPropertyChanged(object sender, PropertyChangedEventArgs e) {
    MessageBox.Show("In main UI. Project property changed!");
}

然后向下一层,我得到了这样的东西:

And then one level down I have got something like this:

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()事件,并将所有事件都公开给父类.

The idea being that each class would pass its own OnPropertyChanged() events to its PropertyChanged() method, and respond to its children's OnPropertyChanged() events, and expose all to the parent class.

如果要这样做,理想情况下,我想保留有关更改哪个属性的知识,以便做出相应的响应.

If doing this, ideally I would like to retain knowledge of which property changed in order to respond accordingly.

最直接的问题是由于参数不同,ProjectPropertyChanged和OnPropertyChanged之间缺乏兼容性.不过,从更根本上来说,我不确定此方法是否可行或最佳.

The most immediate issue is lack of compatibility between ProjectPropertyChanged and OnPropertyChanged due to different parameters. More fundamentally, though, I am not sure whether this method is workable or optimal.

如何最好地做到这一点?

How best to do this?

推荐答案

要回答我自己的问题:

我尝试使用DataTable对中间绑定源执行此操作失败(根据

I tried unsuccessfully to do this with an intermediate binding source, using a DataTable (as per this question.). The problem was that I couldn't create references to the data objects. The DataTable seemed to contain values.

所以我最终使用了一种我更确定但又不太优雅的方法,这是上面我的问题中的选项2.我将标签放置在需要绑定数据值的位置,然后绑定到这些标签.可行.

So I ended up using a method I was more sure about, but is less elegant, which is option 2 in my question above. I position Labels where I need bound data values, and bind to those labels. This works.

通过一些简化,并假装我们的对象是动物,我的解决方案是:

With some simplification, and pretending that our objects are animals, my solution was this:

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".如果初始化,标签将变为绿色,并且将绑定到对象的名称,因此它将从该点开始自动更新.

Then when the objects are created, I call UpdateLabels(). If not initialised, the label will show 'N/A' in red at this point. If initialised, the label will become green and will be bound to the object's name so it will update automatically from that point on.

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

I did much searching and the information I was finding suggested that a DataGridView does not support complex data binding i.e. it is pretty much one class to one DGV, or not at all. I couldn't find an alternative grid-like control which would do it either.

这篇关于响应类对象层次结构中的对象属性更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆