[英]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 的总属性在以下情况下会自动更改:
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.