禁用在标题栏双击时最大化WPF窗口

4
如何禁用WPF窗口标题栏双击最大化功能,但保留调整大小功能?
我知道ResizeMode可以禁用最大化,但它也会阻止调整窗体大小。
ResizeMode="CanMinimize"

我知道如何移除最大化和最小化按钮,但仍然可以通过双击标题栏来最大化。
在WinForms中,这很容易实现。只需将FormBorderStyleNone设置为FixedSingleFixed3D即可。但在WPF中不再是一个选项。

P.S. 我正在尝试使用处理 WM_GETMINMAXINFO、WM_SYSCOMMAND 等技巧。但是似乎没有起作用...

6个回答

9

我参考MSDN的帮助,提供了一个与WPF窗口中检测非客户端鼠标活动相关的良好解决方案。

如果msg == WM_NCLBUTTONDBLCLK,在WndProc中调用handled = true将防止用户双击非客户端区域时窗口最大化。

myClass()  //c'tor
{
  InitializeComponent();
  SourceInitialized += new EventHandler(myClass_SourceInitialized);  
}

void myClass_SourceInitialized(object sender, EventArgs e)
{
    System.Windows.Interop.HwndSource source = System.Windows.Interop.HwndSource.FromHwnd(new System.Windows.Interop.WindowInteropHelper(this).Handle);
    source.AddHook(new System.Windows.Interop.HwndSourceHook(WndProc));
}

int WM_NCLBUTTONDBLCLK { get { return 0x00A3; } }

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    if (msg == WM_NCLBUTTONDBLCLK)
    {
        handled = true;  //prevent double click from maximizing the window.
    }

    return IntPtr.Zero;
}

有用的 MSDN 参考文献:在非客户端窗口区域中的鼠标事件


1
@Klaus - 我知道已经有一段时间了,但这可能会对你有所帮助(将来用得着!)。 - edtheprogrammerguy
1
到目前为止,我发现唯一真正有效的选项。所有其他选项都有限制,或者是hack,或者根本无效。 - DonBoitnott

8

我遇到了类似的问题。我的窗口没有任何表单边框或标题栏,但是可以使用鼠标移动它。问题在于,如果用户将窗口移动到屏幕顶部,那么Windows会自动将窗口最大化。

我通过将以下处理程序附加到窗口的 StateChanged 事件来解决这个问题。

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

3
这个窗口的行为很别扭,因为它会在短暂地最大化后再恢复原来的大小,导致视觉效果不美观。 - edtheprogrammerguy

2

在遇到这个问题并研究了这个SO问题后,我认为答案不够满意。尽管已经移除了标题栏,但当双击窗口靠近顶部时,窗口仍会最大化。

我选择的解决方案是移除标题栏并禁用窗口的双击功能。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        MouseDoubleClick += (sender, args) =>
        {
            args.Handled = true;
        };
    }
}

在我的应用程序中,我使用的是MahApps.Metro,它会继承自MetroWindow而不是Window,但上述示例应该在两种情况下都适用。


"PreviewMouseDoubleClick" 是更好的选择,"MouseDoubleClick" 并不总是有效。 - tetralobita

2

WPF没有本地禁用窗口最大化的方法(不像WinForms)。因此,请考虑以下关键点:

1. 隐藏最大化按钮

使用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));
}

2. 手动最大化处理

上述代码仍允许手动最大化(例如通过双击窗口标题)。

WPF 对标题栏行为没有控制。如果您想更改双击行为,则需要删除标题栏并创建自己的标题栏。看一下在 MahApps.Metro 中如何完成 - 示例链接。之后处理双击事件即可。


1
另一个简单(但丑陋)的解决方案:
// inside a Window class
protected override void OnPreviewMouseDoubleClick(MouseButtonEventArgs e)
{
    base.OnPreviewMouseDoubleClick(e);

    const int titleHeight = 30;
    var position = e.GetPosition(this);

    if (position.Y <= titleHeight)
    {
        e.Handled = true;
    }
}

注意:用户仍然可以使用标题栏上的上下文菜单 / 将窗口移动到屏幕的上边缘来最大化窗口。

它可能不太美观,但却是最佳解决方案,因为它不需要WINAPI导入并且不会闪烁。干得好。 - Prophet Lamb

1
这对你有效吗?
public partial class MainWindow : Window
 {
    public MainWindow()
   {

    InitializeComponent();
    this.SizeChanged += MainWindow_SizeChanged;
   }    
    void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
    {

      if (this.WindowState == WindowState.Maximized)
      {
       this.WindowState = System.Windows.WindowState.Normal;
      }


}
}

实际上它并没有禁用最大化,并且会导致窗口闪烁。因此,我无法将其标记为答案。 - Alex Klaus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接