我在一家建筑公司工作,正在为3D建模程序创建一个插件来协助设计。我有一个建筑班和一个地板班。该建筑物包含对楼层的FloorList集合的引用。我正在尝试弄清FloorList集合的基础,以便可以最大程度地减少创建界面以编辑集合的工作量。
地板系列代表了一系列相互堆叠的建筑地板。每个楼层都有一个可读写的Floor.Height属性,以及一个只读的Floor.Elevation属性,并通过总计当前楼层以下的楼层高度进行设置。因此,无论何时在集合中添加,移除,移动或更改地板,都需要更新Floor.Elevation属性。
另外,我想创建一个UI来编辑此集合。我当时正在考虑使用DataGrid控件,其中每个楼层的高度和其他属性都作为控件的一行列出。用户应该能够使用该控件添加,删除和重新订购楼层。我希望将其设置为尽可能简单灵活。意味着我只想简单地将Floors的集合绑定到DataGrid,并根据Floor类的属性填充DataGrid的列。如果可能的话,我希望能够利用DataGrid控件的内置“添加/删除UI”界面,而不必在我的集合和DataGrid之间设置一堆事件关系。
为了使将来的事情变得更加复杂,我将需要允许用户将自定义属性动态添加到Floors中,希望它们也可以在DataGrid中查看和编辑。我想我最终要通过让Floor类实现IExtenderProvider来做到这一点。因此,最终,DataGrid看起来像这样:
初始属性将来的自定义用户属性
高度标高ProgramType UnitType UnitCount
15'70'住宅豪华5
15'55'住宅豪华5
15'40'住宅预算10
20'20'零售N / A 2
20'0'零售N / A 3
现在我的问题是我应该将FloorList集合作为基础以允许此功能吗?我正在考虑的选项如下。
1)继承自List(Floor)
诸如“添加/删除”之类的方法并不重要,因此我无法覆盖它们来更新高程
2)实现IList(Floor)
OnChange事件不是内置的,因此如果列表发生更改,DataGrid将不会更新(我认为?)
我认为这可能是最好的选择,但是我需要做些什么来确保对FloorList集合或DataGrid所做的更改彼此同步?
3)从BindingList(Floor)继承
诸如“添加/删除”之类的方法不是虚拟的,因此我无法对其进行修改以更新地面高程。
4)实现IBindingList
IBindinglist不是通用的,我只希望我的集合包含Floor对象
最佳答案
您应该为您的集合使用BindingList或实现IBindingList,因为这会将列表中的任何更改通知给DataGridView。
然后为Floor类实现INotifyPropertyChanged接口,这将允许您的单个Floor项目与DataGridView之间建立双向绑定模式。
埃里克,你也可以做这样的事情
public class MyFloorCollection : BindingList<Floor>
{
public MyFloorCollection()
: base()
{
this.ListChanged += new ListChangedEventHandler(MyFloorCollection_ListChanged);
}
void MyFloorCollection_ListChanged(object sender, ListChangedEventArgs e)
{
if (e.ListChangedType == ListChangedType.ItemAdded)
{
Floor newFloor = this[e.NewIndex] as Floor;
if (newFloor != null)
{
newFloor.HeightChanged += new Floor.HeightChangedEventHandler(newFloor_HeightChanged);
}
}
}
void newFloor_HeightChanged(int newValue, int oldValue)
{
//recaluclate
}
}
当然,您可以创建自己的HeightChangedEvent并进行订阅,这样就不必在if语句中按属性名称进行操作。
因此,您的Floor课将如下所示
public class Floor : INotifyPropertyChanged
{
private int _height;
public int Height
{
get { return _height; }
set
{
if (HeightChanged != null)
HeightChanged(value, _height);
_height = value;
OnPropertyChanged("Height");
}
}
public int Elevation { get; set; }
private void OnPropertyChanged(string property)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(property));
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
public delegate void HeightChangedEventHandler(int newValue, int oldValue);
public event HeightChangedEventHandler HeightChanged;
}
这样,您只需要订阅HeightChanged变量,而不是PropertyChanged。 DataGridView将使用PropertyChanged来保持TwoWay绑定。我相信这种方式更清洁。
您还可以更改委托并将该项目作为发件人传递。
public delegate void HeightChangedEventHandler(Floor sender, int newValue, int oldValue);
编辑:要取消订阅HeightChanged事件,您需要覆盖RemoveItem
protected override void RemoveItem(int index)
{
if (index > -1)
this[index].HeightChanged -= newFloor_HeightChanged;
base.RemoveItem(index);
}