動態產生下拉式選取清單 - ContextMenuStrip 的應用

  • 7427
  • 0
  • C#
  • 2014-08-22

動態產生下拉式選取清單 - ContextMenuStrip 的應用

ContextMenuStrip 一般是用來與控制項產生關聯,透過按下滑鼠右鍵來顯顯示快速鍵功能表。但是在 ContextMenuStrip 中,有個 ToolStripComboBox 的控制項可以讓我們做到動態的下拉式選取清單。雖然這和原本的 ComboBox 很類似,但運用的時間就有所不同了。

 

比如說 TextBox 控制項因為有不得已的關係無法直接使用 Combox,但又希望使用者在輸入資料時,可以透過選取的方式來快速輸入資料,這時後 Combox 就無用武之地了。

或者是說在 DataGridView 的某一個欄位 Column 需要讓使用者透過選取的方式來輸入資料,但是不同資料行又必需要有不同的清單選項,相信使用過 DataGridView 控制項的人都知道,使用 DataGridView 中的 ComboxColumn 是做不到的,因為繫結的資料是統一的,無法依照不同資料行有不同的繫結資料來源。

這時後,就可以利用這個技巧,將 ContextMenuStrip 化身為 ComboBox 來使用。

 

測試環境

畫面上布置三個控制項,一個是 TextBox、一個是 DataGridView,還有一個是 ContextMenuStrip。

TextBox 沒有做什麼特別的設定,名稱變更為「TestTextBox」,新增一個 DoubleClick 事件 TestTextBox_DoubleClick。

 

DataGridView 的部份,取消 MultiSelect,名稱變更為「TestDataGridView」,啟用「加入」、「編輯」、「刪除」功能,一共設置了 5 個欄位。

新增一個 CellDoubleClick 事件 TestDataGridView_CellDoubleClick。

      欄位1:名稱為「colA」,顯示名稱為「TEST01」,欄寬 70,型態為 TextBoxColumn,啟用 ReadOnly,無任何資料繫結。

      欄位2:名稱為「colB」,顯示名稱為「TEST02」,欄寬 100,型態為 TextBoxColumn,啟用 ReadOnly,無任何資料繫結。

      欄位3:名稱為「colC」,顯示名稱為「TEST03」,欄寬 150,型態為 TextBoxColumn,啟用 ReadOnly,無任何資料繫結。

      欄位4:名稱為「colD」,顯示名稱為「TEST04」,欄寬為 AutoSizeMode - Fill,型態為 TextBoxColumn,啟用 ReadOnly,無任何資料繫結。

      欄位5:名稱為「colE」,顯示名稱為「TEST05」,欄寬 100,型態為 TextBoxColumn,啟用 ReadOnly,無任何資料繫結。

 

ContextMenuStrip 名稱變更為「TestContextMenu」,只新增一個項目,型態為 ComboBox,命名為 TestPopupMenu,無任何資料繫結。

ContextMenuStrip 新增一個 Closing 事件 TestContextMenu_Closing

TestPopupMenu 新增 SelectedIndexChanged 事件 TestPopupMenu_SelectedIndexChanged 和 KeyPress 事件 TestPopupMenu_KeyPress。

 

功能說明

在 TextBox 上使用滑鼠雙擊後,觸發 DoubleClick,然後將選項清單資料加入到 TestPopupMenu 的項目中, 計算出要顯示的位置資訊 (X, Y) 之後,透過 Show 方法將 ContextMenuStrup 顯示在 TextBox 的下方。

點選資料後,觸發 SelectedIndexChanged 或是手動輸入資料按下 Enter 鍵觸發 KeyPress 事件,將 ContextMenuStrip 關閉,同時間觸發了 Closing 事件。

在 Closing 事件中經由簡易的判斷,將選取的資料回寫到觸發控制項中。

 

相同的在 DataGridView 也是如此。奇數行的時後,可選取的資料為「選項x」。

偶數行的時後則選項變更為「x選項」。

 

程式碼 (TestDataGridView_CellDoubleClick)

private void TestDataGridView_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
    if (e.RowIndex < 0) return;
    int intX = TestDataGridView.RowHeadersWidth, intY = TestDataGridView.ColumnHeadersHeight;

    for (int i = 0; i <= e.RowIndex; i++) { intY += TestDataGridView.Rows[i].Height; }
    for (int i = 0; i < e.ColumnIndex; i++) { intX += TestDataGridView.Columns[i].Width; }

    switch (e.ColumnIndex)
    {
        case 0:
        case 2:
            if ((e.RowIndex % 2) == 0)
            {
                TestPopupMenu.Items.Clear();
                TestPopupMenu.Items.Add("選項一");
                TestPopupMenu.Items.Add("選項二");
                TestPopupMenu.Items.Add("選項三");
            }
            else
            {
                TestPopupMenu.Items.Clear();
                TestPopupMenu.Items.Add("A選項");
                TestPopupMenu.Items.Add("B選項");
                TestPopupMenu.Items.Add("C選項");
            }
            TestContextMenu.Tag = TestDataGridView.Name;
            TestContextMenu.Show(TestDataGridView, intX, intY);
            break;
        default:
            break;
    }
}

 

程式碼 (TestPopupMenu_SelectedIndexChanged)

private void TestPopupMenu_SelectedIndexChanged(object sender, EventArgs e)
{
    TestContextMenu.Close();
}

 

程式碼 (TestTextBox_DoubleClick)

private void TestTextBox_DoubleClick(object sender, EventArgs e)
{
    TestPopupMenu.Items.Clear();
    TestPopupMenu.Items.Add("方塊資料1");
    TestPopupMenu.Items.Add("方塊資料2");
    TestPopupMenu.Items.Add("方塊資料3");
    TestContextMenu.Tag = TestTextBox.Name;
    TestContextMenu.Show(TestTextBox,  0, TestTextBox.Height);
}

 

程式碼 (TestPopupMenu_KeyPress)

private void TestPopupMenu_KeyPress(object sender, KeyPressEventArgs e)
{
    if (e.KeyChar == 13) TestContextMenu.Close();
}

 

程式碼 (TestContextMenu_Closing)

private void TestContextMenu_Closing(object sender, ToolStripDropDownClosingEventArgs e)
{
    if (TestContextMenu.Tag.ToString() == TestDataGridView.Name)
    {
        if (TestDataGridView.NewRowIndex == TestDataGridView.CurrentRow.Index)
        {
            TestDataGridView.Rows.Add();
            TestDataGridView.Rows[TestDataGridView.CurrentCell.RowIndex - 1].Cells[TestDataGridView.CurrentCell.ColumnIndex].Value = TestPopupMenu.Text;
        }
        else
        {
            TestDataGridView.CurrentCell.Value = TestPopupMenu.Text;
        }
    }
    else if (TestContextMenu.Tag.ToString() == TestTextBox.Name)
    {
        TestTextBox.Text = TestPopupMenu.Text;
    }
}

程式是運氣與直覺堆砌而成的奇蹟。
若不具備這兩者,不可能以這樣的工時實現這樣的規格。
修改規格是對奇蹟吐槽的褻瀆行為。
而追加修改則是相信奇蹟還會重現的魯莽行動。