none
色を選択できる DataGridViewComboBoxColumn / Cell を作りたい RRS feed

  • 全般的な情報交換

  • - 方法 : ComboBox コントロールにサイズ変更可能なテキストを作成する

     

    を参考に、色を選択できる DataGridViewComboBoxColumn / Cell を組み込んで
    みました。でも、未達です。


    何が未達かというと、

    1. ComboBox で色の選択後に、Cell の BackColor を選択色に変えられない
    2. あらかじめ色 Item をもつ拡張コントロール ColoredComboBox を流用したい
    3. ComboBox.DrawItem イベントハンドラを削除できない

    以上のことを解決したいのですが、どうにも分かりません。

    どうやったら実現できるのか、お知恵をお貸しください。

     

    + 追記

    1 への対応を追記していますが、それが正しい処理かどうか不明なので、

    詳しい方の助言を期待します。

     

     

    参考画像 (1) 最初の画面

     

    参考画像 (2) GetFormattedValue() 追加後

     

     

    サンプルコード

    Code Snippet

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;

     

    namespace DrawColoringComboBoxItems
    {
      public class ColoredComboBoxColumn : DataGridViewComboBoxColumn
      {
        public ColoredComboBoxColumn()
          : base()
        {
          base.CellTemplate = new ColoredComboBoxCell();
        }

     

        public override DataGridViewCell CellTemplate
        {
          get
          {
            return base.CellTemplate;
          }
          set
          {
            if (value != null

              && !value.GetType().IsAssignableFrom(typeof(ColoredComboBoxCell)))
            {
              throw new InvalidCastException("Must be a ColoredComboBoxCell");
            }
            base.CellTemplate = value;
          }
        }
      }

     

      public class ColoredComboBoxCell : DataGridViewComboBoxCell
      {
        public ColoredComboBoxCell()
          : base()
        { }

     

        public override void InitializeEditingControl(
          int rowIndex,
          object initialFormattedValue,
          DataGridViewCellStyle dataGridViewCellStyle)
        {
          base.InitializeEditingControl(

            rowIndex, initialFormattedValue, dataGridViewCellStyle);

     

          ComboBox comboBox = this.DataGridView.EditingControl as ComboBox;

     

          if (comboBox != null)
          {
            comboBox.DrawMode = DrawMode.OwnerDrawFixed; ........................... (1)
            comboBox.DrawItem -= new DrawItemEventHandler(comboBox_DrawItem);

            comboBox.DrawItem += new DrawItemEventHandler(comboBox_DrawItem); ...... (2)
          }
        }

     

        private void comboBox_DrawItem(object sender, DrawItemEventArgs e)
        {
          if (e.Index >= 0)
          {
            ComboBox comboBox = (ComboBox)sender;
            string colorName  = comboBox.Items[e.Index].ToString();
            Color color       = this.getColor(colorName);
            Rectangle rect    = e.Bounds;

     

            e.Graphics.FillRectangle(new SolidBrush(color), rect);

     

            StringFormat fmt = new StringFormat();
            fmt.Alignment = StringAlignment.Near;
            fmt.LineAlignment = StringAlignment.Near;
            e.Graphics.DrawString(colorName, comboBox.Font, Brushes.White, rect, fmt);
          }
        }

     

        protected override object GetFormattedValue(
          object value,
          int rowIndex,
          ref DataGridViewCellStyle cellStyle,
          System.ComponentModel.TypeConverter valueTypeConverter,
          System.ComponentModel.TypeConverter formattedValueTypeConverter,
          DataGridViewDataErrorContexts context)
        {
          if (value != null)
          {
            cellStyle.BackColor = this.getColor(value.ToString());
          }
         
          return base.GetFormattedValue(
            value, rowIndex, ref cellStyle, valueTypeConverter,

            formattedValueTypeConverter, context);
        }

     

        private Color getColor(string colorName)
        {
          switch (colorName.ToUpper())
          {
            case "RED"     : return Color.Red;
            case "ORANGE"  : return Color.Orange;
            case "YELLOW"  : return Color.Yellow;
            case "GREEN"   : return Color.Green;
            case "BLUE"    : return Color.Blue;
            case "NAVY"    : return Color.Navy;
            case "PURPLE"  : return Color.Purple;
            default        : return Color.White;
          }
        }
      }
    }

    (1)
    元々 DataGridViewComboBoxColumn / Cell では DrawMode は使えないのですが、
    cast して強引に呼び出しています。
    (2)
    DrawItem で描画を行うようにイベントハンドラを設定しています。

     

    追記 (2008-03-18)

    他スレッド (DataGridViewComboBox にイメージを表示するには) のアドバイスを採用。


    追加 (2008-03-18)

    GetFormattedValue() を追加して、DataGridViewComboBoxEditingControl から
    の値を色付けの判定に使うようにした。

     

    2008年3月16日 16:18

すべての返信

  • custarさん、果敢に挑戦されていますね。
     カスタムコントロールをDataGridViewで使う方法については以下のページが参考になると思います。
     私も同様のことをしようとしていますが全く別の原因で引っかかっています。
     custarさんの場合は素直にComboBoxを拡張なさっているのですんなりいくような気がします。

    http://msdn2.microsoft.com/ja-jp/library/system.windows.forms.idatagridvieweditingcontrol(VS.80).aspx
    http://dobon.net/vb/dotnet/datagridview/maskedtextboxcolumn.html

    追記
     あれ?、既にやっておられますね。
     どこかで引っかかったのでしょうか。
     
    http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=2723834&SiteID=7

    2008年3月18日 5:43
  • 三輪の牛 さん、情報ありがとうございます。


    まさしくこちらでも CalendarColumn を参考に組んでいます。いずれも取るべ
    き手順は同じでしょう。


    但し、今回私がやっているのは、既存の DataGridViewComboBox に、あらかじ
    め色 Item を付けて表示させるだけ、という点が違います。

    • CaledarColumn の例ならば、土日のセルの背景色を付けて DateTimePicker を表示させたり、
    • MaskedTextbox の例ならば、既存データとバインドしてあらかじめ代入させて表示させたり

    するようなことをやろうとしています。


     

    DataGridViewComboBoxEditingControl をどう扱うか、考えていたところです。


    既に IDataGridViewEditingControl を実装しているであろう
    DataGridViewComboBoxEditingControl を継承しないのはもったいないんじゃないかと。


    単に、DataGridViewComboBoxEditingControl を継承したものが、あらかじめ色
    Item をもつ EditingControl であればいいだけなんじゃないかと。

     

    既に ColoredCombBox は実装済みなので。

     

     

     

    追記 (2008-03-18)

    Code Snippet

    - DataGridViewComboBoxEditingControl クラス (System.Windows.Forms)

     

    EditingControlShowing イベントを処理すると、
    セルが編集モードになったときに、編集コントロールのカスタムの初期化を実行できます。

     

    ...ということは、EditingControl への ColoredComoboBox 継承は無し!?
    # そうは言われても、出来ると密かに予想しています。

     

    ColoredComboBoxColumn.cs を DataGridView から分離できないのかも。

    ま、ColoredComboBoxColumn を含んだ拡張 DataGridView にすればいいだけですが。


     

    Code Snippet

    コントロールの表示特性をカスタマイズするには、
     

      DataGridViewEditingControlShowingEventArgs.Control プロパティ
        によって返されるコントロールのプロパティを設定するのではなく、

     

      DataGridViewEditingControlShowingEventArgs.CellStyle プロパティ
        によって返されるオブジェクトのプロパティを設定します。

     

    留意点。

    2008年3月18日 6:12
  •  三輪の牛 さんからの引用

    追記
     あれ?、既にやっておられますね。
     どこかで引っかかったのでしょうか。
     
    http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=2723834&SiteID=7


    (1) 1つの DataGridViewCell で複数のコントロールをホストするには
    (2) 標準の DataGridViewCell より大きい UserControl を常時ホストする場合、行の高さや列の幅を調整するには


    (1) はトーンダウンしています。下記 (2) をメインにしようとしてます。
    何故なら応用が利きそうだから。


    しかし、編集時に UserControl をセル上に被せる、という (1)、(2) のや
    り方にしっくり感がないので、ホストしようかと考え出しています。

    2008年3月18日 6:23
  • DataGridViewComboBoxEditingControlを継承して利用するのですか。
     DataGridViewComboBoxEditingControl is-a ComboBoxなので、折角作ったColoredComboBoxが利用できないと思います。
     DataGridViewComboBoxCellやDataGridViewComboBoxColumnの方を継承して利用するのはOKと予想しています。
     コンボボックスのための仕組みを利用しないと委譲コードが多くなりそうですから、うまく利用して減らしたいですね。


    2008年3月18日 7:39
  •  三輪の牛 さんからの引用

    DataGridViewComboBoxEditingControl を継承して利用するのですか。


    そのつもりです。


     三輪の牛 さんからの引用

    DataGridViewComboBoxEditingControl is-a ComboBox なので、
    折角作った ColoredComboBox が利用できないと思います。


    色付き ComboBox ってどうやって作るんだ?という疑問からの試作ですから、
    色付け部分のみ流用します。


     三輪の牛 さんからの引用

    DataGridViewComboBoxCell や DataGridViewComboBoxColumn の方を継承して利用するのは OK と予想しています。


    はい。


     三輪の牛 さんからの引用

    コンボボックスのための仕組みを利用しないと委譲コードが多くなりそうです
    から、うまく利用して減らしたいですね。


    大凡 (おおよそ) の実装は済みましたが、値の引き渡しのところ辺りで例外発生中です。
    選択後の色名が出なくなってしまいました。

    ColoredComboBox を組み込む前までは何も出ませんでしたが。

     

     

    Code Snippet

    public class ColoredComboBoxCell : DataGridViewComboBoxCell
    {
      public ColoredComboBoxCell()
        : base()
      { }

     

      public override void InitializeEditingControl(
        int rowIndex,
        object initialFormattedValue,
        DataGridViewCellStyle dataGridViewCellStyle)
      {
        base.InitializeEditingControl(

          rowIndex, initialFormattedValue, dataGridViewCellStyle);

        ColoredComboBox comboBox = this.DataGridView.EditingControl as ColoredComboBox;

     

        if (comboBox != null)
        {
          comboBox.SelectedValue = (this.Value != null) ? this.Value.ToString() : null;

     

          comboBox.activate(); ..................................................... (3)
        }
      }

     

      public override Type EditType
      {
        get { return typeof(ColoredComboBox); }
      }

     

      protected override object GetFormattedValue(
        object value,
        int rowIndex,
        ref DataGridViewCellStyle cellStyle,
        System.ComponentModel.TypeConverter valueTypeConverter,
        System.ComponentModel.TypeConverter formattedValueTypeConverter,
        DataGridViewDataErrorContexts context)
      {
        if (value != null)
        {
          cellStyle.BackColor = ColoredComboBox.getColor(value.ToString());
        }

     

        return base.GetFormattedValue(
          value, rowIndex, ref cellStyle, valueTypeConverter,
          formattedValueTypeConverter, context);
      }

    }

     

    public class ColoredComboBox : DataGridViewComboBoxEditingControl
    {
      public ColoredComboBox()
        : base()
      { }

     

      ~ColoredComboBox()
      {
        this.Items.Clear();
      }

     

      public void activate()
      {
        this.Items.AddRange(
    new object[] {

          "", "Red", "Orange", "Yellow", "Green", "Blue", "Navy", "Purple" });
        this.DrawMode = DrawMode.OwnerDrawFixed;
      }

     

      protected override void OnDrawItem(DrawItemEventArgs e)
      {
        base.OnDrawItem(e);

     

        if (e.Index >= 0)
        {
          string colorName = this.Items[e.Index].ToString();
          Color color = ColoredComboBox.getColor(colorName);
          Rectangle rect = e.Bounds;

     

          e.Graphics.FillRectangle(new SolidBrush(color), rect);

     

          StringFormat fmt = new StringFormat();
          fmt.Alignment = StringAlignment.Near;
          fmt.LineAlignment = StringAlignment.Near;
          e.Graphics.DrawString(colorName, this.Font, Brushes.White, rect, fmt);
        }
      }

     

      public static Color getColor(string colorName)
      {
        switch (colorName.ToUpper())
        {
          case "RED"    : return Color.Red;
          case "ORANGE" : return Color.Orange;
          case "YELLOW" : return Color.Yellow;
          case "GREEN"  : return Color.Green;
          case "BLUE"   : return Color.Blue;
          case "NAVY"   : return Color.Navy;
          case "PURPLE" : return Color.Purple;
          default       : return Color.White;
        }
      }
    }

     


    元々 DataGridView.EditingControl は DataGridViewComboBoxEditingControl
    なので、色付き Item なんてもっていません。(3) で色付き Item を追加する
    処理を呼び出しています。


    なんか他にやり方がありそうなんですけど。

     

     

    + 追記

    色 Items を一々追加するのが面倒なので、それをもつクラスを作ろうとしたけど、

    失敗中。そこまでしなければ出来ているので、後日、時間の空いた時に取り掛かる。

    一旦閉じます。

     

    三輪の牛 さん、アドバイスありがとうございます。

    2008年3月18日 8:34
  • 関連情報

     

    - CodeGuru: ColorComboBox


     

    本件は、今であれば ColorDialog を使うのですが、当時はその存在を知らなかった。

    2008年7月21日 4:05