如何创建悬停的C#Winforms控件

如何创建悬停的C#Winforms控件,c#,.net,winforms,user-controls,user-interface,C#,.net,Winforms,User Controls,User Interface,如何创建超出其区域边界的C#Winforms控件?例如下拉框。有点像你在一个小的面板上有一个下拉框。我最近做了类似的事情,我使用了一个列表框。列表框最酷的一点是,你可以在任何你想显示的地方显示它,甚至超出你的控制范围。这样,当您通过单击按钮或其他方式检测到需要显示所需的下拉列表时,只需填充列表框并将其显示在任何您想要的位置。我从这里得到了这个想法: 它们展示了如何构建带有筛选的自定义DataGridView,以及如何显示筛选值,它们在标题单元格下放置了一个列表框。Windows窗体不支持这样的

如何创建超出其区域边界的C#Winforms控件?例如下拉框。有点像你在一个小的面板上有一个下拉框。

我最近做了类似的事情,我使用了一个列表框。列表框最酷的一点是,你可以在任何你想显示的地方显示它,甚至超出你的控制范围。这样,当您通过单击按钮或其他方式检测到需要显示所需的下拉列表时,只需填充列表框并将其显示在任何您想要的位置。我从这里得到了这个想法:


它们展示了如何构建带有筛选的自定义DataGridView,以及如何显示筛选值,它们在标题单元格下放置了一个列表框。

Windows窗体不支持这样的窗口,它与设计器基本不兼容。这里有一些代码可以帮助您开始。您不能在设计器中使用此控件,它必须在运行时创建。您还必须自己调用它的Dispose()方法

using System;
using System.Drawing;
using System.ComponentModel;
using System.Windows.Forms;

public class MyListBox : ListBox {
  private Control mParent;
  private Point mPos;
  private bool mInitialized;

  public MyListBox(Control parent) {
    mParent = parent;
    mInitialized = true;
    this.SetTopLevel(true);
    parent.LocationChanged += new EventHandler(parent_LocationChanged);
    mPos = mParent.Location;
  }

  public new Point Location {
    get { return mParent.PointToClient(this.Location); }
    set { 
      Point zero = mParent.PointToScreen(Point.Empty);
      base.Location = new Point(zero.X + value.X, zero.Y + value.Y);
    }
  }

  protected override Size DefaultSize {
    get {
      return mInitialized ? base.DefaultSize : Size.Empty;
    }
  }

  protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) {
    if (this.mInitialized)
      base.SetBoundsCore(x, y, width, height, specified);
  }

  void parent_LocationChanged(object sender, EventArgs e) {
    base.Location = new Point(base.Left + mParent.Left - mPos.X, base.Top + mParent.Top - mPos.Y);
    mPos = mParent.Location;
  }

  protected override CreateParams CreateParams {
    get {
      CreateParams cp = base.CreateParams;
      if (mParent != null && !DesignMode) {
        cp.Style = (int)(((long)cp.Style & 0xffff) | 0x90200000);
        cp.Parent = mParent.Handle;
        Point pos = mParent.PointToScreen(Point.Empty);
        cp.X = pos.X;
        cp.Y = pos.Y;
        cp.Width = base.DefaultSize.Width;
        cp.Height = base.DefaultSize.Height;
      }
      return cp;
    }
  }
}

这里有一篇好文章:


它有一个类,可以处理使其正常工作的一些棘手方面,例如保持应用程序窗口标题栏处于活动状态、处理Alt Tab和用鼠标单击取消。

尝试过它,效果很好,但不知何故它不会引发列表框事件,如DrawItem和SelectedIndexChanged。你知道为什么吗?请看我的回答: