【问题标题】:Disable maximize button of WPF window, keeping resizing feature intact禁用 WPF 窗口的最大化按钮,保持调整大小功能不变
【发布时间】:2013-09-09 22:04:39
【问题描述】:

因此 WPF 窗口只有四个调整大小模式选项:NoResizeCanMinimizeCanResizeCanResizeWithGrip。不幸的是,启用调整大小的选项也启用了最大化窗口,而那些不启用的选项对我来说毫无用处。

是否可以在保留调整大小功能的同时禁用最大化按钮?

我更喜欢不涉及 WinAPI 东西的解决方案。

【问题讨论】:

  • 为什么要禁用最大化按钮,但允许调整窗口大小?
  • 因为设置了 MaxWidth 的窗口在最大化时通常看起来很糟糕。尝试最大化命令提示符,你会看到。
  • @Dai, WPF dialogs 就是很好的例子。看看 VS2013 的 Options 窗口 - 它是 resizable 但有 no minimizemaximize 按钮
  • @Dai 用户很少会故意调整窗口大小以掩盖其他过度思考,或者将其最小化并“丢失”它,从而导致混乱。有了那里的按钮,这很容易发生。
  • 我知道这是一个老问题,但我想为这些新访客留下评论。试试 Telerik RadWindow。它不是免费的,但有隐藏最小化和隐藏最大化选项。

标签: c# .net wpf


【解决方案1】:

仅禁用最大化:

ResizeMode="CanMinimize"

【讨论】:

  • 这也会禁用调整窗口大小
  • @RobSiklos 谢谢,我正在尝试两者,哈哈,正要研究如何禁用调整大小并看到您的评论。
【解决方案2】:

WPF 不具备单独禁用“最大化”按钮的本机功能,就像使用 WinForms 一样。您将需要求助于 WinAPI 调用。这并不可怕:

[DllImport("user32.dll")]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

private const int GWL_STYLE = -16;
private const int WS_MAXIMIZEBOX = 0x10000;

private void Window_SourceInitialized(object sender, EventArgs e)
{
    var hwnd = new WindowInteropHelper((Window)sender).Handle;
    var value = GetWindowLong(hwnd, GWL_STYLE);
    SetWindowLong(hwnd, GWL_STYLE, (int)(value & ~WS_MAXIMIZEBOX));
}

【讨论】:

  • 这是否也会禁用任何其他最大化窗口的方法?我真的不希望用户尝试通过任务管理器或其他方式最大化它。
  • @Peter 最大化系统控制菜单项显示为灰色,Win7/Win8 Aero“拖动到顶部以最大化”手势和键盘快捷键不起作用。任务管理器仍然允许您最大化窗口,其他直接使用 WinAPI 的程序仍然可以做到这一点。不要太担心它。如果有人真的想最大化窗口,你不能阻止他们。
  • 其实我错了。对不起,应该更彻底地测试。根据您的问题,此代码将隐藏最大化按钮。如果您设置 MaxWidth/MaxHeight,则最大化窗口只会将其移动到左上角。内容不会超过您设置的最大大小。
【解决方案3】:

如果你设置了

WindowStyle="ToolWindow"

在您的窗口属性中,它将为您提供一个可调整大小的窗口,顶部没有最小化或最大化按钮。它看起来是方形的,关闭按钮也是方形的,但至少没有最小化和最大化!

【讨论】:

  • 但是这个可以通过双击窗口绕过
  • 但是如果你设置了 ResizeMode=NoResize 那么就不能绕过了。
【解决方案4】:

P/调用方法

从托管 (.NET) 代码调用非托管代码(在本例中为 C++)的最简单方法是使用平台调用服务,通常也称为 P/Invoke。您只需向编译器提供非托管函数的声明,然后像调用任何其他托管方法一样调用它。有一个非托管的 SetWindowLong 方法可用于更改指定窗口的属性。为了能够使用 P/Invoke 从 WPF 窗口类调用此方法,您只需将以下声明添加到窗口类:

[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

DllImport 属性指定包含该方法的 DLL 的名称,extern 关键字告诉 C# 编译器该方法是在外部实现的,并且在编译应用程序时它不会找到任何实现或方法体。传递给 SetWindowLong 方法的第一个参数是要禁用任何上述按钮的窗口的句柄。您可以通过创建托管 WindowInteropHelper 类的实例并在窗口的 SourceInitialized 事件的事件处理程序中访问其 Handle 属性来获取 WPF 窗口的句柄。当句柄完全创建时引发此事件。 SetWindowLong 方法的第二个参数指定要设置的窗口的属性或值,以常量整数值表示。当您想更改窗口样式时,您应该将 GWL_STYLE (= -16) 常量作为第二个参数传递给该方法。

private const int GWL_STYLE = -16;

最后第三个参数指定替换值。您可以在这里使用一组常量:

private const int WS_MAXIMIZEBOX = 0x10000; //maximize button
private const int WS_MINIMIZEBOX = 0x20000; //minimize button

但是请注意,由于您应该传入一个 DWORD,该 DWORD 指定由第二个参数指定的“属性”的完整值,即本例中的窗口样式,因此您不能简单地将这些常量中的任何一个单独传递为方法的第三个参数。还有另一个 GetWindowLong 方法可以检索特定属性的当前值(在本例中也是 GWL_STYLE),然后您可以使用按位运算符获取第三个参数的正确值以传递给 SetWindowLong 方法。下面是一个完整的代码示例,例如如何禁用 WPF 中窗口的最小化按钮:

public partial class MainWindow : Window
{
 [DllImport("user32.dll")]
 private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
 [DllImport("user32.dll")]
 private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int  dwNewLong);

 private const int GWL_STYLE = -16;

 private const int WS_MAXIMIZEBOX = 0x10000; //maximize button
 private const int WS_MINIMIZEBOX = 0x20000; //minimize button

 public MainWindow() {
  InitializeComponent();
  this.SourceInitialized += MainWindow_SourceInitialized;
}

private IntPtr _windowHandle;
private void MainWindow_SourceInitialized(object sender, EventArgs e) {
_windowHandle = new WindowInteropHelper(this).Handle;

 //disable minimize button
 DisableMinimizeButton();
}

protected void DisableMinimizeButton() {
  if (_windowHandle == IntPtr.Zero)
    throw new InvalidOperationException("The window has not yet been completely initialized");

   SetWindowLong(_windowHandle, GWL_STYLE, GetWindowLong(_windowHandle,  GWL_STYLE) & ~WS_MAXIMIZEBOX);
 }
}

禁用最小化按钮只需将 WS_MAXIMIZEBOX 常量替换为 WS_MINIMIZEBOX

【讨论】:

【解决方案5】:

另一个选项是捕捉窗口最大化时引发的StateChanged 事件。然后只需将WindowState 设置为“正常”。

但是,这不会隐藏最大化框!

private void Window_StateChanged(object sender, EventArgs e)
{
    if (WindowState == WindowState.Maximized)
    {
        WindowState = WindowState.Normal;
    }
}

【讨论】:

  • 这个解决方案的主要问题是你会看到窗口最大化然后又回到正常状态的视觉反馈。
【解决方案6】:

您可以通过将 WindowStyle 设置为“无”来创建自定义窗口,这会删除“最小化”、“最大化”和“关闭”按钮,并自己创建所需的按钮。 这是一个很好的例子:

http://www.codeproject.com/Articles/131515/WPF-Custom-Chrome-Library

它为您提供了一些额外的工作,但如果您真的不想使用 WinAPI,这是一个选择。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-04-20
    • 1970-01-01
    • 1970-01-01
    • 2017-11-18
    • 1970-01-01
    • 2012-01-28
    • 2011-03-20
    • 2021-09-20
    相关资源
    最近更新 更多