2

以前に入力された項目を記憶する WinForms ComboBox があります。以前のエントリを削除する方法が必要です。ComboBox の DrawItem イベントをオーバーライドして、X アイコンと共にテキストをレンダリングします。X アイコンは、アイテムの高さに合わせた正方形の画像です。コードはかなり簡単です。

// Enable the owner draw on the ComboBox.
ServerComboBox.DrawMode = DrawMode.OwnerDrawFixed;
// Handle the DrawItem event to draw the items.
ServerComboBox.DrawItem += delegate(object cmb, DrawItemEventArgs args)
{
    // Draw the default background
    args.DrawBackground();

    String url = (String)ServerComboBox.Items[args.Index];

    // Get the bounds for the first column
    Rectangle r1 = args.Bounds;
    r1.Width -= r1.Height;

    // Draw the text
    using (SolidBrush sb = new SolidBrush(args.ForeColor))
    {
        args.Graphics.DrawString(url, args.Font, sb, r1);
    }

    // Draw the X icon
    Rectangle r2 = new Rectangle(r1.Width+1, r1.Y + 1, r1.Height - 2, r1.Height - 2);
    args.Graphics.DrawImage(Project.Test.Properties.Resources.CloseIcon, r2);
};

今私の問題は、X がクリックされた場合にキャプチャする方法です。私が最初に考えたのは、ComboBox の MouseDown イベントをキャプチャし、DroppedDown プロパティが true かどうかを確認することでしたが、そのイベントは展開されていない ComboBox をクリックしたときにのみ発生します。ComboBox の DropDown 部分からイベントをキャプチャするにはどうすればよいですか。それが分かれば、X がクリックされたのか、それとも今クリックされたのかを判断することはそれほど問題にはならないと思います。

4

4 に答える 4

2

実際、あなたの問題は、Win32解決できる簡単な問題です。

public class Form1 : Form {
  [DllImport("user32")]
  private static extern int GetComboBoxInfo(IntPtr hwnd, out COMBOBOXINFO comboInfo);
  struct RECT {
    public int left, top, right, bottom;
  }
  struct COMBOBOXINFO {
        public int cbSize;
        public RECT rcItem;
        public RECT rcButton;
        public int stateButton;
        public IntPtr hwndCombo;
        public IntPtr hwndItem;
        public IntPtr hwndList;
  }
  public Form1(){
    InitializeComponent();  
    comboBox1.HandleCreated += (s, e) => {
       COMBOBOXINFO combo = new COMBOBOXINFO();
       combo.cbSize = Marshal.SizeOf(combo);
       GetComboBoxInfo(comboBox1.Handle, out combo);
       hwnd = combo.hwndList;
       init = false;
    };
  }
  bool init;
  IntPtr hwnd;
  NativeCombo nativeCombo = new NativeCombo();
  //This is to store the Rectangle info of your Icons
  //Key:  the Item index
  //Value: the Rectangle of the Icon of the item (not the Rectangle of the item)
  Dictionary<int, Rectangle> dict = new Dictionary<int, Rectangle>();
  public class NativeCombo : NativeWindow {
        //this is custom MouseDown event to hook into later
        public event MouseEventHandler MouseDown;
        protected override void WndProc(ref Message m)
        {                
            if (m.Msg == 0x201)//WM_LBUTTONDOWN = 0x201
            {                    
                int x = m.LParam.ToInt32() & 0x00ff;
                int y = m.LParam.ToInt32() >> 16;
                if (MouseDown != null) MouseDown(null, new MouseEventArgs(MouseButtons.Left, 1, x, y, 0));                                                                  
            }
            base.WndProc(ref m);
        }
  }
  //DropDown event handler of your comboBox1
  private void comboBox1_DropDown(object sender, EventArgs e) {
        if (!init) {
            //Register the MouseDown event handler <--- THIS is WHAT you want.
            nativeCombo.MouseDown += comboListMouseDown;
            nativeCombo.AssignHandle(hwnd);                
            init = true;
        }
  }
  //This is the MouseDown event handler to handle the clicked icon
  private void comboListMouseDown(object sender, MouseEventArgs e){
    foreach (var kv in dict) {
      if (kv.Value.Contains(e.Location)) {
         //Show the item index whose the corresponding icon was held down
         MessageBox.Show(kv.Key.ToString());
         return;
      }
    }
  }
  //DrawItem event handler
  private void comboBox1_DrawItem(object sender, DrawItemEventArgs e) {
     //We have to save the Rectangle info of the item icons
     Rectangle rect = new Rectangle(0, e.Bounds.Top, e.Bounds.Height, e.Bounds.Height);
     dict[e.Index] = rect;
     //Draw the icon
     //e.Graphics.DrawImage(yourImage, rect);   
  }
}

何が起こるかについて少し

Aにはドロップ ダウン リストComboBoxが添付されています。これには からアクセスできます。GetComboBoxInfo win32 API 関数を使用して の情報を取得します。この情報はCOMBOBOXINFOという構造に保存されます。この構造体のメンバーhwndListを介して、ドロップ ダウン リストのハンドルを取得できます。HandleComboBox

hwndListにアクセスした後。カスタムのNativeWindowクラス (例ではNativeCombo )を使用して、そのメッセージ ループにフックできます。これにより、ドロップダウン リストのメッセージ ループを簡単に妨害できます。次に、 WM_LBUTTONDOWNメッセージをキャッチして、 MouseDownイベントを処理します。もちろん、これは完全な MouseDownイベントではありませんが、単なるデモであり、この場合は問題を解決するのに十分です。WM_LBUTTONDOWNは、LParamに保存されたクリックされたポイントに関する情報とともに送信されます。クリックされたポイントは、クライアント領域の座標で計算されますドロップダウンリストの(画面座標ではありません)。DrawItemイベント ハンドラーにもe.Bounds引数があり、これもクライアント領域座標(画面座標ではありません)で計算されることに注意してください。したがって、それらは同じ座標系にあります。Rectangle.Containsメソッドを使用して、クリックされたポイントが何らかのアイコンの境界に含まれているかどうかを確認します。すべてのアイコン BoundsDictionaryに保存します。したがって、を含むRectangleの対応するキー(アイテム インデックスを格納)クリックされたポイントは、対応するアイテム インデックスを知らせてくれます。その後、さらに処理を進めることができます。

于 2013-08-29T22:45:05.093 に答える
1

ユーザーがマウス ホイールを選択または使用すると、SelectionIndexChangedイベントが発生します。マウス ホイールに反応したくない場合や、クリックと選択のみに反応する必要がある場合は、SelectionChangeCommitedイベントの使用を検討してください。

次に、読み取りSelectedIndexまたはSelectedItemプロパティを使用して、選択したアイテムを取得できます。

編集:申し訳ありませんが、質問を完全に誤解しているようです。ListBoxコンボ内のマウスダウンをキャプチャし、 を使用して手動で確認する必要があると思いますRectange.Contains。詳細はまたお知らせします。

于 2013-08-29T21:28:01.590 に答える
0

ユーザーがコンボ ボックス内の項目をクリックすると、その項目が選択された状態になります。このプロパティは、コンボ ボックス オブジェクトから取得できます。

于 2013-08-29T21:22:23.790 に答える