.net Winforms:添加一个“关闭”;x";用户控件中的按钮

.net Winforms:添加一个“关闭”;x";用户控件中的按钮,.net,winforms,user-controls,.net,Winforms,User Controls,我需要在UserControl的左上角添加一个关闭“x”按钮。我希望该按钮具有与通常的Winforms关闭按钮类似的样式(XP样式的蓝色按钮,等等) 有可能做这样的事情吗?不确定是否有可能,但如果您的主控件(将承载此UserControl)将有这3个按钮(最小、最大/关闭)以及您的UserControl,则肯定会让用户感到困惑。这背后的原因是什么?更新的答案 我刚刚发现.net中有一个类,它与DrawFrameControl函数的作用相同。用它来代替 您可以使用ControlPaint类实现一个

我需要在UserControl的左上角添加一个关闭“x”按钮。我希望该按钮具有与通常的Winforms关闭按钮类似的样式(XP样式的蓝色按钮,等等)


有可能做这样的事情吗?

不确定是否有可能,但如果您的主控件(将承载此UserControl)将有这3个按钮(最小、最大/关闭)以及您的UserControl,则肯定会让用户感到困惑。这背后的原因是什么?

更新的答案
我刚刚发现.net中有一个类,它与
DrawFrameControl
函数的作用相同。用它来代替

您可以使用
ControlPaint
类实现一个按钮控件,该控件将自身绘制为类似于Windows“关闭”按钮(覆盖
OnPaint
)。根据所需的复杂程度,您也可以实现鼠标悬停事件和鼠标悬停事件,以提供当前状态的视觉反馈。如果您将该控件放置在
UserControl
上,您应该在正确的轨道上

原始、过时的答案
您可能想看看windows中的API函数


DFC\u CAPTION
DFCS\u CAPTION close
的组合应该可以满足您的需要。

下面是一个如何制作模拟按钮的示例。它在窗体本身上执行此操作,但在自定义控件上也执行相同的操作

它还展示了如何使用
VisualStyleRenderer
获得“奇特”按钮样式,以防
ControlPaint
样式太“旧”

经过六次编辑后更新了,我想我对它很满意

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;

class Form1 : Form
{
    [STAThread]
    static void Main()
    {
        //Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

    public Form1()
    {
        SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.UserPaint | ControlStyles.Opaque | ControlStyles.AllPaintingInWmPaint, true);
    }

    Rectangle buttonRect = new Rectangle(10, 10, 50, 20);
    ButtonState buttonState = ButtonState.Normal;

    protected override void OnMouseMove(MouseEventArgs e)
    {
        if (buttonRect.Contains(e.Location))
            buttonState = Capture ? ButtonState.Pushed : ButtonState.Checked;
        else
            buttonState = ButtonState.Normal;
        Invalidate(buttonRect);

        base.OnMouseMove(e);
    }

    protected override void OnMouseDown(MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left && buttonRect.Contains(e.Location))
        {
            Capture = true;
            buttonState = ButtonState.Pushed;
            Invalidate(buttonRect);
        }

        base.OnMouseDown(e);
    }

    protected override void OnMouseUp(MouseEventArgs e)
    {
        if (Capture)
        {
            Capture = false;
            Invalidate(buttonRect);
            if (buttonRect.Contains(e.Location))
            {
                // The button was clicked

                MessageBox.Show("You clicked the button.");
            }
        }

        base.OnMouseUp(e);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        e.Graphics.FillRectangle(SystemBrushes.Window, e.ClipRectangle);

        VisualStyleRenderer renderer = null;
        if (Application.RenderWithVisualStyles)
        {
            switch (buttonState)
            {
                case ButtonState.Checked:
                    if (VisualStyleRenderer.IsElementDefined(VisualStyleElement.Window.CloseButton.Hot))
                        renderer = new VisualStyleRenderer(VisualStyleElement.Window.CloseButton.Hot);
                    break;
                case ButtonState.Pushed:
                    if (VisualStyleRenderer.IsElementDefined(VisualStyleElement.Window.CloseButton.Pressed))
                        renderer = new VisualStyleRenderer(VisualStyleElement.Window.CloseButton.Pressed);
                    break;
                default:
                    if (VisualStyleRenderer.IsElementDefined(VisualStyleElement.Window.CloseButton.Normal))
                        renderer = new VisualStyleRenderer(VisualStyleElement.Window.CloseButton.Normal);
                    break;
            }
        }

        if (renderer != null)
            renderer.DrawBackground(e.Graphics, buttonRect);
        else
            ControlPaint.DrawCaptionButton(e.Graphics, buttonRect, CaptionButton.Close, buttonState);

        base.OnPaint(e);
    }
}
扩展评论

扩展操作是一种从用户按下鼠标按钮开始的操作,(可选)移动鼠标,然后释放该按钮。单击UI按钮始终是一个扩展操作。捕获鼠标的目的是防止鼠标在操作过程中与其他窗口交互

您现在可以看到演示的内容:

首先请注意,当您将鼠标移动到此页面上的元素(如注释)上时,它们是如何更改背景颜色的

现在打开Windows运行对话框(Win+R)

单击“取消”或“浏览…”。。。按钮并保持按住按钮

将鼠标移动到浏览器窗口,注意它不再记录您的鼠标移动

这就是所有按钮的设计工作原理。但几乎没有人注意到它,因为您通常在不移动鼠标的情况下单击并释放(很多)

将鼠标从按钮上移开并释放是为用户提供的一种机制,允许他们改变主意,而不是“单击”按钮。这就是为什么要在button up事件中再次进行测试,以确保它们仍在按钮上,然后才能确定用户是否执行了单击

因此,捕获鼠标有三个原因:

首先,您不希望其他窗口执行高亮显示之类的操作,因为用户正忙于与您的窗口进行交互,让其他窗口在操作过程中执行操作会分散注意力,并可能造成混乱

第二,您不希望用户释放鼠标按钮被发送到另一个窗口,因为他们可能会将鼠标一直移动到另一个窗口上。没有附带新闻的虚假鼠标发布可能会混淆编写糟糕的应用程序


第三,对于某些扩展操作,如绘画或“争吵”,您希望知道鼠标的坐标,即使它们位于窗口的边界之外。您可以通过单击并按住桌面并移动鼠标来查看争吵的示例。请注意,即使将鼠标移到其他窗口上,矩形也会发生变化。

他可能希望实现一些停靠功能或“关闭选项卡上的按钮”之类的功能。我以前使用过Infrastics dock manager,从未想过这种情况。这是一个相当于答案的评论。它是否会混淆,这是另一个问题。我需要一个浮动的用户控件,比如Photoshop中的工具栏,你可以在图片上移动,如果你不再需要它,也可以关闭它。你希望按钮有什么功能。是关闭整个表单还是卸载用户控件,如VisualStudio中的选项卡?@Phil Murray:我只需要外观。但是,如果您希望行为更接近VS中的选项卡,请注意我关于
ControlPaint
类的更新答案。但是,不是很清楚。。。我应该重写OnPaint方法吗。。。我应该如何管理点击它…嗯,你不是说你也想点击按钮。这个方法只是画一些看起来像按钮的东西。当然,您必须调用
ControlPaint
进行绘制的地方!最简单的方法是实现一个控件,该控件使用
ControlPaint
绘制自身,并对单击做出反应(
ControlPaint
也能够绘制按下的按钮)。这样,您就可以将按钮放在用户控件上,使其像普通按钮一样工作。进一步说明:实现一个可单击控件,使用
ControlPaint
(覆盖
OnPaint
)。把它放在你的
UserControl
上,当它被点击时做出反应。嗯?因为提供正确答案而被否决?这是新的。OP问如何画一个关闭按钮,我告诉他如何画一个关闭按钮,另外甚至提供如何将它变成一个实际按钮的信息-如果这不是一个有效的答案,我不知道…换句话说,我应该建立我自己的按钮,按下时画按钮,不按下时画按钮,当鼠标悬停、鼠标离开等时绘制按钮。我尝试在自定义按钮上实现此代码。。。和
MessageBox.Show(“您单击了按钮”)?有点confusing@Tergiver:此代码对f非常有用