我看到有些应用程序(也许不是 .NET 应用程序)在窗体标题栏的最小化按钮左边有一个额外的按钮。我该如何在 C# 中实现这个功能?
我看到有些应用程序(也许不是 .NET 应用程序)在窗体标题栏的最小化按钮左边有一个额外的按钮。我该如何在 C# 中实现这个功能?
更新: 添加了一种适用于启用Aero的 Windows Vista 和 Windows 7 的解决方案
窗口的非客户端区域交互是由一系列非客户端特定消息管理的。例如,WM_NCPAINT消息被发送到窗口过程以绘制非客户端区域。
我从未在.NET中完成过这个操作,但我认为您可以重写 WndProc 并处理 WM_NC* 消息以实现您想要的效果。
更新:由于我从未在.NET中尝试过这个操作,所以我抽出了几分钟时间,尝试了一下。
在 Windows 7 上进行测试时,我发现如果我想让操作系统执行非客户端区域的基本渲染,则需要为窗口禁用主题。所以这是一个简短的测试。我使用 GetWindowDC 获取整个窗口的 DC 而不是 GetDCEx,那只是因为我可以从内存中进行Interop而不必查找所有的GetDcEx标志常量。当然,代码还可以进行更多的错误检查。
using System;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsFormsApplication1
{
public partial class CustomBorderForm : Form
{
const int WM_NCPAINT = 0x85;
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetWindowDC(IntPtr hwnd);
[DllImport("user32.dll", SetLastError = true)]
public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc);
[DllImport("user32.dll", SetLastError = true)]
public static extern void DisableProcessWindowsGhosting();
[DllImport("UxTheme.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr SetWindowTheme(IntPtr hwnd, string pszSubAppName, string pszSubIdList);
public CustomBorderForm()
{
// This could be called from main.
DisableProcessWindowsGhosting();
InitializeComponent();
}
protected override void OnHandleCreated(EventArgs e)
{
SetWindowTheme(this.Handle, "", "");
base.OnHandleCreated(e);
}
protected override void WndProc(ref Message m)
{
base.WndProc(ref m);
switch (m.Msg)
{
case WM_NCPAINT:
{
IntPtr hdc = GetWindowDC(m.HWnd);
using (Graphics g = Graphics.FromHdc(hdc))
{
g.FillEllipse(Brushes.Red, new Rectangle((Width-20)/2, 8, 20, 20));
}
ReleaseDC(m.HWnd, hdc);
}
break;
}
}
}
}
顺便说一下,我调用了DisableProcessWindowsGhosting
,这将阻止操作系统在应用程序响应窗口消息的时间过长时绘制非客户区域。如果你不这样做,在某些情况下边框会被渲染但装饰不会显示。所以要根据你的需求来决定是否适合使用此方法。
受到@TheCodeKing的评论的启发,我认为我应该再次看看这个问题。事实证明,这可以在完全记录的方式下支持Aero完成。但这不是针对新手的。我不会在这里提供完整的解决方案,还有一些细节需要处理,但它可以做到基本功能。
这段代码/解决方案基于Win32示例,可以在以下位置找到http://msdn.microsoft.com/en-us/library/bb688195(VS.85).aspx
原则上,您需要执行以下操作。
上述步骤将为您提供具有标准玻璃框架(不包括系统菜单(窗口图标)和标题)的窗口。最小化,最大化和关闭按钮仍将绘制并可用。您无法拖动或调整窗口大小,这是因为框架实际上不存在,记住客户区域覆盖整个窗口,我们只是要求操作系统将框架绘制到客户区域上。
现在您可以像往常一样在窗口上绘制,甚至在框架顶部绘制。您甚至可以在标题区域放置控件。
最后,通过从WndProc
中调用DwmDefWindowProc(在处理它之前),允许DWM为您处理命中测试。它返回一个布尔值,指示DWM是否为您处理了消息。
g.DrawString()
改变标题的字体,但是我遇到了一些问题:如果我使用 SetWindowTheme(this.Handle, "", "");
,标题会正常显示,但窗体的边框将会是灰色的。如果我使用 SetWindowTheme(this.Handle, "explorer", null);
,标题就不会显示(在标题栏后面),但窗体的边框颜色不会变化(默认颜色)。我该怎么做才能以默认颜色显示标题呢?谢谢! - GSP-Set Form Border Style to None
-Add whatever controls you would like to this
-I will name this custom form "TitleBarButtons"
第2步。在您想要使用此自定义控件的表单中添加
titleBarBtn = new TitleBarButtons();
titleBarBtn.Location = new Point(this.Location.X + 100, this.Location.Y+5);
titleBarBtn.Show();
titleBarBtn.Owner = this;
private void Form14_Move(object sender, EventArgs e)
{
titleBarBtn.Location = new Point(this.Location.X + 100, this.Location.Y+5);
}