WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

DataGridView に ComboBox を表示

by WebSurfer 2014年1月23日 15:26

DataGridView の特定の列を ComboBox を使って表示する方法を備忘録として書いておきます。

DataGridView に ComboBox を表示

Northwind サンプルデータベースの Products テーブルを例に使い、上の画像のように Category 列と Supplier 列を ComboBox を使って表示します。

Products テーブルを DataGridView に表示して更新操作ができるようにするだけなら、自分でコードは一行も書かなくても、Visual Studio のウィザードを使ってドラッグ&ドロップ操作だけで Windows Form アプリを作成できます。

ただし、Products テーブルの中の CategoryID, SupplierID は ID(数字)で表示されるので、そのままではユーザーにとっては分かりにくいです。

ID に代えて、名前を Categories, Suppliers テーブルから取得して表示した方がユーザーにとっては分かりやすいはずです。

さらにユーザーがデーターベースを編集・更新する場合は、ComboBox を使用してドロップダウン形式で一覧を表示し、その中からユーザーが選択できるようにするとさらにユーザーフレンドリーになると思います。

今回の例では、CategoryID, SupplierID 列に ComboBox を使い、各行の CategoryID, SupplierID に該当する名前(CategoryName, CompanyName)を Categories, Suppliers テーブルから取得して ComboBox に表示するようにします。

Category 列の方は Visual Studio のウィザードを利用して、自力では一行もコードを書かずに ComboBox を実装してみます。

Supplier 列の方は自力でコードを書いて DataTable を作成し、それを ComboBox の DataSource に設定することにします。

以下にその手順を書きます。

  1. Visual Studio の[ファイル(F)]⇒[新しいプロジェクト(P)...]メニューから[Windows フォームアプリケーション]テンプレートを使って空のプロジェクトを作成する。
  2. ソリューションエクスプローラーでプロジェクトのルートを右クリック。[追加(D)]⇒[新しい項目(W)...]⇒[データセット]で適当な名前(例えば NorthwindDataSet.xsd)をつけて空の xsd ファイルを作成。(注:下の画像はステップ 12 まで進んだ時の完成済みのデータセットで、このステップの時点では何も表示されていません)

NorthwindDataSet.xsd ファイル

  1. ツールボックスから TableAdapter をドラッグ&ドロップすると TableAdapter 構成ウィザードが立ち上がる。
  2. クエリビルダで以下の SELECT クエリを作り、これをベースに DataTable + TableAdapter を作る。

    SELECT ProductID, ProductName, CategoryID, SupplierID,
    UnitPrice, Discontinued FROM Products

    DataGridView に表示するとともに編集・更新操作を行うのはこれなので、TableAdapter 内に作成する更新系のメソッド等の生成オプションはフルにチェックを入れておく。
  3. TableAdapter 構成ウィザードでの操作が完了すると、ProductsDataTable と ProductsTableAdapter が自動生成されているはず。(上の NorthwindDataSet.xsd ファイルの画像で、左側の箱)
  4. Form1.cs を開きそのデザイン画面を表示する。データソースウィンドウを開くとその中に Products という項目があるはずなので、それを Form にドラッグ&ドロップする。
  5. 上のステップまでで、Products テーブルの表示、編集、更新ができるアプリが完成するはず。とりあえずこの段階で DataGridView への表示、レコードの INSERT, DELETE, UPDATE が問題なくできることを確認しておく。
  6. 上記が確認できたら、最初に Category の方を ComboBox で表示するための設定を行う。
  7. 自力でコードを書くのは必要最小限にするため、TableAdapter 構成ウィザードを利用して DataTable + TableAdapter を作り、これを利用する。
  8. NorthwindDataSet.xsd ファイルを開き、ツールボックスからもう一つ TableAdapter をドラッグ&ドロップする。
  9. TableAdapter 構成ウィザードが立ち上がるので、クエリビルダで以下の SELECT クエリを作り、これをベースに DataTable + TableAdapter を作成する。

    SELECT CategoryID, CategoryName FROM Categories

    こちらは、CategoryID に該当する CategoryName を ComboBox を使って表示するためのデーターソースとして利用するだけなので、TableAdapter に更新系のメソッドは不要。
  10. TableAdapter 構成ウィザードでの操作が完了すると、CategoriesDataTable と CategoriesTableAdapter が自動生成されているはず。(上の NorthwindDataSet.xsd ファイルの画像で、右側の箱)
  11. DataGridView の列の編集画面で、CatrgoryID 列の ColumnType を DataGridViewComboBoxColumn に変更する。

列の編集画面その1

  1. 上の画面で、DataSource を[他のデータソース]⇒[プロジェクトデータソース]⇒[NorthwindDataSet]⇒[Catrgories]に設定すると、自動的に categoriesBindingSource が生成され、DataSource に設定される。
  2. 次に、DisplayMember を CategoryName に、ValueMember を CategoryID に設定する。

列の編集画面その2

  1. ここまでの操作で、Category の方は ComboBox で表示され、編集する際は ComboBox をドロップダウンしてその中から選択して更新をかけることが可能になるはず。
  2. 次に、Supplier の方を ComboBox に表示するための設定を行う。こちらは TableAdapter 構成ウィザードを使用しないで、自力でコードを書いて DataTable を作り、それをデーターソースに利用してみる。
  3. Category の場合と同様に、DataGridView の列の編集画面で、SupplierID 列の ColumnType を DataGridViewComboBoxColumn に変更する。
  4. その先は自力でコードを書いて DataTable を作成し、それを DataGridViewComboBoxColumn の DataSource に設定する。
  5. Form1.cs のコード画面を開く。
  6. ADO.NET のライブラリを使い、Suppliers テーブルから SupplierID, CompanyName を取得し DataTable を作成するコードを追加する。具体例は以下のサンプルコードの CreateSuppliersTable を参照。
  7. Form1_Load メソッド(自動生成されているはず)の中に、上記 18 の手順で作成した DataGridViewComboBoxColumn の DataSource プロパティを CreateSuppliersTable メソッドが返す DataTable に、DisplayMember プロパティを "CompanyName" に、ValueMember プロパティを "SupplierID" に設定する。具体例は以下のサンプルコードを参照。
  8. 以上の操作で、一番上の画像のアプリが完成するはずです。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;  // 要追加

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

    private void productsBindingNavigatorSaveItem_Click(
        object sender, EventArgs e)
    {
      this.Validate();
      this.productsBindingSource.EndEdit();
      this.tableAdapterManager.UpdateAll(
          this.northwindDataSet);
    }

    private void Form1_Load(object sender, EventArgs e)
    {
      this.categoriesTableAdapter.Fill(
          this.northwindDataSet1.Categories);
      this.productsTableAdapter.Fill(
          this.northwindDataSet.Products);
      // ここまでのコードは Visual Studio のウィザードで
      // 自動生成される。


      // ここから下のコードを自力で書いて追加する。

      // DataSource に設定するのは Supplier の ComboBox に
      // 表示するデータを含む DataTable。下のヘルパーメソッ
      // ド CreateSuppliersTable で作成。
      this.dataGridViewTextBoxColumn4.DataSource = 
          CreateSuppliersTable();
      this.dataGridViewTextBoxColumn4.DisplayMember = 
          "CompanyName";
      this.dataGridViewTextBoxColumn4.ValueMember = 
          "SupplierID";
    }

    // Suppliers テーブルから SupplierID, CompanyName を抽出
    // して DataTable を作るためのヘルパーメソッド。
    private DataTable CreateSuppliersTable()
    {
      DataTable table = new DataTable("Suppliers");
      table.Columns.Add(
            new DataColumn("SupplierID", typeof(int)));
      table.Columns.Add(
            new DataColumn("CompanyName", typeof(string)));

      string connString = DataGridViewComboBox.Properties.
          Settings.Default.NORTHWNDConnectionString;
      string query = 
          "SELECT SupplierID, CompanyName FROM Suppliers " + 
          "ORDER BY SupplierID";

      using (SqlConnection conn = new SqlConnection(connString))
      {
        conn.Open();
        using (SqlCommand cmd = new SqlCommand(query, conn))
        {
          using (SqlDataReader reader = cmd.ExecuteReader())
          {
            if (reader != null)
            {
              while (reader.Read())
              {
                DataRow row = table.NewRow();
                row["SupplierID"] = reader.GetInt32(0);
                row["CompanyName"] = reader.GetString(1);
                table.Rows.Add(row);
              }
            }
          }
        }
      }
      return table;
    }

  }
}

Tags: , ,

.NET Framework

ACT ComboBox の日本語対応

by WebSurfer 2012年3月18日 16:50

AJAX Control Toolkit (ACT) の ComboBox は日本語に対応していませんが、それを無理やり(?)、ブラウザが IE のみの場合に限り、日本語対応させてみました。

日本語対応させた AJAX Control Toolkit の ComboBox

ヒントは MDSN の Visual Studio 共通フォーラムのスレッド「AJAX ComboBoxコントロール 日本語」にありました。

ComboBox は、テキストボックス(html コードで言うと <input type="text" ... />)の onkeypress イベントで、入力された文字列をリスト(html で言うと ul, li 要素を使った一覧)の中の文字列と比較していますが、IME が ON の時は onkeypress イベントが発生しないのがうまくいかない原因のようです。

その Workaround は、IE のみの場合ですが、以下の通りです。

  1. IME モードが ON のときは onkeypress イベントが発生しないので、代わりに onkeyup イベントを利用する。そのため _onTextBoxKeyUp イベントハンドラを作成し、テキストボックスの onkeyup イベントにアタッチする。
  2. _onTextBoxKeyDown イベントハンドラで、Keycode を取得しておく(IME モード ON の時は 229 になる)。
  3. _onTextBoxKeyUp イベントハンドラで、上記 ② で取得した Keycode が 229 で、かつ KeyCode が 13(ENTER) のとき(文字変 換を確定)に、_onTextBoxKeyPress イベントハンドラを実行する。

AJAX Control Toolkit のソースコードは CodePlex のサイトから入手できます。今回の場合は、JavaScript のコード ComboBox.pre.js を入手して、関係する部分を書き換えて差し替えてやります。

具体的には以下の通りです。実際に動かして試せるよう 実験室 にアップしましたので、興味のある方は試してみてください。

<%@ Page Language="C#" %>
<%@ Import Namespace="AjaxControlToolkit" %>
<%@ Import Namespace="System.Data" %>
<%@ Register
    Assembly="AjaxControlToolkit"
    Namespace="AjaxControlToolkit"
    TagPrefix="ajaxToolkit" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

  private static string[] japaneseWordListText;
  public string[] GetJapaneseWordListText()
  {
    if (null == japaneseWordListText)
    {
      string[] tempWordListText = new string[] {
        "あいうえお",
        "かきくけこ",
        "さしすせそ",
        "たちつてと",
        "なにぬねの",
        "はひふへほ",
        "まみむめも",
        "abcdef",
        "日本語",
        "東京都",
        "神奈川県"
      };            
      japaneseWordListText = tempWordListText;
    }
    return japaneseWordListText;
  }

  private static string[] wordListText;
  public string[] GetWordListText()
  {
    if (null == wordListText)
    {
      string[] tempWordListText = new string[] {
        "Alfa",
        "Alpha",
        "Bravo",
        "Charlie",
        "Delta",
        "Echo",
        "Foxtrot",
        "Golf",
        "Hotel",
        "India",
        "Juliett",
        "Juliet",
        "Kilo",
        "Lima",
        "Mike",
        "November",
        "Oscar",
        "Papa",
        "Quebec",
        "Romeo",
        "Sierra",
        "Tango",
        "Uniform",
        "Victor",
        "Whiskey",
        "X-ray",
        "Xray",
        "Yankee",
        "Zulu",
        "Zero",
        "Nadazero",
        "One",
        "Unaone",
        "Two",
        "Bissotwo",
        "Three",
        "Terrathree",
        "Four",
        "Kartefour",
        "Five",
        "Pantafive",
        "Six",
        "Soxisix",
        "Seven",
        "Setteseven",
        "Eight",
        "Oktoeight",
        "Nine",
        "Novenine"
      };
      Array.Sort(tempWordListText);
      wordListText = tempWordListText;
    }
    return wordListText;
  }
    
  protected void Page_Load(object sender, EventArgs e)
  {
    if (!Page.IsPostBack)
    {
      ComboBox1.DataSource = GetWordListText();
      ComboBox1.DataBind();

      ComboBox3.DataSource = GetJapaneseWordListText();
      ComboBox3.DataBind();
    }
  }

  protected void Button1_Click(object sender, EventArgs e)
  {
    Label1.Text = ComboBox1.SelectedItem.Text;
  }

  protected void Button3_Click(object sender, EventArgs e)
  {
    Label3.Text = ComboBox3.SelectedItem.Text;
  }
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
  <title>AJAX Control Toolkit ComboBox の日本語対応</title>
</head>
<body>
  <form id="form1" runat="server">
  <ajaxToolkit:ToolkitScriptManager 
    ID="ToolkitScriptManager1" 
    runat="server">
  </ajaxToolkit:ToolkitScriptManager>

  <div>
    <ajaxToolkit:ComboBox ID="ComboBox1" 
      runat="server"
      AutoCompleteMode="SuggestAppend">
    </ajaxToolkit:ComboBox>
    <asp:Button ID="Button1" 
      runat="server" 
      Text="Button" 
      OnClick="Button1_Click" />
    <asp:Label ID="Label1" runat="server">
    </asp:Label>        
  </div>

  <div>
    <ajaxToolkit:ComboBox ID="ComboBox3" 
      runat="server"
      AutoCompleteMode="SuggestAppend">
    </ajaxToolkit:ComboBox>
    <asp:Button ID="Button3" 
      runat="server" 
      Text="Button" 
      OnClick="Button3_Click" />
    <asp:Label ID="Label3" runat="server">
    </asp:Label>        
  </div>
  </form>

  <script type="text/javascript">
  //<![CDATA[

  Sys.Extended.UI.ComboBox.prototype.createDelegates = function () {
    // ①
    // IME モードが ON のときは onkeypress イベントが発生
    // しない為、代わりに onkeyup イベントを利用。
    this._textBoxKeyUpHandler = 
      Function.createDelegate(this, this._onTextBoxKeyUp);

    // ここから下はオリジナルのコードそのまま。
    this._listMouseOverHandler = 
      Function.createDelegate(this, this._onListMouseOver);
    this._listMouseOutHandler = 
      Function.createDelegate(this, this._onListMouseOut);
    this._listMouseDownHandler = 
      Function.createDelegate(this, this._onListMouseDown);
    this._listClickHandler = 
      Function.createDelegate(this, this._onListClick);
    this._listDragHandler = 
      Function.createDelegate(this, this._onListDrag);
    this._listSelectStartHandler = 
      Function.createDelegate(this, this._onListSelectStart);
    this._listMouseWheelHandler = 
      Function.createDelegate(this, this._onListMouseWheel);
    this._textBoxClickHandler = 
      Function.createDelegate(this, this._onTextBoxClick);
    this._textBoxFocusHandler = 
      Function.createDelegate(this, this._onTextBoxFocus);
    this._textBoxBlurHandler = 
      Function.createDelegate(this, this._onTextBoxBlur);
    this._textBoxKeyPressHandler = 
      Function.createDelegate(this, this._onTextBoxKeyPress);
    this._textBoxKeyDownHandler = 
      Function.createDelegate(this, this._onTextBoxKeyDown);
    this._buttonClickHandler = 
      Function.createDelegate(this, this._onButtonClick);
    this._buttonBlurHandler = 
      Function.createDelegate(this, this._onButtonBlur);
    this._buttonKeyDownHandler = 
      Function.createDelegate(this, this._onButtonKeyDown);

    this._buttonKeyPressHandler = 
      Function.createDelegate(this, this._onButtonKeyPress);
    this._documentClickHandler = 
      Function.createDelegate(this, this._onDocumentClick);
    this._documentMouseWheelHandler = 
      Function.createDelegate(this, this._onDocumentMouseWheel);
    this._popupShowingHandler = 
      Function.createDelegate(this, this._popupShowing);
    this._popupShownHandler = 
      Function.createDelegate(this, this._popupShown);
    this._popupHidingHandler = 
      Function.createDelegate(this, this._popupHiding);
  };

  Sys.Extended.UI.ComboBox.prototype.clearDelegates = function () {
    // ①
    // IME モードが ON のときは onkeypress イベントが発生
    // しない為、代わりに onkeyup イベントを利用。
    this._textBoxKeyUpHandler = null;

    // ここから下はオリジナルのコードそのまま。
    this._listMouseOverHandler = null;
    this._listMouseOutHandler = null;
    this._listMouseDownHandler = null;
    this._listClickHandler = null;
    this._listDragHandler = null;
    this._listSelectStartHandler = null;
    this._listMouseWheelHandler = null;
    this._textBoxClickHandler = null;
    this._textBoxFocusHandler = null;
    this._textBoxBlurHandler = null;
    this._textBoxKeyPressHandler = null;
    this._textBoxKeyDownHandler = null;
    this._buttonClickHandler = null;
    this._buttonBlurHandler = null;
    this._buttonKeyDownHandler = null;
    this._buttonKeyPressHandler = null;
    this._documentClickHandler = null;
    this._documentMouseWheelHandler = null;
    this._popupShowingHandler = null;
    this._popupShownHandler = null;
    this._popupHidingHandler = null;
  };

  Sys.Extended.UI.ComboBox.prototype.addHandlers = function () {

    var optionListControl = this.get_optionListControl();

    $addHandlers(
      optionListControl,
      {
        'mouseover': this._listMouseOverHandler,
        'mouseout': this._listMouseOutHandler,
        'mousedown': this._listMouseDownHandler,
        'click': this._listClickHandler,
        'drag': this._listDragHandler,
        'selectstart': this._listSelectStartHandler
      },
      this);

    $addHandlers(
      this.get_textBoxControl(),
      {
        // ①
        // IME モードが ON のときは onkeypress イベントが発生
        // しない為、代わりに onkeyup イベントを利用。
        // これ以外はオリジナルのコードそのまま。
        "keyup": this._textBoxKeyUpHandler,

        "click": this._textBoxClickHandler,
        "focus": this._textBoxFocusHandler,
        "blur": this._textBoxBlurHandler,
        "keypress": this._textBoxKeyPressHandler
      }, 
      this);

    if (Sys.Browser.agent == Sys.Browser.InternetExplorer ||
      Sys.Browser.agent === Sys.Browser.Safari ||
      Sys.Browser.agent === Sys.Browser.WebKit) {
      $addHandler(
        this.get_textBoxControl(),
        "keydown", 
        this._textBoxKeyDownHandler);
    }

    $addHandlers(
      this.get_buttonControl(),
      {
        'click': this._buttonClickHandler,
        'blur': this._buttonBlurHandler,
        'keydown': this._buttonKeyDownHandler,
        'keypress': this._buttonKeyPressHandler
      }, 
      this);

    $addHandler(
      document,
      'click', 
      this._documentClickHandler);

    if (typeof (optionListControl.onmousewheel) === 'undefined') {
      $addHandler(
        optionListControl,
        'DOMMouseScroll', 
        this._listMouseWheelHandler);
      $addHandler(
        document,
        'DOMMouseScroll', 
        this._documentMouseWheelHandler);
    }
    else {
      $addHandler(
        optionListControl,
        'mousewheel', 
        this._listMouseWheelHandler);
      $addHandler(
        document,
        'mousewheel', 
        this._documentMouseWheelHandler);
    }
  };

  var keycodeOnTextBoxKeyDown = "";

  Sys.Extended.UI.ComboBox.prototype._onTextBoxKeyDown = function (e) {

    // ②
    // _onTextBoxKeyDown 時に Keycode を取得
    // (IME モード ON の時は 229)
    keycodeOnTextBoxKeyDown = this._getKeyboardCode(e);

    // ここから下はオリジナルのコードそのまま。
    var enterResult = this._handleEnterKey(e);
    if (enterResult != null) {
      return enterResult;
    }

    this._handleArrowKey(e);

    var erasureKeyResult = this._handleErasureKeys(e);
    if (erasureKeyResult != null) {
      return erasureKeyResult;
    }

    return true;

  };

  // ①
  // IME モードが ON のときは onkeypress イベントが発生
  // しない為、代わりに onkeyup イベントを利用。
  Sys.Extended.UI.ComboBox.prototype._onTextBoxKeyUp = function (e) {

    // ③
    // onkeyup時に②で取得した Keycode が 229 で
    // かつ KeyCode が 13(ENTER)のときに(文字変
    // 換を確定)、_onTextBoxKeyPress を Call する。
    if (keycodeOnTextBoxKeyDown == 229 && e.keyCode == 13) {
      this._onTextBoxKeyPress(e);
    }
  };

  //]]>  
  </script>
</body>
</html>

Tags: , ,

AJAX

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。

Calendar

<<  2024年4月  >>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar