0

我的项目有一个带有 Combobox 列的 DataGridView,并且该列有两个项目,如您在图片中看到的“Punch Window”和“Window Wall”。

我正在使用 dataGridView1_CellEndEdit 事件,这些是我的代码

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 列)返回“无条目”。当我选择 A 列“窗墙”B 列返回 null 时,一切正常,直到这里。

我的问题是当 A 列选择“窗口墙”项时,我尝试在 B 列中输入一些数据,然后 dataGridView1_CellEndEdit 事件开始并使 B 列再次为空。我怎样才能防止这种情况。选择 Window Wall 后,我想处理 cellandedit 事件或希望 B 列单元独立运行。我希望用户可以在 B 列单元格中输入数据。

提前谢谢。在此处输入图像描述

4

1 回答 1

0

我经常看到人们将他们的模型与他们的显示方式(视图)交织在一起。您应该将模型与视图分开。

如果您将数据与数据的显示方式分开,然后您决定更改模型的显示方式,例如从 Forms 更改为 WPF,则更改不会出现在您的模型中。如果您决定更改模型,例如,从 XML 序列化更改为数据库,则您的视图不必更改。

模型和视图的分离还使您的模型的单元测试更容易:您不需要启动 Forms 程序来查看您是否正确处理了您的模型。

我的土耳其语有点生疏,但在我看来,您想显示一个 序列MaliyetCalismasi,其中每个MaliyetCalismasi都至少有 a Number, aProductType和 a Pcs,无论是什么。

乍一看,ProductType 和 Pcs 似乎有关系。似乎如果 ProductType 等于“Punch Window”,那么 Pcs 应该是“No Entry”,如果 ProductType 等于“Window Wall”,那么 Pcs 等于 null。

显然,上述内容无效:可以将 Pcs 更改为“No Entry”和 null 以外的其他值。如果操作员在 Pcs 中键入不同的值,您没有指定 ComboBox 的值:显示空 ComboBox?显示原始值?

您应该决定:您是否ProductType只是因为我希望能够在我的 DataGridView 中进行 ComboBox 选择,还是因为它是模型的一部分:如果您不必在 DataGridView 中显示数据,你还会有一个“ProductType”吗?

模型

我不确定 ProductType 是否可以超过这两个值。我们假设不是。如果它可以有更多的值,你应该改变类型。

enum ProductType
{
    PunchWindow,
    WindowWall,
    ...          // other Values?
}

class MaliyetCalismasi
{
    public int Number {get; set;}
    public string Pcs {get; set;}

    // TODO: ProductType
}

如果有人将 ProductType 设置为 ProductType.PunchWindow,我们知道属性 Pcs 会发生什么。但是如果有人更改 Pcs,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;
    } 
}

如果 Pcs 更改,您希望 ProductType 做什么?没有什么?还是第三个值?

private string pcs = null;
public string Pcs
{
    get => this.pcs
    set
    {
        if (this.Pcs != value)
        {
            this.pcs = value;
            this.OnPcsChanged();
        }
    }
}

顺便说一句,您是否看到因为我创建了 On...Changed 方法,所以 PropertyChanged 事件的实现将相当容易。

对此类进行单元测试是最少的工作。

很容易看出,如果将来您决定添加一个新的 ProductType 值“ManualSelected”,这意味着如果有人更改 Pcs,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());
}

如果你想对 Selected Rows 做一些事情:

MaliyetCalismasi CurrentMaliyetCalismasi => 
    this.DataGridView1.CurrentRow?.DataBoundItem as MaliyetCalismasi;

IEnumerable<MaliyetCalismasi> SelectedMaliyetCalismasi =>
    this.DataGridView1.SelectedRows
        .Select(row => row.DataBoundItem)
        .Cast<MaliyetCalismasi>();

您会看到,因为您将模型与其显示方式分开,处理数据的显示主要由单行方法组成!

意大利面kadar kolay!

于 2021-01-26T08:28:14.587 回答