【问题标题】:winform .net best way if you want to display images in a datagridview如果你想在 datagridview 中显示图像,winform .net 的最佳方式
【发布时间】:2012-04-18 00:05:56
【问题描述】:

net webdeveloper,通常不制作任何 win32 应用程序。但现在我必须这样做。我有一个包含大约 2000 个条目的列表。 每个条目都应显示为带有文本框的标签和另一个标签和图片。我用flowlayoutpanel做了这个,我对条目做了一个foreach,为每个条目制作了一个带有标签、文本框、标签和图片框的面板。

现在,当它超过 1000 个条目时,我遇到了渲染问题。 所以我读到我应该使用列表视图或数据网格视图。

现在我有一个像这样的数据网格视图:

DataGridView dgv = new DataGridView();
dgv.AutoSize = true;
dgv.ScrollBars = ScrollBars.Vertical;

System.Data.DataTable dt = new System.Data.DataTable();
DataColumn dc1 = new DataColumn("Code", typeof(string));
dc1.ReadOnly = true;
dt.Columns.Add(dc1);
dt.Columns.Add(new DataColumn("Quantity", typeof(int)));
DataColumn dc3 = new DataColumn("Price", typeof(string));
dc3.ReadOnly = true;
dt.Columns.Add(dc3);
dt.Columns.Add(new DataColumn("Image", typeof(Bitmap)));

foreach (Product pd in products)
{
      DataRow dr = dt.NewRow();
      dr["Code"] = pd.ProductCode;
      dr["Quantity"] = pd.ProductQuantity;
      dr["Price"] = "€ " + String.Format("{0:0,00}", pd.ProductResalePrice.ToString());

      dr["Image"] = BitmapFromWeb(pd.ProductImage);
      dt.Rows.Add(dr);
}

dt.AcceptChanges();
dgv.RowTemplate.Height = 50;
dgv.DataSource = dt;

但问题是 datagridview 上的位图真的很慢!我之前拥有的图片框选项和面板要快得多。我该如何解决?

第二个问题是:当我想跟踪第二列中所做的更改时,我需要哪个事件?

有一件事:图片是在线可用的,所以“pd.ProductImage”是一个网址

    private static Bitmap BitmapFromWeb(string URL)
    {
        try
        {
            HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(URL);
            myRequest.Method = "GET";
            HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
            System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(myResponse.GetResponseStream());
            myResponse.Close();

            return bmp;
        }
        catch (Exception ex)
        {
            return null; // if for some reason we couldn't get to image, we return null
        }
    }

【问题讨论】:

    标签: winforms datagridview picturebox


    【解决方案1】:

    图像加载异步然后强制刷新单元格。您可以将您的 foreach 代码放入对 ThreadPool 的调用中,例如...

    ThreadPool.QueueUserWorkItem(delegate
    {
     foreach (DataRow row in dt)
     {
      row["Image"] = BitmapFromWeb(Products[row["Code"]].ProductImage);
      //maybe a call to invalidate here, remember to do Control.Invoke(...)
     }
    }
    

    编辑:这是我在 Form 构造函数中测试的示例代码...

            DataTable t= new DataTable();
            t.Columns.Add("id");
            t.Columns.Add("uri");
            t.Columns.Add(new DataColumn("Img",typeof(Bitmap)));
    
            Bitmap b = new Bitmap(50, 15);
            using (Graphics g = Graphics.FromImage(b))
            {
                g.DrawString("Loading...", this.Font, new SolidBrush(Color.Black), 0f,0f);
            }
    
            t.Rows.Add(new object[] { "1", "http://farm1.static.flickr.com/88/377522544_c4774f15cc_s.jpg", b });
            t.Rows.Add(new object[] { "2", "http://farm1.static.flickr.com/175/377522405_2c505def99_s.jpg", b });
            t.Rows.Add(new object[] { "3", "http://farm1.static.flickr.com/185/377524902_72f82e2db9_s.jpg", b });
            t.Rows.Add(new object[] { "4", "http://farm1.static.flickr.com/136/377524944_d011abf786_s.jpg", b });
            t.Rows.Add(new object[] { "5", "http://farm1.static.flickr.com/137/377528675_d3b9d541fb_s.jpg", b });
            dataGridView1.DataSource = t;
            ThreadPool.QueueUserWorkItem(delegate
            {
                foreach (DataRow row in t.Rows)
                {
                    HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(row["uri"].ToString());
                    myRequest.Method = "GET";
                    HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
                    System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(myResponse.GetResponseStream());
                    myResponse.Close();
    
                    row["Img"] = bmp;
                }
            });
    
            dataGridView1.CellEndEdit += dataGridView1_CellEndEdit;
    

    ....并在单元格末尾编辑代码:

        private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            string value = dataGridView1.Rows[e.RowIndex].Cells["uri"].Value.ToString();
            ThreadPool.QueueUserWorkItem(delegate
            {
                    HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(value);
                    myRequest.Method = "GET";
                    HttpWebResponse myResponse = (HttpWebResponse)myRequest.GetResponse();
                    System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(myResponse.GetResponseStream());
                    myResponse.Close();
                    dataGridView1.Rows[e.RowIndex].Cells["Img"].Value=bmp;
            });
        }
    

    【讨论】:

    • 感谢 jmservera,但在 win32 编码方面我是菜鸟。 control.invoke 是什么意思?你知道如何跟踪第二列文本框中的变化
    • 你好 jmservera,这要快得多,但它几乎在每一行都显示相同的图像。我是线程新手......对不起
    • 然后查看您发送到您的 bitmapfromweb 代码的内容,我没有测试代码我只是将其编写为一种 C# 伪代码。
    【解决方案2】:
    // table is DataTable object declared as member in my form class
    table = new DataTable();
    table.Columns.Add(new DataColumn("Column1", typeof(string)));
    table.Columns.Add(new DataColumn("Column2", typeof(string)));
    table.Columns.Add(new DataColumn("Column3", typeof(System.Drawing.Bitmap)));
    
    dataGridView1.DataSource = table;
    

    【讨论】:

    • 大声笑,你回答了 2009 年 12 月的一个帖子!使用同步解决方案而不是异步
    猜你喜欢
    • 2010-11-15
    • 2020-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-05
    • 1970-01-01
    • 2016-02-25
    相关资源
    最近更新 更多