我有两个课程:Employee
和EmployeeGridViewAdapter
。 Employee
由几种复杂类型组成。 EmployeeGridViewAdapter
包装一个Employee
并将其成员公开为一组扁平的系统类型,以便DataGridView可以处理显示,编辑等。
我正在使用VS的内置支持将POCO转换为数据源,然后将其附加到BindingSource
对象。当我将DataGridView
附加到BindingSource
时,它会创建预期的列,并且在运行时我可以执行预期的CRUD操作。到目前为止一切都很好。
问题是适配器的集合以及员工集合未被同步。因此,我创建运行时的所有员工永远不会被持久化。这是生成EmployeeGridViewAdapter
的集合的代码片段:
var employeeCollection = new List<EmployeeGridViewAdapter>();
foreach (var employee in this.employees)
{
employeeCollection.Add(new EmployeeGridViewAdapter(employee));
}
this.view.Employees = employeeCollection;
非常简单,但我无法弄清楚如何将更改同步回原始集合。我想已经处理了编辑,因为两个集合都引用了相同的对象,但创建新员工和删除员工的情况并没有发生,所以我无法确定。
答案 0 :(得分:3)
您还可以考虑使用System.Collections.ObjectModel.ObservableCollection并将其CollectionChanged事件连接起来。它可能看起来像这样。
ObservableCollection<EmployeeAdapter> observableEmployees =
new ObservableCollection<EmployeeAdapter>();
foreach (Employee emp in employees)
{
observableEmployees.Add(new EmployeeAdapter(emp));
}
observableEmployees.CollectionChanged +=
(object sender, NotifyCollectionChangedEventArgs e) =>
{
ObservableCollection<EmployeeAdapter> views =
sender as ObservableCollection<EmployeeAdapter>;
if (views == null)
return;
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
foreach (EmployeeAdapter view in e.NewItems)
{
if (!employees.Contains(view.Employee))
employees.Add(view.Employee);
}
break;
case NotifyCollectionChangedAction.Remove:
foreach (EmployeeAdapter view in e.OldItems)
{
if (employees.Contains(view.Employee))
employees.Remove(view.Employee);
}
break;
default:
break;
}
};
代码假定使用以下语句。
using System.Collections.ObjectModel;
using System.Collections.Specialized;
如果您需要IList界面,还可以使用System.ComponentModel.BindingList并将其ListChanged事件连接起来。它可能看起来像这样。
BindingList<EmployeeAdapter> empViews = new BindingList<EmployeeAdapter>();
foreach (Employee emp in employees)
{
empViews.Add(new EmployeeAdapter(emp));
}
empViews.ListChanged +=
(object sender, ListChangedEventArgs e) =>
{
BindingList<EmployeeAdapter> employeeAdapters =
sender as BindingList<EmployeeAdapter>;
if (employeeAdapters == null)
return;
switch (e.ListChangedType)
{
case ListChangedType.ItemAdded:
EmployeeAdapter added = employeeAdapters[e.NewIndex];
if (!employees.Contains(added.Employee))
employees.Add(added.Employee);
break;
case ListChangedType.ItemDeleted:
EmployeeAdapter deleted = employeeAdapters[e.OldIndex];
if (employees.Contains(deleted.Employee))
employees.Remove(deleted.Employee);
break;
default:
break;
}
};
代码假定使用以下语句。
using System.ComponentModel;
答案 1 :(得分:1)
第一个问题似乎是你正在创建一个新的列表和数据绑定到那个。当您添加元素时,这些元素将添加到集合中,但您的原始员工列表仍未修改。
为了避免这种情况,您应该提供一个自定义集合类,将更改迁移回基础员工列表,或者在绑定数据之前连接相应的事件(在插入/删除时进行迁移)。
为了避免将可编辑集合绑定到网格的许多其他问题,您应该实现数据绑定接口,如下所述。这些接口的存在允许可视控件向底层集合通知诸如“插入已取消”之类的操作(当用户中止新记录的输入时),并且类似地允许信息以相反的方向流动(在收集或个人时更新UI)条目变更)。
首先,您需要在数据绑定集合中的各个项目上实现至少IEditableObject,INotifyPropertyChanged和IDataErrorInfo,在您的情况下,它们将是EmployeeGridViewAdaper类。
此外,您希望您的集合实现ITypedList和INotifyCollectionChanged。 BCL包含一个BindingList实现,为此提供了一个很好的起点。建议使用此代替普通列表。
我可以推荐Data Binding with Windows Forms 2.0详尽地介绍这个主题。