【问题标题】:Preventing selection of certain items in Winforms ListBox防止选择 Winforms ListBox 中的某些项目
【发布时间】:2015-11-11 15:24:50
【问题描述】:

我看到了一些与此类似的问题,但它们似乎是针对 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;,但由于某种原因(可能与我的绘图事件有关?)它只是突出显示了我选择的每个项目(没有取消选择它们)。

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

【问题讨论】:

  • 是的...当您正在处理现有的 WinForms 应用程序时,这是不可能的。
  • @HighCore,“winforms 不支持自定义”究竟是什么意思?我们不要混淆该网站的访问者。
  • @cdkMoose 我已经解释过很多次了,某种技术或框架“Foo”“支持”某种特性或能力“Bar”,意味着你可以相对容易使用“Foo”来做或实现“Bar”。由于您实际上无法相对轻松地在winforms中自定义anything,因此可以说winforms不支持自定义。是的,您可以实施可怕的变通办法和黑客攻击,以在一定程度上实现您所需要的,但这种变通办法和黑客攻击的存在证明了我的观点。
  • @HighCore,太好了,你已经为我们这些可怜的未受过教育的傻瓜解释了很多次但这只是你的定义,而不是解决 OPs 问题的方法。我在这里和其他地方读过很多次,WPF 有一个陡峭的学习曲线,在我的书中“陡峭的学习曲线”不等于“相对容易”,所以我猜你的定义意味着 WPF 也不支持自定义。为什么我们不远离关于技术的意见和贬低言论,而是尝试帮助 OP 解决他提出的问题。
  • 这对 OP 有什么帮助?如果他有必要使用 WInForms,无论出于何种原因,您的评论都没有帮助。 cmets 和 answers 的目的应该是帮助 OP 和其他可能处于类似情况的人。

标签: c# winforms listbox


【解决方案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;
}

【讨论】:

  • 这实际上导致了我的双击事件的问题,该事件删除和项目(虽然在帖子中没有提到,所以它不会影响这个答案)。使用额外的MouseDown 解决了这个问题,以利用您的lastIndex 变量。
【解决方案2】:

我修改了 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);
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-11
    相关资源
    最近更新 更多