OwnerDrawVariable ListBox在单击项目

时间:2018-01-22 18:03:46

标签: winforms

我在我的应用程序的ListBox中发现了这个问题,然后确定在MSDN上为ListBox.MeasureItem提供的示例遇到了同样的问题。

当您将ListBox的DrawMode设置为OwnerDrawVariable以处理MeasureItem事件(比如绘制具有增加高度的列表项)时,如果单击下面的空白区域,控件将选择最后一项最后一项。

我希望它在DrawMode设置为OwnerDrawFixed或Normal时的行为方式,如果用户点击项目列表下方的控件,则不会更改项目选择。

我尝试通过处理MouseDown事件来实现此行为,并发现控件在触发MouseDown事件之前选择最底层的项目。

我想知道我是否需要继承ListBox,或者是否有更好的方法来执行此操作。

为了查看行为,MSDN的代码示例就足够了:

https://msdn.microsoft.com/en-us/library/system.windows.forms.listbox.measureitem(v=vs.110).aspx

2 个答案:

答案 0 :(得分:2)

您可以通过检查鼠标按下消息来执行此操作,如果用户没有单击某个项目,则不允许它处理消息:

public class ListBoxEx : ListBox {
  private const int WM_LBUTTONDOWN = 0x201;

  protected override void WndProc(ref Message m) {
    int lParam = m.LParam.ToInt32();
    int wParam = m.WParam.ToInt32();
    if (m.Msg == WM_LBUTTONDOWN) {
      Point clickedPt = new Point();
      clickedPt.X = lParam & 0x0000FFFF;
      clickedPt.Y = lParam >> 16;
      bool lineOK = false;
      for (int i = 0; i < Items.Count; i++) {
        if (GetItemRectangle(i).Contains(clickedPt)) {
          lineOK = true;
        }
      }
      if (!lineOK) {
        return;
      }        
    }
    base.WndProc(ref m);
  }
}

答案 1 :(得分:1)

这是Win32控件中的内置行为。基本上,当您单击ListBox时,将调用名为IndexFromPoint的方法(您可以通过控件实例自行调用此方法)来确定所选项的索引。

我试图完全控制这个过程,但是我找不到任何证据表明,即使这样,当控件使用DrawMode.OwnerDrawVariable时,你可以区分点击实际项目。

因此,我相信你无法控制它。但你可能会躲闪它:

private void ListBox1_MouseDown(object sender, MouseEventArgs e)
{
    for (Int32 i = 0; i < ListBox1.Items.Count; i++)
    {
        var rect = ListBox1.GetItemRectangle(i);
        if (rect.Contains(e.Location))
            return;
    }
    ListBox1.SelectedIndex = -1;
}

正如您所注意到的,该事件将在此事件触发时被选中。这只是试图以足够快的速度取消选择,以免引起注意。如果ListBox中有很多项,您可能会注意到它是一个闪烁。

这可能是你能做的最好的事情。

相关问题