我的项目有一个带有组合框列的DataGridView,这个列有两个项目:"Punch Window"one_answers"窗户墙";如图所示。
我使用datagridview1_cellenddit事件,这些是我的代码
for (int i = 0; i < dgv_MaliyetCalismasi.Rows.Count; i++)
{
if (dgv_MaliyetCalismasi.Rows[i].Cells["col_numberofProduct"].Value != null)
{
if (dgv_MaliyetCalismasi.Rows[i].Cells["col_numberofProduct"].Value.ToString() == "PUNCH WINDOW")
{
dgv_MaliyetCalismasi.Rows[i].Cells["col_pcs"].Value = "No entry";
dgv_MaliyetCalismasi.Rows[i].Cells["col_pcs"].ReadOnly = true;
}
else
{
dgv_MaliyetCalismasi.Rows[i].Cells["col_pcs"].Value = null;
dgv_MaliyetCalismasi.Rows[i].Cells["col_pcs"].ReadOnly = false;
}
}
}
当我选择打孔窗口(列A)然后另一列(列B)返回"No entry"。当我选择A列"窗口墙"时;B列返回null。在此之前一切正常。
我的问题是,当列A选择"窗口墙"项目,我尝试在B列输入一些数据,然后datagridview1_cellenddit事件开始并再次使B列为空。我怎样才能避免呢?与选定的窗口墙,我想处理cellanddedit事件或希望B列单元格独立行动。我希望用户可以在B列单元格中输入数据。
提前感谢。输入图片描述
我经常看到人们将他们的模型与他们如何显示它(视图)纠缠在一起。你应该把模型和视图分开。
如果您将数据与数据的显示方式分开,然后您决定更改显示模型的方式,例如从Forms更改为WPF,则更改将不在您的模型中。如果您决定更改模型,例如,从XML序列化更改为数据库,则不必更改视图。
模型和视图的分离也使你的模型单元测试更容易:你不需要启动一个窗体程序来查看你是否正确处理了你的模型。
我的土耳其语有点生锈,但在我看来,你想要显示MaliyetCalismasi
的序列,其中每个MaliyetCalismasi
至少有一个Number
,一个ProductType
和一个Pcs
,无论那可能是什么。
乍一看,ProductType和pc之间似乎有关系。似乎如果ProductType等于"Punch window",那么pc应该是"No entry"。如果ProductType = "Window Wall",那么Pcs = null。
显然以上是无效的:可以将pc更改为其他值而不是"No entry &;"和零。如果操作符在"pc: show empty ComboBox?"中键入不同的值,则没有指定组合框的值。显示原始值?
你应该决定:你做ProductType
只是因为我想要能够在我的DataGridView中做组合框选择,或者你做它是因为它是模型的一部分:如果你不需要在DataGridView中显示数据,你还会有一个"产品类型"吗?
我不确定ProductType是否可以有两个以上的值。让我们假设不是。如果它可以有更多的值,你应该改变类型。
enum ProductType
{
PunchWindow,
WindowWall,
... // other Values?
}
class MaliyetCalismasi
{
public int Number {get; set;}
public string Pcs {get; set;}
// TODO: ProductType
}
我们知道如果某人将ProductType设置为ProductType. punchwindow属性pc应该发生什么。但如果有人换了个人电脑,ProductType会发生什么变化吗?
private ProductType productType = ProductType.WindowWall;
public ProductType ProductType
{
get => this.productType;
set
{
if (this.ProductType != value)
{
this.productType = value;
this.OnProductTypeChanged();
}
}
}
private void OnProductTypeChanged()
{
const string pcsPuncWhindowValue = "No Entry";
if (this.ProductType == ProductType.PunchWindow}
{
this.Pcs = pcsPunchWindowValue;
}
else
{
this.Pcs = null;
}
}
如果pc改变了,你想用ProductType做什么?没有什么?还是第三个值?
private string pcs = null;
public string Pcs
{
get => this.pcs
set
{
if (this.Pcs != value)
{
this.pcs = value;
this.OnPcsChanged();
}
}
}
顺便说一下,你看到了吗,因为我创建了On…更改方法后,PropertyChanged事件的实现将相当容易。
对这个类进行单元测试是最简单的工作。
很容易看出,如果将来你决定添加一个新的ProductType值"ManualSelected",这意味着如果有人更改了pc, ProductType得到的值,那么更改将是最小的。
显示MaliyetCalismasi
人们倾向于直接编辑DataGridView中的单元格。如果你想这么做,再考虑一下。如果你仍然认为有必要,那就去做。使用数据源更容易。
// Create the DataGridView and the add the columns
DataGridView dataGridView1 = new DataGridView();
DataGridViewColumn columnNumber = new DataGridViewColumn();
DataGridViewColumn columnPcs = new DataGridViewColumn();
DataGridViewComboBoxColumn columnProductType = new DataGridViewComboBoxColumn();
// which properties should these column show?
columnNumber.DataPropertyName = nameof(MaliyetCalismasi.Number);
columnPcs.DataPropertyName = nameof(MaliyetCalismasi.Pcs);
columnProductType.DataPropertyName = nameof(MaliyetCalismasi.ProductType);
以上通常是使用visual studio designer完成的。您还需要做一些特殊的事情来填充ComboBox。这不是这个问题的一部分。
现在只做一个显示,你所需要做的就是将数据分配给DataGridView的数据源:
List<MaliyetCalismasi> fetchedMaliyetCalismasi = this.FetchMaliyetCalismasi();
this.dataGridView1.DataSource = fetchedMaliyetCalismasi;
这将是仅显示:如果操作符更改显示的数据:更改单元格,添加或删除行,原始数据不更新。
如果你想要更新数据,你需要把数据放在一个实现了IBindingList的对象中,像BindingList(显而易见的名字):
this.dataGridView.DataSource = new BindingList<MaliyetCalismasi>
(fetchedMaliyetCalismasi);
,很快!每个编辑过的单元格都会在BindingList中自动更新,即使添加或删除了行。即使操作符对显示的行进行排序,或重新排列列。这是因为你把视图和模型分开了:显示改变了,而模型没有。
将数据与其显示方式分离的良好实践将导致以下过程:
BindingList<MaliyetCalismasi> MaliyetCalismasi
{
get => (BindingList<MaliyetCalismasi>)this.DataGridView1.DataSource;
set => this.DataGridView1.DataSource = value;
}
IEnumerable<MaliyetCalismasi> FetchMaliyetCalismasi()
{
// TODO implement, fetch from database, or Json, or internet, or whatever
}
void InitDataGridView
{
this.MaliyetCalismasi = new BindingList<MaliyetCalismasi>(
this.FetchMaliyetCalismasi().ToList());
}
如果你想对选定行做点什么:
MaliyetCalismasi CurrentMaliyetCalismasi =>
this.DataGridView1.CurrentRow?.DataBoundItem as MaliyetCalismasi;
IEnumerable<MaliyetCalismasi> SelectedMaliyetCalismasi =>
this.DataGridView1.SelectedRows
.Select(row => row.DataBoundItem)
.Cast<MaliyetCalismasi>();
您可以看到,由于您将模型与其显示方式分离,因此处理数据的显示主要由单行方法组成!
Pasta kadar kolay!