将数据从 Grid View 复制到另一个(有没有更好的方法)
Copy data from Grid View to another (is there a better way)
我有三个网格视图
网格视图 1 包含这些列
IdProject ;IdItem ;长度 ;数量
网格视图 2 包含这些列
IdInventory ;IdItem ;Length ;QuantityAvailable
网格视图 3 包含这些列
IdProject ;IdInventory ;IdItem ;Length ;ReservedQuantity ;UnavailableQuantity
操作是这样的:
我比较 Grid View1 和 Grid View2 的 (IdItem, Length, Quantity) 如果匹配,我有两个选择:
- 数量 <= 可用数量
我向 Grid View3 添加一行(ReservedQuantity= Quantity and UnavailableQuantity=0)
- 数量 > 可用数量
我有两个选择:
a- Grid View2:匹配的行不是最后一行
我向 Grid View3 添加一行(ReservedQuantity= QuantityAvailable 和 UnavailableQuantity=0)并继续到下一个匹配的行
b- Grid View2:匹配/不匹配的行是最后
我向 Grid View3 添加一行(ReservedQuantity= QuantityAvailable and UnavailableQuantity= Quantity-Sum(ReservedQuantity))
我习惯用这个代码
int[] selectedRows = gridView1.GetSelectedRows();
for (int i = 0; i < selectedRows.Length; i++)
{
DataRow rowGridView1 = (gridView1.GetRow(selectedRows[i]) as DataRowView).Row;
for (int j = 0; j < gridView2.RowCount; j++)
{
//check for comparison
//add rows
}
}
刚接触 DataGridView 的人倾向于 fiddle 直接使用 DataGridView 的单元格,尽管使用 DataSource 更容易。
您写道:操作是这样进行的:
我比较 Grid View1 和 Grid View2 的 (IdItem, Length, Quantity)。
唉,Grid View1 没有(IdItem、Length、Quantity)。但是,此 DataGridView 中的每一行都有。我假设您打算比较 Dgv
中的行
我想你的意思是,你将 Dgv1 的第 0 行与 Dgv2 的第 0 行进行比较,并根据你从 Dgv3 创建的第 0 行的值进行比较。同样,您对所有行都执行此操作。
显然 Dgv1 显示了一系列相似的项目。我不知道它们是什么,所以假设它们是 class A 的项目。这个 class 类似于以下内容:
class A
{
public int IdProject {get; set;}
public int IdItem {get; set;}
public decimal Length {get; set;}
public int Quantity {get; set;}
}
同样,Dgv2 显示 class B:
的项目
class B
{
public int IdInventory {get; set;}
public int IdItem {get; set;}
public decimal Length {get; set;}
public int QuantityAvailable {get; set;}
}
并且 Dgv3 显示 class C:
class C
{
public int IdProject {get; set;}
public int IdInventory {get; set;}
public int IdItem {get; set;}
public decimal Length {get; set;}
public int ReservedQuantity {get; set;}
public int UnavailableQuantity {get; set;}
}
您的 classes 可能有几个其他属性,或者其他标识符或类型,但您明白了要点。
您使用 visual studio 设计器添加了三个 DataGridView 和列。在构造函数中,您可以提及哪一列应该显示哪个 属性.
为此我们使用 属性 DataGridViewColumn.DataPropertyName
// constructor
public MyForm()
{
InitializeComponent();
// Dgv1 shows properties of class A
dgv1ColumnIdProject.DataPropertyName = nameof(A.IdProject);
dgv1ColumnIdItem.DataPropertyName = nameof(A.IdItem);
dgv1ColumnLength.DataPropertyName = nameof(A.Length);
dgv1ColumnQuantity.DataPropertyName = nameof(B.Length);
// Dgv2 shows properties of class B
dgv2ColumnIdInventory.DataPropertyName = nameof(B.IdInventory);
... // etc also Dgv3 and class C
}
在某个地方你有方法来获取应该在 Dgv1 和 Dgv2 中显示的数据:
(As 是 A 的复数;Bs 是 B 的复数,等等)
private IEnumerable<A> FetchAsToDisplay() {...}
private IEnumerable<B> FetchBsToDisplay() {...}
要填充 DataGridView 并获取 DataGridVies 中的项目,请创建以下属性:
private BindingList<A> DisplayedAs
{
get => (BindingList<A>)this.Dgv1.DataSource;
set => this.Dgv1.DataSource = value;
}
private BindingList<B> DisplayedBs
{
get => (BindingList<B>)this.Dgv2.DataSource;
set => this.Dgv2.DataSource = value;
}
private BindingList<C> DisplayedCs
{
get => (BindingList<C>)this.Dgv3.DataSource;
set => this.Dgv3.DataSource = value;
}
现在要用初始值填充 Dgv1 和 Dgv2,请执行以下操作:
IEnumerable<A> asToDisplay = this.FetchAsToDisplay();
this.DisplayedAs = new BindingList<A>(asToDisplay.ToList());
IEnumerable<B> bsToDisplay = this.FetchBsToDisplay();
this.DisplayedBs = new BindingList<B>(bsToDisplay.ToList());
要计算 Dgv3 中应包含的内容,您可以重复使用 asToDisplay 和 bsToDisplay,或者如果您稍后必须执行此操作,例如在单击“确定”按钮后:
private void OnButtonOk_Clicked(object sender, ...)
{
ICollection<A> displayedAs = this.DisplayedAs;
ICollection<B> displayedBs = this.DisplayedBs;
IEnumerable<C> csToDisplay = this.CreateCsToDisplay(displayedAs, displayedBs);
this.DisplayedCs = new BindingList(csToDisplay.ToList();
}
CreateCsToDisplay(TODO:发明一个更好的名称)是根据您定义的两个选项决定应该显示什么的过程。
private IEnumerable<C> CreateCsToDisplay(IEnumerable<A> as, IEnumerable<B> bs)
{
// assume Dgv1 and Dgv2 has the same number of rows,
// so sequence as has the same number of elements as sequence bs
// use ZIP to combine A and B. For every [a,b] combination create a C:
return as.Zip(bs, (a, b) => this.CreateC(a, b);
}
private C CreateC(A a, B b)
{
// use the conditions you defined
if (a.Quantity < b.QuantityAvailable)
{
return new C
{
ReservedQuantity = a.Quantity,
UnavailableQuantity = 0,
};
}
else
{
return new C ... etc, see your specification
}
}
总结
通过使用 DataSource 和 BindingList,您不必再 fiddle 处理行和单元格,您可以将行解释为类似项目的序列。使用 DisplayedAs
等属性访问行。获取和设置显示的项目现在是小菜一碟:只需使用属性。
为了计算如何从一个 [A, B] 组合创建一个 C,我们创建了一个方法 CreateC。此方法隐藏了您的规范。
类似地,我们有一个方法可以从 A 和 B 的序列创建 C 的序列:CreateCsToDisplay。此方法还隐藏了 C 的创建方式。
我有三个网格视图
网格视图 1 包含这些列
IdProject ;IdItem ;长度 ;数量
网格视图 2 包含这些列
IdInventory ;IdItem ;Length ;QuantityAvailable
网格视图 3 包含这些列
IdProject ;IdInventory ;IdItem ;Length ;ReservedQuantity ;UnavailableQuantity
操作是这样的:
我比较 Grid View1 和 Grid View2 的 (IdItem, Length, Quantity) 如果匹配,我有两个选择:
- 数量 <= 可用数量
我向 Grid View3 添加一行(ReservedQuantity= Quantity and UnavailableQuantity=0) - 数量 > 可用数量
我有两个选择:
a- Grid View2:匹配的行不是最后一行
我向 Grid View3 添加一行(ReservedQuantity= QuantityAvailable 和 UnavailableQuantity=0)并继续到下一个匹配的行
b- Grid View2:匹配/不匹配的行是最后
我向 Grid View3 添加一行(ReservedQuantity= QuantityAvailable and UnavailableQuantity= Quantity-Sum(ReservedQuantity))
我习惯用这个代码
int[] selectedRows = gridView1.GetSelectedRows();
for (int i = 0; i < selectedRows.Length; i++)
{
DataRow rowGridView1 = (gridView1.GetRow(selectedRows[i]) as DataRowView).Row;
for (int j = 0; j < gridView2.RowCount; j++)
{
//check for comparison
//add rows
}
}
刚接触 DataGridView 的人倾向于 fiddle 直接使用 DataGridView 的单元格,尽管使用 DataSource 更容易。
您写道:操作是这样进行的: 我比较 Grid View1 和 Grid View2 的 (IdItem, Length, Quantity)。
唉,Grid View1 没有(IdItem、Length、Quantity)。但是,此 DataGridView 中的每一行都有。我假设您打算比较 Dgv
中的行我想你的意思是,你将 Dgv1 的第 0 行与 Dgv2 的第 0 行进行比较,并根据你从 Dgv3 创建的第 0 行的值进行比较。同样,您对所有行都执行此操作。
显然 Dgv1 显示了一系列相似的项目。我不知道它们是什么,所以假设它们是 class A 的项目。这个 class 类似于以下内容:
class A
{
public int IdProject {get; set;}
public int IdItem {get; set;}
public decimal Length {get; set;}
public int Quantity {get; set;}
}
同样,Dgv2 显示 class B:
的项目class B
{
public int IdInventory {get; set;}
public int IdItem {get; set;}
public decimal Length {get; set;}
public int QuantityAvailable {get; set;}
}
并且 Dgv3 显示 class C:
class C
{
public int IdProject {get; set;}
public int IdInventory {get; set;}
public int IdItem {get; set;}
public decimal Length {get; set;}
public int ReservedQuantity {get; set;}
public int UnavailableQuantity {get; set;}
}
您的 classes 可能有几个其他属性,或者其他标识符或类型,但您明白了要点。
您使用 visual studio 设计器添加了三个 DataGridView 和列。在构造函数中,您可以提及哪一列应该显示哪个 属性.
为此我们使用 属性 DataGridViewColumn.DataPropertyName
// constructor
public MyForm()
{
InitializeComponent();
// Dgv1 shows properties of class A
dgv1ColumnIdProject.DataPropertyName = nameof(A.IdProject);
dgv1ColumnIdItem.DataPropertyName = nameof(A.IdItem);
dgv1ColumnLength.DataPropertyName = nameof(A.Length);
dgv1ColumnQuantity.DataPropertyName = nameof(B.Length);
// Dgv2 shows properties of class B
dgv2ColumnIdInventory.DataPropertyName = nameof(B.IdInventory);
... // etc also Dgv3 and class C
}
在某个地方你有方法来获取应该在 Dgv1 和 Dgv2 中显示的数据:
(As 是 A 的复数;Bs 是 B 的复数,等等)
private IEnumerable<A> FetchAsToDisplay() {...}
private IEnumerable<B> FetchBsToDisplay() {...}
要填充 DataGridView 并获取 DataGridVies 中的项目,请创建以下属性:
private BindingList<A> DisplayedAs
{
get => (BindingList<A>)this.Dgv1.DataSource;
set => this.Dgv1.DataSource = value;
}
private BindingList<B> DisplayedBs
{
get => (BindingList<B>)this.Dgv2.DataSource;
set => this.Dgv2.DataSource = value;
}
private BindingList<C> DisplayedCs
{
get => (BindingList<C>)this.Dgv3.DataSource;
set => this.Dgv3.DataSource = value;
}
现在要用初始值填充 Dgv1 和 Dgv2,请执行以下操作:
IEnumerable<A> asToDisplay = this.FetchAsToDisplay();
this.DisplayedAs = new BindingList<A>(asToDisplay.ToList());
IEnumerable<B> bsToDisplay = this.FetchBsToDisplay();
this.DisplayedBs = new BindingList<B>(bsToDisplay.ToList());
要计算 Dgv3 中应包含的内容,您可以重复使用 asToDisplay 和 bsToDisplay,或者如果您稍后必须执行此操作,例如在单击“确定”按钮后:
private void OnButtonOk_Clicked(object sender, ...)
{
ICollection<A> displayedAs = this.DisplayedAs;
ICollection<B> displayedBs = this.DisplayedBs;
IEnumerable<C> csToDisplay = this.CreateCsToDisplay(displayedAs, displayedBs);
this.DisplayedCs = new BindingList(csToDisplay.ToList();
}
CreateCsToDisplay(TODO:发明一个更好的名称)是根据您定义的两个选项决定应该显示什么的过程。
private IEnumerable<C> CreateCsToDisplay(IEnumerable<A> as, IEnumerable<B> bs)
{
// assume Dgv1 and Dgv2 has the same number of rows,
// so sequence as has the same number of elements as sequence bs
// use ZIP to combine A and B. For every [a,b] combination create a C:
return as.Zip(bs, (a, b) => this.CreateC(a, b);
}
private C CreateC(A a, B b)
{
// use the conditions you defined
if (a.Quantity < b.QuantityAvailable)
{
return new C
{
ReservedQuantity = a.Quantity,
UnavailableQuantity = 0,
};
}
else
{
return new C ... etc, see your specification
}
}
总结
通过使用 DataSource 和 BindingList,您不必再 fiddle 处理行和单元格,您可以将行解释为类似项目的序列。使用 DisplayedAs
等属性访问行。获取和设置显示的项目现在是小菜一碟:只需使用属性。
为了计算如何从一个 [A, B] 组合创建一个 C,我们创建了一个方法 CreateC。此方法隐藏了您的规范。
类似地,我们有一个方法可以从 A 和 B 的序列创建 C 的序列:CreateCsToDisplay。此方法还隐藏了 C 的创建方式。