【问题标题】:transfer selected datagridview row with image to another datagridview将选定的带有图像的datagridview行传输到另一个datagridview
【发布时间】:2020-09-13 13:11:44
【问题描述】:

我正在尝试制作购物车,当用户在产品表中选择行时,输入数量并单击“添加到购物车”,该行将转到购物车表。我可以做到,但图像列显示图像的 system.byte 插入。同样,当我选择新产品并将其添加到购物车时,购物车表中的前一行被覆盖而不是添加新产品。

 public partial class AddToCartForm : Form
{
    public AddToCartForm()
    {
        InitializeComponent();
    }

    private void AddToCartForm_Load(object sender, EventArgs e)
    {
        PopulateProductImageDgv("Select * from ProductDetailsTwo", ref dataGridView1);

        dataGridView1.MultiSelect = false;
        dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;

        dataGridView2.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
        dataGridView2.RowTemplate.Height = 100;
        dataGridView2.AllowUserToAddRows = false;

    }

    private void btnSaveToCart_Click(object sender, EventArgs e)
    {
        if (dataGridView1.SelectedRows.Count > 0)
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("Id");
            dt.Columns.Add("Name");
            dt.Columns.Add("ImageData");
            dt.Columns.Add("Qty");
            foreach (DataGridViewRow dgvRow in dataGridView1.SelectedRows)
            {
                dt.Rows.Add(dgvRow.Cells[0].Value, dgvRow.Cells[1].Value, dgvRow.Cells[2].Value, txtqty.Text.ToString());
            }

            dataGridView2.DataSource = dt;

        }
        else
        {
            MessageBox.Show("select something");
        }
    }

    public void PopulateProductImageDgv(string sql, ref DataGridView dg)
    {
        using (SqlConnection connection = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["cn"].ConnectionString))
        {
            connection.Open();

            using (SqlCommand cmd = new SqlCommand(sql, connection))
            {
                SqlDataAdapter da = new SqlDataAdapter(cmd);
                DataTable table = new DataTable();

                //settings for dgv with image
                dg.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
                dg.RowTemplate.Height = 100;
                dg.AllowUserToAddRows = false;

                da.Fill(table);
                dg.DataSource = table;

                DataGridViewImageColumn imageColumn = new DataGridViewImageColumn();
                imageColumn = (DataGridViewImageColumn)dg.Columns[2];
                imageColumn.ImageLayout = DataGridViewImageCellLayout.Stretch;

                connection.Close();
            }
        }
    }

}

这是图片。感谢您的帮助

【问题讨论】:

  • ImageData 列的DataType 设置为DataType = typeof(Image)。从 PopulateProductImageDgv() 方法中删除 reftxtqty.Text.ToString()? txtqty.Text 已经是一个字符串了。
  • @Jimi 它工作谢谢。我将类型更改为字节 []。我还有一个问题。购物车 datagridview 始终只显示 1 行。每当我添加另一个时,它都会覆盖上一行,
  • 是的,好吧,这并不是绑定两个 DataGridView 控件的真正方法。无论如何,你可以设置dataGridView2.DataSource = null; dataGridView2.DataSource = dt;。假设dataGridView1.SelectedRows 包含多个引用。您可以添加一个复选框列以简化选择(对于用户和您)。之后了解如何使用 BindingSource 组件。这是一个生活改变者(是的,好吧,好吧......)
  • 顺便说一句,我只记得我发布了类似的内容(只是语言略有不同),它使用中间类模型简化了选择。 Here
  • 用户一次只能选择一行,因为用户需要添加数量。数量也显示在购物车 datagridview 上。它仍然不允许我向卡 datagridview 添加新记录。现有记录仍被新添加的记录覆盖

标签: c# winforms datagridview datagridviewimagecolumn


【解决方案1】:

我有几个问题,但是,为了简单起见,一个问题是每次用户单击保存到购物车时,似乎没有必要为第二个(选定项目)网格“重新创建”一个新的 DataTable按钮。

此外,发布的代码只是“覆盖”了“选定”项目网格中的现有数据。这是一种奇怪的行为。例如,用户单击一个项目,然后单击保存到购物车按钮。这会将项目保存在选定项目网格中,然后用户单击不同的项目,然后单击保存按钮……然后,使用已发布,先前保存的项目将消失。我猜你不想要这种行为。

鉴于上述 cmets 和有限的发布代码,我建议为此使用两个不同的 DataTables 的简单解决方案。一张表保存“所有”项目,供用户选择。显然,它一开始就充满了所有项目。第二个表是一个“空”表,用于保存用户选择的项目。

我们显然可以“手动”创建选定项目表,但是,这需要更多的工作,并且我们需要确保维护某些列。 “克隆”第一个表将有助于从一个表中查找行并将其复制到另一个表。换句话说,我们希望能够查看“已选择”项目表并查看当前选择的项目是否已经在其中。如果是,我们不想添加新行,我们只想更新现有选定项目的数量。

鉴于此,第二个表的架构可以使用与第一个表相同的架构,并且只显示我们想要的列,或者在这种情况下……“添加”一个新的数量列。如果我们Clone 第一个表模式,然后将“数量”列添加到其中,那么搜索和复制会容易得多。这将起作用,您可以在不手动将列添加到网格的情况下执行此操作。这意味着即使我们在第二个表中添加了另一列,行导入仍然会成功。

下面是一个完整的示例,测试数据使用原始表格,其中包含每单位的“ItemID”、“Description”和“Cost”列。第二个表也有这些列和两个附加列“QTY”用于数量和“TotalCost”。 “TotalCost”列是“Expression”列,它只是将“QTY”值乘以“Cost”值。当“数量”值随着每次按钮单击而改变时,“总成本”值将自动更新。网格的前两个全局数据表……

DataTable AllItems;
DataTable SelectedItems;

当表单加载时,我们用数据库中的所有项目填充AllItems。然后我们将这个表模式“克隆”到SelectedItems 表中。然后我们将数量列添加到SelectedItems 表中。最后将每个网格设置为正确的DataSource。像……

private void Form3_Load(object sender, EventArgs e) {
  AllItems = GetDataFromDB();
  SelectedItems = AllItems.Clone();
  DataColumn qtyCol = new DataColumn();
  qtyCol.ColumnName = "QTY";
  qtyCol.DataType = typeof(int);
  SelectedItems.Columns.Add(qtyCol);
  DataColumn totCol = new DataColumn();
  totCol.ColumnName = "Tot";
  totCol.DataType = typeof(decimal);
  totCol.Expression = "Cost * QTY";
  SelectedItems.Columns.Add(totCol);
  //SetSelectedItemsGridColumns();
  dataGridView1.DataSource = AllItems;
  dataGridView2.DataSource = SelectedItems;
}

如果需要,注释掉的“SetSelectedItemsGridColumns”代码用于自定义第二个网格的列。

通过此设置,现在应该相对简单地将所选行从包含所有项目的网格“复制”到包含所选项目的网格。应该注意的是,我们要搜索/查找的任何字段都必须与数据库中的字段类型匹配。如果您收到“类型”不匹配错误,请检查以确保代码中定义的“类型”与数据库中的“类型”匹配。在下面的示例中,我使用int 的“类型”来唯一标识数据库中的每个“ItemID”。这对您/可能显然会有所不同,您需要更改代码以匹配您要使用的正确类型/名称。

首先,三个变量:newItemID来唯一标识选中的项目。而dataRow 则使用来自每个选定行的数据进行初始化。它用于在SelectedItems 表中查找行并更新现有行。最后一个 DataRowView 从第一个网格中获取包含所有项目的行。

通过选定行的简单循环。抓取选定的行并获取其唯一的项目 ID。从数量文本框中解析数量值。尝试从选定项目表中获取行。如果返回的行为空,则该项目不在表中,我们需要将其添加为新行。如果返回了一行,那么我们只想将“数量”值添加到现有行。

private void button1_Click(object sender, EventArgs e) {
  int newItemID;
  DataRow dataRow;
  DataRowView drv;
  foreach (DataGridViewRow dgr in dataGridView1.SelectedRows) {
    drv = (DataRowView)dgr.DataBoundItem;
    newItemID = (int)drv["ItemID"];
    int.TryParse(txtQTY.Text.Trim(), out int qty);
    dataRow = SelectedItems.AsEnumerable().Where(x => x.Field<int>("ItemID") == newItemID).FirstOrDefault();
    if (dataRow != null) {
      int tot = (int)dataRow["QTY"] + qty;
      dataRow["QTY"] = tot;
    }
    else {
      SelectedItems.ImportRow(drv.Row);
      dataRow = SelectedItems.AsEnumerable().Where(x => x.Field<int>("ItemID") == newItemID).FirstOrDefault();
      dataRow["QTY"] = qty;
    }
  }
}

private DataTable GetDataFromDB() {
  DataTable dt = new DataTable();
  dt.Columns.Add("ItemID", typeof(int));
  dt.Columns.Add("Description", typeof(string));
  dt.Columns.Add("Cost", typeof(decimal));
  Random rand = new Random();
  for (int i = 1; i < 10; i++) {
    dt.Rows.Add(i, "Item_" + i, rand.NextDouble() * 100);
  }
  return dt;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    相关资源
    最近更新 更多