星期五, 7月 29, 2016

[C#] DataGridView 範例 II

這篇 MSDN 範例 DataGridView 控制項範例,下面這段 Code 是用來保留使用者點選 CheckBox 紀錄,一直想不透這段語法存在的用意,在這篇筆記 [C#] DataGridView 範例 內就把它跳過
namespace Microsoft.Samples.Windows.Forms.DataGridViewSample
{
    partial class CustomerOrdersForm : Form
    {
        private System.Collections.Generic.Dictionary<int, bool> checkState;

        public void ShowDialog(string customerID, IWin32Window parent, IBindingListView blist)
        {
            // The check box column will be virtual.
            dataGridView1.VirtualMode = true;
            dataGridView1.Columns.Insert(0, new DataGridViewCheckBoxColumn());

            // Initialize the dictionary that contains the boolean check state.
            checkState = new Dictionary<int, bool>();

            // Show the dialog.
            this.ShowDialog(parent);
        }

        private void dataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
        {
            // Handle the notification that the value for a cell in the virtual column
            // is needed. Get the value from the dictionary if the key exists.
            if (e.ColumnIndex == 0)
            {
                int orderID = (int)dataGridView1.Rows[e.RowIndex].Cells["OrderID"].Value;
                if (checkState.ContainsKey(orderID))
                {
                    e.Value = checkState[orderID];
                }
                else
                    e.Value = false;
            }
        }

        private void dataGridView1_CellValuePushed(object sender, DataGridViewCellValueEventArgs e)
        {
            // Handle the notification that the value for a cell in the virtual column
            // needs to be pushed back to the dictionary.
            if (e.ColumnIndex == 0)
            {
                // Get the orderID from the OrderID column.
                int orderID = (int)dataGridView1.Rows[e.RowIndex].Cells["OrderID"].Value;

                // Add or update the checked value to the dictionary depending on if the 
                // key (orderID) already exists.
                if (!checkState.ContainsKey(orderID))
                {
                    checkState.Add(orderID, (bool)e.Value);
                }
                else
                    checkState[orderID] = (bool)e.Value;
            }
        }
    }
}
後來閱讀文章內容時,才發現到這段文字
使用虛擬模式,在排序時保留未繫結資料行中的值。
測試後才了解,原來未繫結資料行的值,經過排序後就會消失不見,所以才需要記錄下來,排序後再把資料補上去,測試結果如下圖

[C#] DataGridView 範例 II-1

下面除了上述語法整合外,也紀錄不是 VirtualMode 情況下,保留未繫結資料行的值作法 - 在 CellContentClick 紀錄,在 Sort Event 觸發時把資料補回去

Porject 內只有一個 Form1,Form1 內只有一個 DataGridView 控件

[C#] DataGridView 範例 II-3
namespace DGVSample2
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private Dictionary<int, bool> CheckBoxState;

        private void CheckBoxStateHandle(int ID, bool CheckedState)
        {
            if (CheckBoxState.ContainsKey(ID))
                CheckBoxState[ID] = CheckedState;
            else
                CheckBoxState.Add(ID, CheckedState);
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            CheckBoxState = new Dictionary<int, bool>();

            dataGridView1.AutoGenerateColumns = false;
            dataGridView1.AllowUserToAddRows = false;
            dataGridView1.Dock = DockStyle.Fill;

            // VirtualMode 預設為 false
            // dataGridView1.VirtualMode = true;

            dataGridView1.DataSource = GetDataSource();

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

            dataGridView1.Columns.Add(new DataGridViewTextBoxColumn
            {
                DataPropertyName = "ID",
                Name = "ColID",
                HeaderText = "流水編號",
                Width = 100,
                Visible = true,
                SortMode = DataGridViewColumnSortMode.Automatic
            });

            dataGridView1.Sorted += DataGridView1_Sorted;
            dataGridView1.CellContentClick += DataGridView1_CellContentClick;
            dataGridView1.CellValueNeeded += DataGridView1_CellValueNeeded;
            dataGridView1.CellValuePushed += DataGridView1_CellValuePushed;
        }

        #region VirtualMode = false
        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;

            int ID = (int)dgv.Rows[e.RowIndex].Cells["ColID"].Value;
            Object obj = dgv.Rows[e.RowIndex].Cells["ColChecked"].EditedFormattedValue;
            bool CheckedState = (obj == null) ? false : (bool)obj;

            CheckBoxStateHandle(ID, CheckedState);
        }

        private void DataGridView1_Sorted(object sender, EventArgs e)
        {
            foreach (DataGridViewRow row in dataGridView1.Rows)
            {
                int ID = (int)row.Cells["ColID"].Value;
                if (CheckBoxState.ContainsKey(ID) == false) continue;
                row.Cells["ColChecked"].Value = CheckBoxState[ID];
            }

            dataGridView1.EndEdit();
        }
        #endregion

        #region VirtualMode = true
        private void DataGridView1_CellValuePushed(object sender, DataGridViewCellValueEventArgs e)
        {
            // Handle the notification that the value for a cell in the virtual column
            // needs to be pushed back to the dictionary.
            if (e.ColumnIndex == 0)
            {
                // Get the orderID from the OrderID column.
                int ID = (int)dataGridView1.Rows[e.RowIndex].Cells["ColID"].Value;
                CheckBoxStateHandle(ID, (bool)e.Value);
            }
        }

        private void DataGridView1_CellValueNeeded(object sender, DataGridViewCellValueEventArgs e)
        {
            // Handle the notification that the value for a cell in the virtual column
            // is needed. Get the value from the dictionary if the key exists.
            if (e.ColumnIndex == 0)
            {
                int ID = (int)dataGridView1.Rows[e.RowIndex].Cells["ColID"].Value;
                if (CheckBoxState.ContainsKey(ID))
                    e.Value = CheckBoxState[ID];
                else
                    e.Value = false;
            }
        } 
        #endregion

        private DataTable GetDataSource()
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("Checked", typeof(bool));
            dt.Columns.Add("ID", typeof(int));
            dt.Rows.Add(false, 1);
            dt.Rows.Add(false, 2);
            dt.Rows.Add(false, 3);
            dt.Rows.Add(false, 4);
            dt.Rows.Add(false, 5);
            return dt;
        }
    }
}
[C#] DataGridView 範例 II-2

沒有留言:

張貼留言