堆叠面板折叠后,将窗口与中心屏幕对齐

时间:2013-05-23 06:12:44

标签: c# wpf visual-studio-2010

在我的应用程序中,单击按钮时我将Stackpanel可见性设置为折叠,再次单击另一个按钮,然后再次设置为Visible。
这很好。但是当窗口没有位于中心时,可以看到堆叠面板 如何在更改堆叠面板可见性时自行调整..
我在更改StackPanel的可见性后尝试调用此函数。

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

但它没有正确对齐。如何实现这个??

1 个答案:

答案 0 :(得分:1)

这里有很多问题要处理。

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

<强>解决方案:CenterWindow()事件处理程序执行SizeChanged并使用计时器不要经常调用CenterWindow()

  • 接下来,我们需要使用事件处理程序中的this.ActualWidththis.ActualHeight来确定尺寸而非this.Width ...
  • 您的用户可能有多个屏幕(其中也有不同的分辨率)。当您使用CenterWindow(...)以获得可用性时,在大多数情况下,您通常希望将其置于当前屏幕中,而不是您的代码无法容纳的。

<强>解决方案: 需要使用一些WinForms帮助程序来获取实际屏幕并区分多个屏幕。

  • 最后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;
}

注意:

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