C# 防止在Winforms列表框中选择某些项

C# 防止在Winforms列表框中选择某些项,c#,winforms,listbox,C#,Winforms,Listbox,我见过一些与此类似的问题,但它们似乎是针对WPF的(我对WPF不熟悉,解决方案似乎不适用于我)。我有一个OwnerDrawFixed列表框(实际上是2个),如果添加的项目是”,我就用它来绘制水平分隔符项目。我想要的是在单击(我在选择项目时遇到了单击拖动问题)或通过上/下箭头键选择时完全跳过这些。这是我的DrawItem事件: private void ListBox_DrawItem(object sender, DrawItemEventArgs e) { if (e.Index &l

我见过一些与此类似的问题,但它们似乎是针对WPF的(我对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();
}  
private void ListBox\u DrawItem(对象发送方,DrawItemEventArgs e)
{
如果(e.指数<0)
返回;
e、 牵引杆接地();
e、 Graphics.DrawString((发送者作为列表框)。Items[e.Index]。ToString(),(发送者作为列表框)。Font,新SolidBrush(e.ForeColor),e.Bounds;
//如果没有文本,则绘制为分隔符
if(string.IsNullOrWhiteSpace((发送者作为列表框).Items[e.Index].ToString())
{
e、 绘图线(新画笔(画笔.DarkGray)、新点(e.Bounds.X+5、e.Bounds.Y+7)、新点(e.Bounds.X+e.Bounds.Width-5、e.Bounds.Y+7);
}
//似乎什么都没做,例如,牵引地面不是。。?
//e、 DrawFocusRectangle();
}  
我尝试了MouseUp、MouseDown和SelectedIndexChanged事件的组合,或者完全清除选择(由于明显的原因,对于箭头导航来说不是很好),或者存储以前选择的索引,确定方向,然后选择下一个值(如果项目不接近,有时单击会不直观).
我还尝试了
myListBox.SelectionMode=SelectionMode.None,但出于某种原因(可能是我的绘图事件?)它只会高亮显示我选择的每个项目(而不会取消选择它们)

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

我修改了中的代码以满足您的需要:

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);
  }
}
公共类ListBoxEx:ListBox{
私有常量int WM_MOUSEMOVE=0x200;
私有常量int WM_LBUTTONDOWN=0x201;
私有常量int WM_KEYDOWN=0x100;
私有常量int VK_LEFT=0x25;
私有常量int VK_UP=0x26;
私有常量int VK_RIGHT=0x27;
私有常量int VK_DOWN=0x28;
受保护的覆盖无效WndProc(参考消息m){
//获取参数为int
int lParam=m.lParam.ToInt32();
int wParam=m.wParam.ToInt32();
//拦截鼠标选择
如果(m.Msg==WM|MOUSEMOVE | m.Msg==WM|LBUTTONDOWN){
点击点PT=新点();
clickedPt.X=lParam&0x0000FFFF;
单击pt.Y=lParam>>16;
//如果点位于禁用的项目上,则忽略鼠标
对于(int i=0;i=0;i--)
if(!string.IsNullOrWhiteSpace(Items[i].ToString())){
{
SelectedIndex=i;
打破
}
}
返回;
}
基准WndProc(参考m);
}
受保护的覆盖无效OnDrawItem(DrawItemEventArgs e){
如果(如索引>-1){
string item=this.Items[e.Index].ToString();
if(string.IsNullOrWhiteSpace(项)){
e、 图形.绘制线(画笔.暗线,新点(e.Bounds.X+5,e.Bounds.Y+7),
新点(e.Bounds.Right-5,e.Bounds.Y+7);
}否则{
if((e.State&DrawItemState.Selected)=DrawItemState.Selected){
e、 Graphics.FillRectangle(SystemBrush.Highlight,e.Bounds);
TextRenderer.DrawText(例如图形、项目、字体、边界、系统颜色、HighlightText);
}否则{
e、 Graphics.FillRectangle(SystemBrush.Window,e.Bounds);
TextRenderer.DrawText(如图形、项目、字体、边界、系统颜色、WindowText);
}
}
}
基础项目(e);
}
}

这里有一个简单的解决方案,对我来说很有效。我刚刚将这一事件添加到您发布的代码中:

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;
}
int lastIndex=0;
私有无效列表框1\u SelectedIndexChanged(对象发送方,事件参数e)
{
字符串s=listBox1.SelectedItem.ToString();
int newIndex=listBox1.SelectedIndex;
如果(s==“”)
{
if(newIndex>lastIndex&&newIndex0)
{
列表框1.SelectedIndex--;
}
}
else lastIndex=newIndex;
}

是的。。。在处理现有WinForms应用程序时不可能。@HighCore,“WinForms不支持自定义”到底是什么意思?让我们不要混淆该网站的访问者。@cdkMoose我已经解释过很多次了,某项技术或框架“Foo”支持“某项功能”Bar,这意味着您可以相对轻松地使用“Foo”来执行或实现“Bar”。由于您实际上无法相对轻松地自定义winforms中的任何内容,因此可以说winforms不支持自定义。是的,你可以在一定程度上实施可怕的变通方法和黑客来实现你所需要的,但这种变通方法和黑客的存在本身就证明了我的观点。@HighCore,你真是太好了,已经为我们这些没有受过教育的可怜的傻瓜解释了很多次了,但这只是你的定义,不是解决OPs问题的办法。我在这里和其他地方读过很多次,WPF有着深刻的经验