阻止在Winforms ListBox中选择某些项目

时间:2015-11-11 15:24:50

标签: c# winforms listbox

我已经看到了一些与此类似的问题,但它们似乎适用于WPF(我不熟悉,并且该解决方案似乎不适用于我)。我有一个OwnerDrawFixed列表框(实际上是2个),如果添加的项目是"",我用它来绘制水平分隔符项目。我想要的是在点击时完全跳过这些(我点击拖动项目选择它时遇到麻烦)或通过上/下箭头键选择。这是我的DrawItem事件:

private void ListBox_DrawItem(object sender, DrawItemEventArgs e)
{
    if (e.Index < 0)
        return;

    e.DrawBackground();
    e.Graphics.DrawString((sender as ListBox).Items[e.Index].ToString(), (sender as ListBox).Font, new SolidBrush(e.ForeColor), e.Bounds);

    //Draw as a separator if there is no text
    if (string.IsNullOrWhiteSpace((sender as ListBox).Items[e.Index].ToString()))
    {
        e.Graphics.DrawLine(new Pen(Brushes.DarkGray), new Point(e.Bounds.X + 5, e.Bounds.Y + 7), new Point(e.Bounds.X + e.Bounds.Width - 5, e.Bounds.Y + 7));
    }
    //Doesn't appear to do anything e.DrawBackground isn't..?
    //e.DrawFocusRectangle();
}  

我尝试过MouseUp,MouseDown和SelectedIndexChanged事件的组合,要么完全清除选择(出于显而易见的原因不适合箭头导航),要么存储先前选择的索引,确定方向,并选择下一个值(如果项目不靠近,有时点击不直观) 我也尝试了myListBox.SelectionMode = SelectionMode.None;,但出于某种原因(可能是我的绘制事件?)它只是突出显示我选择的每个项目(没有取消选择它们)。

如果我试图禁止选择项目为空字符串的项目,我是否遗漏了某些内容?

2 个答案:

答案 0 :(得分:1)

这是一个适合我的简单解决方案。我刚刚将这一事件添加到您发布的代码中:

int lastIndex = 0;
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
    string s = listBox1.SelectedItem.ToString();
    int newIndex = listBox1.SelectedIndex;
    if (s == "" )
    {
        if (newIndex > lastIndex && newIndex  < listBox1.Items.Count)
        {
            listBox1.SelectedIndex++;
        }
        else if (newIndex < lastIndex && newIndex > 0)
        {
            listBox1.SelectedIndex--;
        }
    }
    else lastIndex = newIndex;
}

答案 1 :(得分:0)

我修改了ListBox with Disableable Items中的代码以满足您的需求:

public class ListBoxEx : ListBox {

  private const int WM_MOUSEMOVE = 0x200;
  private const int WM_LBUTTONDOWN = 0x201;
  private const int WM_KEYDOWN = 0x100;
  private const int VK_LEFT = 0x25;
  private const int VK_UP = 0x26;
  private const int VK_RIGHT = 0x27;
  private const int VK_DOWN = 0x28;

  protected override void WndProc(ref Message m) {
    // Get params as int
    int lParam = m.LParam.ToInt32();
    int wParam = m.WParam.ToInt32();

    // Intercept mouse selection
    if (m.Msg == WM_MOUSEMOVE || m.Msg == WM_LBUTTONDOWN) {
      Point clickedPt = new Point();
      clickedPt.X = lParam & 0x0000FFFF;
      clickedPt.Y = lParam >> 16;

      // If point is on a disabled item, ignore mouse
      for (int i = 0; i < Items.Count; i++)
        if (string.IsNullOrWhiteSpace(Items[i].ToString()) &&
          GetItemRectangle(i).Contains(clickedPt))
          return;
    }

    // Intercept keyboard selection
    if (m.Msg == WM_KEYDOWN)
      if (wParam == VK_DOWN || wParam == VK_RIGHT) {
        // Select next enabled item
        for (int i = SelectedIndex + 1; i < Items.Count; i++)
          if (!string.IsNullOrWhiteSpace(Items[i].ToString())) {
            SelectedIndex = i;
            break;
          }
        return;
      } else if (wParam == VK_UP || wParam == VK_LEFT) {
        // Select previous enabled item
        for (int i = SelectedIndex - 1; i >= 0; i--)
          if (!string.IsNullOrWhiteSpace(Items[i].ToString())) {
            {
              SelectedIndex = i;
              break;
            }
          }
        return;
      }
    base.WndProc(ref m);
  }

  protected override void OnDrawItem(DrawItemEventArgs e) {
    if (e.Index > -1) {
      string item = this.Items[e.Index].ToString();
      if (string.IsNullOrWhiteSpace(item)) {
        e.Graphics.DrawLine(Pens.DarkGray, new Point(e.Bounds.X + 5, e.Bounds.Y + 7),
                                           new Point(e.Bounds.Right - 5, e.Bounds.Y + 7));
      } else {
        if ((e.State & DrawItemState.Selected) == DrawItemState.Selected) {
          e.Graphics.FillRectangle(SystemBrushes.Highlight, e.Bounds);
          TextRenderer.DrawText(e.Graphics, item, e.Font, e.Bounds, SystemColors.HighlightText);
        } else {
          e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds);
          TextRenderer.DrawText(e.Graphics, item, e.Font, e.Bounds, SystemColors.WindowText);
        }
      }
    }
    base.OnDrawItem(e);
  }
}