关于在DataGridView中嵌入图片……

 

有一句英语名言——Picutures speak louder than words(图片胜于千言万语)。可见在描述一些细节问题,或者是用语言文字难以让人产生“身临其境”的时候,图片就发挥了其作用。在WinForm中,DataGridView不仅仅是用于显示文字、我们还可以显示图片。本章就和大伙儿讨论DataGridView中嵌入显示图片的问题。

一、嵌入式显示:

所谓“嵌入式”,就是说把图片单独存放在某个DataTable的字段中(该字段为byte[]类型)然后绑定到对应DataGridView的指定单元格中显示出来,代码大致如下:

[C#]

public partial class Form1 : Form
    {
        DataGridView dgv = null;

        public Form1()
        {
            InitializeComponent();

            //初始化动态产生数据表等字段
            dgv = new DataGridView();
            dgv.Parent = this;
            dgv.Dock = DockStyle.Fill;

            DataTable dt = new DataTable();
            dt.Columns.Add("Name", typeof(string));
            dt.Columns.Add("Image", typeof(byte[]));
            dt.Rows.Add("Test1", File.ReadAllBytes("d:\\test.jpg"));
            dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
            dgv.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
            dgv.DataSource = dt;
        }
    }

 

这样做的好处在于:由于你的图片文件被嵌入到了数据库中(这里是模拟数据库的效果,真实情况下你应该使用DataAdapter.Fill填充到DataTable中方可)。这样不存在图片丢失等情况;当然数据库的容量也大大增加。

二、连接式图片显示:

这是我给起的名字,就是类似我“关于资源文件”中那个“Link when compile"效果差不多——只在动态绑定的时候根据一定规律(如存储在数据库中的绝对或者相对路径)顺序加载图片,这样图片和数据库必然是分离的。不过拷贝的时候注意路径等问题。示例代码如下:

[C#]

public partial class Form1 : Form
    {
        DataGridView dgv = null;

        public Form1()
        {
            InitializeComponent();

            //初始化动态产生数据表等字段
            dgv = new DataGridView();
            dgv.Parent = this;
            dgv.Dock = DockStyle.Fill;

            DataTable dt = new DataTable();
            dt.Columns.Add("Name", typeof(string));
            dt.Columns.Add("Image", typeof(string));
            dt.Rows.Add("Test1", "d:\\test.jpg");
            dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
            dgv.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
            dgv.Columns.Add(new DataGridViewTextBoxColumn() { HeaderText = "Name", DataPropertyName = "Name" });
            dgv.Columns.Add(new DataGridViewImageColumn() { HeaderText = "Image", DataPropertyName = "Image" });
            dgv.CellFormatting += new DataGridViewCellFormattingEventHandler(dgv_CellFormatting);
            dgv.DataSource = dt;
        }

        void dgv_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex==1 && e.RowIndex!=dgv.NewRowIndex)
            {
                e.Value = File.ReadAllBytes(dgv.Rows[e.RowIndex].Cells[1].Value.ToString());
            }
        }
    }

以上代码和第一种”嵌入式“差不多,不过还请注意一下重要差别:

1)自定义了各个Columns,而不是自动生成(这是因为DataTable中都是string类型,包括存储图片的路径,如果单用自动生成的话则无法生成Image类型的列)。

2)人为使用了CellFormatting事件,该事件在呈现整个DataGridView的时候被出发。此时该事件的e的RowIndex将从0~最后一行(实际在DataTable中不存在),ColumnIndex从0~最后一列逐个遍历。如If中判断,其中e.ColumnIndex=1表示第一列,e.RowIndex不等于dgv.NewRowIndex表示不等于最后一行。同时给e.Value(实际单元格中内容)直接赋予其byte数组即可。

附带说明一下:你把DataGridView的AllowUserToAddRows设置为False,那么“e.RowIndex <> dgv.NewRowIndex”完全可以省略。

有兴趣的话,可以尝试结合我“关于资源文件”的方法,先把图片嵌入到资源文件中,然后在DataTable中某列添加各个对应资源文件的相对路径和名称,然后动态加载。

三、图片大小调整:

有时我们喜欢统一把图片“按比例缩放”,不喜欢很大或者很小的图片——怎么办?我们可以采取把图片的byte数组读入一个Memory中,然后加载到Image,同时创建新的BitMap(利用其构造函数定义统一的Size),然后存储到另外一个MemoryStream中并且使用其ToArray方法与DataGridView进行绑定。

对于“嵌入式”,示例代码如下:

[C#]

public partial class Form1 : Form
{
DataGridView dgv = null;

public Form1()
{
InitializeComponent();

//初始化动态产生数据表等字段
dgv = new DataGridView();
dgv.Parent = this;
dgv.Dock = DockStyle.Fill;

DataTable dt = new DataTable();
dt.Columns.Add("Name", typeof(string));
dt.Columns.Add("Image", typeof(byte[]));
dt.Rows.Add("Test1", File.ReadAllBytes("d:\\test.jpg"));
dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
dgv.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
dgv.CellFormatting += new DataGridViewCellFormattingEventHandler(dgv_CellFormatting);
dgv.AllowUserToAddRows = false;
dgv.DataSource = dt;
}

void dgv_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.ColumnIndex == 1)
{
using (MemoryStream oldms = new MemoryStream((byte[])e.Value))
{
Image img = Image.FromStream(oldms);
Bitmap bt = new Bitmap(img,new Size(100, 100));
using (MemoryStream newms = new MemoryStream())
{
bt.Save(newms,ImageFormat.Jpeg);
e.Value = newms.ToArray();
}
}
}
}
}

 

注意我还是沿用了CellFormatting事件,并且请观察该事件内部代码。如果是“连接式”的,只需更改第二列的类型,并且在CellFormatting中读取该列存储的图片路径,转化为byte即可。
[C#]

 public partial class Form1 : Form
    {
        DataGridView dgv = null;

        public Form1()
        {
            InitializeComponent();

            //初始化动态产生数据表等字段
            dgv = new DataGridView();
            dgv.Parent = this;
            dgv.Dock = DockStyle.Fill;

            DataTable dt = new DataTable();
            dt.Columns.Add("Name", typeof(string));
            dt.Columns.Add("Image", typeof(string));
            dt.Rows.Add("Test1", "d:\\test.jpg");
            dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
            dgv.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;

            dgv.Columns.Add(new DataGridViewTextBoxColumn() { HeaderText = "Name", DataPropertyName = "Name" });
            dgv.Columns.Add(new DataGridViewImageColumn() { HeaderText = "Image", DataPropertyName = "Image" });
            dgv.CellFormatting += new DataGridViewCellFormattingEventHandler(dgv_CellFormatting);
            dgv.AllowUserToAddRows = false;
            dgv.DataSource = dt;
        }

        void dgv_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
        {
            if (e.ColumnIndex == 1)
            {
                byte[] bytes = File.ReadAllBytes(e.Value.ToString());
                using (MemoryStream oldms = new MemoryStream(bytes))
                {
                    Image img = Image.FromStream(oldms);
                    Bitmap bt = new Bitmap(img,new Size(100, 100));
                    using (MemoryStream newms = new MemoryStream())
                    {
                        bt.Save(newms,ImageFormat.Jpeg);
                        e.Value = newms.ToArray();
                    }
                }
            }
        }
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值