简体   繁体   English

c# 从孩子通知父属性

[英]c# Notify parent property from child

I have the following classes:我有以下课程:

public class child
{
   public string product { get; set; }
   public decimal amount { get; set; }
   public decimal price { get; set; }
   public decimal total { get; set; }
}

public class parent
{
   public decimal total { get; set; }
   public BindingList<child> childs { get; set; }
}

Now, in a windows form I set the following:现在,在 windows 表单中,我设置以下内容:

var parent_object = new parent();

numericUpDown1.DataBindings.Add("Value", parent_object , "total", true, DataSourceUpdateMode.OnPropertyChanged);
dataGridView1.DataBindings.Add("DataSource", parent_object , "childs", true, DataSourceUpdateMode.OnPropertyChanged);

Finally (and I have no idea how to do), is that the total property of parent changes automatically when:最后(我不知道该怎么做), parent 的总属性在以下情况下会自动更改:

  1. The amount or price of some detail of the dataGridView is changed. dataGridView 的某些细节的数量或价格发生了变化。
  2. A row is added to the dataGridView.一行被添加到 dataGridView。
  3. A row is removed from the dataGridView.从 dataGridView 中删除一行。

Thanks for your help.谢谢你的帮助。

Your code so far looks reasonable except that there are a few missing pieces in terms of getting everything hooked up so I'll offer a few suggestions.到目前为止,您的代码看起来很合理,除了在连接所有内容方面缺少一些部分,因此我将提供一些建议。 The first would be to simplify the data binding for the DataGridView where all you need is dataGridView.DataSource = childs .第一个是简化DataGridView的数据绑定,您需要的只是dataGridView.DataSource = childs If you did nothing else besides initialize it by overriding MainForm.OnLoad you'd already have a decent-looking view (but it would be missing the two-way interactions).如果您除了通过覆盖MainForm.OnLoad来初始化它之外什么都不做,那么您已经有了一个看起来不错的视图(但它会缺少双向交互)。

预赛

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    dataGridView.DataSource = childs;
    // Add one or more child items to autogenerate rows.
    childs.Add(new child
    {
        product = "GEARWRENCH Pinch Off Pliers",
        price = 27.10m,
        amount = 1.0m
    });
    childs.Add(new child
    {
        product = "AXEMAX Bungee Cords",
        price = 25.48m,
        amount = 1.0m
    });
    // Format rows
    foreach (DataGridViewColumn column in dataGridView.Columns)
    {
        switch (column.Name)
        {
            case nameof(child.product):
                column.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
                break;
            default:
                column.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
                column.DefaultCellStyle.Format = "F2";
                break;
        }
    }
}
private readonly BindingList<child> childs = new BindingList<child>();
private readonly parent parent_object = new parent();

Bindable Properties可绑定属性

In order to create a bound property that supports two-way communication, you need a way to detect and notify when the properties change.为了创建支持双向通信的绑定属性,您需要一种方法来检测和通知属性何时发生变化。 For example, to make the total property bindable in the parent class do this:例如,要使parent class 中的total属性可绑定,请执行以下操作:

public class parent : INotifyPropertyChanged
{
    decimal _total = 0;
    public decimal total
    {
        get => _total;
        set
        {
            if (!Equals(_total, value))
            {
                _total = value;
                OnPropertyChanged();
            }
        }
    }
    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    public event PropertyChangedEventHandler PropertyChanged;
}

The data binding shown in your code for numericUpDown will now respond to changes of total . numericUpDown代码中显示的数据绑定现在将响应total的更改。

numericUpDown.DataBindings.Add(
    nameof(numericUpDown.Value),
    parent_object, 
    nameof(parent_object.total), 
    false, 
    DataSourceUpdateMode.OnPropertyChanged);

Responding to Changes Internally内部响应变化

Once you make all of your properties in the child class bindable in the same way by using the example above, consider taking the approach of handling certain changes internally in which case you would suppress the firing of the property change notification.通过使用上面的示例以相同的方式使child class 中的所有属性可绑定后,请考虑采用在内部处理某些更改的方法,在这种情况下,您将禁止触发属性更改通知。

public class child : INotifyPropertyChanged
{
    private void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        switch (propertyName)
        {
            case nameof(price):
            case nameof(amount):
                // Perform an internal calculation.
                recalcTotal();
                break;
            default:
                // Notify subscribers of important changes like product and total.
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
                break;
        }
    }
    private void recalcTotal()
    {
        total = price * amount;
    }
    ...
}

Connecting the total property in the parent class.连接parent class 中的total属性。

The only thing missing now is having a way to tell the parent_object that a new global total for all the rows is needed.现在唯一缺少的是有一种方法可以告诉parent_object所有行都需要一个新的全局总计。 The good news is that the bindings are already in place from the previous steps.好消息是绑定已经在前面的步骤中就位。 To detect any change to the DGV whether a new row is added or aa total is edited, subscribe to the ListChanged event of the childs collection by making this the first line in the OnLoad (before adding any items).要检测对childs任何更改,无论是添加新行还是编辑总计,请订阅子集合的ListChanged事件,方法是将其设为OnLoad中的第一行(在添加任何项目之前)。

childs.ListChanged += parent_object.onChildrenChanged;

This is a method that will need to be implemented in the parent_object class.这是需要在parent_object class 中实现的方法。 Something like this:像这样的东西:

internal void onChildrenChanged(object sender, ListChangedEventArgs e)
{
    var tmpTotal = 0m;
    foreach (var child in (IList<child>)sender)
    {
        tmpTotal += child.total;
    }
    total = tmpTotal;
}

READY TO TEST准备测试

If you implement these steps, you'll have a fully-functional linked view where you can add, remove, and modify child records.如果您实施这些步骤,您将拥有一个功能齐全的链接视图,您可以在其中添加、删除和修改child记录。

功能结合

Hope this gives some overall insight on how all the puzzle pieces fit together.希望这能提供一些关于所有拼图如何组合在一起的整体见解。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM