1

在我的应用程序中,单击按钮时,我将 Stackpanel 可见性设置为 Collapsed,另一个按钮再次单击设置回 Visible。
这一切都很好。但是,当该堆栈面板可见时,我的窗口未位于中心。
更改堆栈面板可见性时如何进行自我调整。
我在更改堆栈面板的可见性后尝试调用此函数。

private void CenterWindowOnScreen()
{
    double screenWidth = System.Windows.SystemParameters.PrimaryScreenWidth;
    double screenHeight = System.Windows.SystemParameters.PrimaryScreenHeight;
    double windowWidth = this.Width;
    double windowHeight = this.Height;
    this.Left = (screenWidth / 2) - (windowWidth / 2);
    this.Top = (screenHeight / 2) - (windowHeight / 2);
}  

但它没有正确对齐。如何做到这一点?

4

1 回答 1

1

这里有多个问题需要处理。

  • Resize在调用之前(如果直接调用)Window未完成 的 ,因此计算不正确。CenterWindow()

解决方案:CenterWindow()从事件处理程序 中执行SizeChanged并使用计时器来避免CenterWindow()过于频繁地调用。

  • 接下来,我们需要使用this.ActualWidththis.ActualHeight从事件处理程序中获取确切的尺寸,而不是this.Width......
  • 您的用户可能有多个屏幕(它们之间也有不同的分辨率)。当您执行CenterWindow(...)可用性时,在大多数情况下,您通常希望将当前屏幕居中而不是主要屏幕,而您的代码不会适应这种情况。

解决方案: 需要使用一些WinForms helper来获取实际屏幕,区分多个屏幕。

  • 最后,WPF 尺寸与 DPI 无关,虽然应用上述步骤可以使其在默认 96dpi 下正常工作(win-8 也认为 win-7 和 vista),但当用户机器上的 dpi 不同时,您会开始看到奇怪的行为。

解决方案: 使用 dpi 独立措施来解决这个问题。

现在把这一切放在一起,我们得到类似的东西:

您需要参考System.Windows.Forms.dll

using System;
using System.Windows;
using System.Windows.Forms;
using System.Windows.Interop;
using System.Windows.Media;

private readonly System.Timers.Timer _resizeTimer = new System.Timers.Timer(500);

public MainWindow() {
  InitializeComponent();

  ...

  SizeChanged += (sender, args) => {
    _resizeTimer.Stop();
    _resizeTimer.Start();
  };
  _resizeTimer.Elapsed +=
    (sender, args) =>
    System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(CenterWindowToCurrentScreen));
}

public static double GetDpiFactor(Visual window) {
  HwndSource windowHandleSource = PresentationSource.FromVisual(window) as HwndSource;
  if (windowHandleSource != null && windowHandleSource.CompositionTarget != null) {
    Matrix screenmatrix = windowHandleSource.CompositionTarget.TransformToDevice;
    return screenmatrix.M11;
  }
  return 1;
}

private void CenterWindowToCurrentScreen() {
  _resizeTimer.Stop();
  double dpiFactor = GetDpiFactor(this);
  var screen = Screen.FromHandle(new WindowInteropHelper(this).Handle);
  double screenLeft = screen.Bounds.Left / dpiFactor;
  double screenTop = screen.Bounds.Top / dpiFactor;
  double screenWidth = screen.Bounds.Width / dpiFactor;
  double screenHeight = screen.Bounds.Height / dpiFactor;
  Left = ((screenWidth - ActualWidth) / 2) + screenLeft;
  Top = ((screenHeight - ActualHeight) / 2) + screenTop;
}

笔记:

上述代码尚未适应的一件事是实际的任务栏尺寸。如果需要,您也可以从屏幕尺寸中减去它们以更加精确。

于 2013-05-23T10:29:33.573 回答