星期四, 7月 28, 2016

[C#] DataGridView 範例

原本只是想找找 DataGridViewLinkColumn 資料來閱讀,沒想到發現 DataGridView 官方範例 - DataGridView 控制項範例,該文章 SampleCode 是切換到 2.0 版本才可以下載喔,拿它當範本來練習囉

Project
  • Form1 是主 Form
  • Form2 用來顯示明細資料
  • DataSource.Script 內有用到的 Sample Data 和 Store Prodecure
[C#] DataGridView 範例-3

Layout
  • Form1:一個 DataGridView
  • Form2:如下圖,DataGridView + ToolStripStatusLabel
[C#] DataGridView 範例-2


DataSource Script - 建立資料來練習
-- DROP XXX IF EXISTS 為 SQL Server 2016 新語法
DROP DATABASE IF EXISTS Demo
CREATE DATABASE Demo
GO

USE Demo
GO

DROP TABLE IF EXISTS Product
CREATE TABLE Product (ProdID int , ProdName nchar(50) , ProdURL char(100))
INSERT INTO Product VALUES
    (1,'SQL Server','https://www.microsoft.com/en-us/cloud-platform/sql-server'),
    (2,'Wndows Server','https://www.microsoft.com/en-us/cloud-platform/windows-server-2016'),
    (3,'Visual Studio','https://www.visualstudio.com/')
GO

DROP TABLE IF EXISTS ProductDetail
CREATE TABLE ProductDetail (ID int IDENTITY(1,1), ProdID int , DetailName nchar(50))
INSERT INTO ProductDetail VALUES
    (1,'SQL Server 2016'),
    (1,'SQL Server 2014'),
    (1,'SQL Server 2012'),
    (1,'SQL Server 2008'),
    (1,'SQL Server 2005'),
    (2,'Windows Server 2016'),
    (2,'Windows Server 2012'),
    (2,'Windows Server 2008'),
    (2,'Windows Server 2003'),
    (2,'Windows Server 2000'),
    (3,'Visual Studio 2015'),
    (3,'Visual Studio 2013'),
    (3,'Visual Studio 2012'),
    (3,'Visual Studio 2010'),
    (3,'Visual Studio 2008')
GO

DROP PROCEDURE IF EXISTS uspProduct
GO
CREATE PROCEDURE uspProduct
AS
    BEGIN
        SELECT
            ProdID ,
            ProdName , 
            ProdURL
        FROM Demo.dbo.Product
    END
GO

DROP PROCEDURE IF EXISTS uspProductDetailByProdID
GO
CREATE PROCEDURE uspProductDetailByProdID(@ProdID int)
AS
    BEGIN
        SELECT
            DetailName
            FROM Demo.dbo.ProductDetail
        WHERE ProdID = @ProdID
    END
GO

Form1.cs
using System.Data.SqlClient;
using System.Diagnostics;

namespace DGVSample
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            dataGridView1.AutoGenerateColumns = false;
            dataGridView1.AllowUserToAddRows = false;
            dataGridView1.Dock = DockStyle.Fill;

            dataGridView1.Columns.Add(new DataGridViewTextBoxColumn { DataPropertyName = "ProdID", Name = "ColProdID", HeaderText = "產品編號", Width = 100, Visible = true });
            dataGridView1.Columns.Add(new DataGridViewTextBoxColumn { DataPropertyName = "ProdName", Name = "ColProdName", HeaderText = "產品名稱", Width = 100, Visible = true, AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells });

            // 採取把  URL 塞在一個看不見 Column 內,也可以點選後進 DataTable 內抓網站連結
            dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
            {
                DataPropertyName = "ProdURL",
                Name = "ColProdURL",
                HeaderText = "產品官方網站連結",
                Width = 100,
                Visible = false
            });

            dataGridView1.Columns.Add(new DataGridViewLinkColumn
            {
                DataPropertyName = "",
                Name = "ColURL",
                HeaderText = "產品官方網站連結",
                Text = "連結網址",
                Width = 100,
                Visible = true,
                AutoSizeMode = DataGridViewAutoSizeColumnMode.ColumnHeader,
                UseColumnTextForLinkValue = true,
            });

            dataGridView1.Columns.Add(new DataGridViewLinkColumn
            {
                DataPropertyName = "",
                Name = "ColProductDetail",
                HeaderText = "",
                Text = "明細資料",
                Width = 100,
                Visible = true,
                AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCellsExceptHeader,
                UseColumnTextForLinkValue = true,
            });

            dataGridView1.DataSource = GetProductData();

            dataGridView1.CellContentClick += DataGridView1_CellContentClick;
            dataGridView1.KeyDown += DataGridView1_KeyDown;
        }

        private void ShowDetail(int ProdID)
        {
            Form2 frmDetail = new Form2();
            frmDetail.ShowDialog(
                GetProdName(ProdID),
                GetProductDetailData(ProdID));
        }

        private string GetProdName(int ProdID)
        {
            string ProdName = string.Empty;

            DataGridViewRow row = dataGridView1.Rows.OfType<DataGridViewRow>()
                .Where(r => (int)r.Cells["ColProdID"].Value == ProdID)
                .First();

            if (row == null) return ProdName;

            ProdName = row.Cells["ColProdName"].Value.ToString().Trim();

            return ProdName;
        }

        #region DataGridView Event
        private void DataGridView1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.Enter) return;

            // 抓 DataGridView Cell 值方法
            // 方法一
            // int ProdID = (int)dataGridView1.CurrentRow.Cells["ColProdID"].Value;
            // 方法二
            int ProdID = (int)dataGridView1.Rows[dataGridView1.CurrentCellAddress.Y].Cells["ColProdID"].Value;
            ShowDetail(ProdID);
        }

        private void DataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex < 0) return;

            DataGridView dgv = sender as DataGridView;

            if (e.ColumnIndex == dgv.Columns["ColURL"].Index)
            {
                Process.Start(dataGridView1.Rows[e.RowIndex].Cells["ColProdURL"].Value.ToString());
            }

            if (e.ColumnIndex == dgv.Columns["ColProductDetail"].Index)
            {
                int ProdID = (int)dgv.Rows[e.RowIndex].Cells["ColProdID"].Value;
                ShowDetail(ProdID);
            }
        }
        #endregion

        #region 資料庫存取相關
        private string ConnectionString = @"Data Source=.\SQL2016;Initial Catalog=Demo;Integrated Security=True";

        private DataTable GetProductData()
        {
            using (SqlConnection conn = new SqlConnection(ConnectionString))
            {
                try
                {
                    SqlCommand cmd = new SqlCommand("uspProduct", conn);
                    cmd.CommandType = CommandType.StoredProcedure;

                    SqlDataAdapter da = new SqlDataAdapter(cmd);
                    DataTable dt = new DataTable();
                    da.Fill(dt);
 
                    return dt;
                }
                catch (Exception)
                {
                    throw;
                }
            }
        }

        private DataTable GetProductDetailData(int ProdID)
        {
            using (SqlConnection conn = new SqlConnection(ConnectionString))
            {
                try
                {
                    SqlCommand cmd = new SqlCommand("uspProductDetailByProdID", conn);
                    cmd.CommandType = CommandType.StoredProcedure;

                    cmd.Parameters.Add("@ProdID", SqlDbType.Int).Value = ProdID;

                    SqlDataAdapter da = new SqlDataAdapter(cmd);
                    DataTable dt = new DataTable();
                    da.Fill(dt);

                    return dt;
                }
                catch (Exception)
                {
                    throw;
                }
            }
        }
        #endregion
    }
}
Form2.cs
namespace DGVSample
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();

            dataGridView1.AutoGenerateColumns = false;
            dataGridView1.AllowUserToAddRows = false;
            dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            dataGridView1.Dock = DockStyle.Fill;
            dataGridView1.DataBindingComplete += DataGridView1_DataBindingComplete;
            dataGridView1.KeyUp += DataGridView1_KeyUp;
            dataGridView1.CellContentClick += DataGridView1_CellContentClick;
            dataGridView1.KeyDown += DataGridView1_KeyDown;
            dataGridView1.RowPostPaint += DataGridView1_RowPostPaint;

            dataGridView1.Columns.Add(new DataGridViewCheckBoxColumn
            {
                DataPropertyName = "",
                Name = "ColChecked",
                HeaderText = "勾選",
                Width = 100,
                Visible = true
            });

            dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
            {
                DataPropertyName = "DetailName",
                Name = "ColDetailName",
                HeaderText = "產品明細名稱",
                Width = 100,
                Visible = true,
                ReadOnly = true
            });
        }

        private void DataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
        {
            ((DataGridView)sender).AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
        }

        public void ShowDialog(string ProdName, DataTable dt)
        {

            dataGridView1.DataSource = dt;
            Text = $"{ProdName} 明細資料";
            UpdateStatus();

            this.ShowDialog();
        }

        private void DataGridView1_RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
        {
            // 在 RowHeader 標記資料序號
            using (SolidBrush b = new SolidBrush(dataGridView1.RowHeadersDefaultCellStyle.ForeColor))
            {
                e.Graphics.DrawString(
                    (e.RowIndex + 1).ToString(System.Globalization.CultureInfo.CurrentUICulture),
                    e.InheritedRowStyle.Font,
                    b,
                    e.RowBounds.Location.X + 20,
                    e.RowBounds.Location.Y + 4);
            }
        }

        private void DataGridView1_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode != Keys.Space) return;

            // 按 Space 鍵可以勾選 CheckBox
            // 測試時發現,一進入該 Form 時,Focus 是在 ColChecked Column 的 Cell 上,
            // 此時按 Space,會同時觸發 KeyDown 和 CellContentClick Event
            // 即使是在 SelectionMode = FullRowSelect 狀態下,Focus 還是用 Cell,而不是整筆 Row
            DataGridViewCell cell = dataGridView1.CurrentRow.Cells["ColChecked"];
            cell.Value = cell.Value == null ? true : !((bool)cell.Value);
        }

        private void DataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex < 0) return;

            DataGridView dgv = sender as DataGridView;

            if (e.ColumnIndex != dgv.Columns["ColChecked"].Index) return;

            UpdateStatus();
        }

        private void DataGridView1_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Escape)
                this.Close();
        }

        private void UpdateStatus()
        {
            int CheckedCount = dataGridView1.Rows.OfType<DataGridViewRow>().Where(r => (bool)r.Cells["ColChecked"].EditedFormattedValue == true).Count();
            toolStripStatusLabel1.Text = $"使用者勾選 {CheckedCount} 筆資料";
        }
    }
}
[C#] DataGridView 範例-1

沒有留言:

張貼留言