• Centering a Window with a WPF Owner Window


    This post demonstrates how to manually center a window with respect to both a WPF and non-WPF owner window.

    Centering a Window with a WPF Owner Window

    To center a window over another window in WPF, you need to do two things. First, you need to set the WindowStartupLocation property of the Window you want centered to WindowStartupLocation.CenterOwner:

    <Window

      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

      x:Class="SDKSample.CenteredWindow"

      Title="Centered Window"

      WindowStartupLocation="CenterOwner"

      Width="250" Height="250">

      ...

    </Window>

    using System.Windows; // Window

    namespace SDKSample

    {

        public partial class CenteredWindow : Window

        {

            public CenteredWindow()

            {

                InitializeComponent();

            }

        }

    }

    Second, when you open the window to be centered, you *must* set its Owner property with the Window that opens it:

    <Window

      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

      x:Class="SDKSample.OwnerWindow"

      Title="Owner Window"

      Width="300" Height="300">

        ...

        <Button Click="button_Click">

          Show Centered Window

        </Button>

        ...

    </Window>

    using System.Windows; // Window, RoutedEventArgs

    namespace SDKSample

    {

        public partial class OwnerWindow : Window

        {

            public OwnerWindow()

            {

                InitializeComponent();

            }

            void button_Click(object sender, RoutedEventArgs e)

            {

                // Open window and set this window as its owner.

                // This causes the window to be centered with

                // respect to this window

                CenteredWindow cw = new CenteredWindow();

                cw.Owner = this;

                cw.Show();

            }

        }

    }

    When the button in this example is clicked, the owned window appears centered with respect to the owner window, as shown in the following figure:

    Centering a Window with a Non-WPF Owner Window

    WPF does allow you to set a non-WPF window as the owner of a WPF window. For example, a Visual Studio 2005 (VS05) add-in that shows a WPF window whose owner is the main VS05 IDE window. The following shows a generalized version of code that sets a WPF window with a non-WPF owner, using WindowInteropHelper:

    using System.Windows; // Window

    using System.Windows.Interop; // WindowInteropHelper

    ...

    // Instantiate the owned WPF window

    CenteredWindow cw = new CenteredWindow();

    // Get the handle to the non-WPF owner window

    IntPtr ownerWindowHandle = ...;

     

    // Set the owned WPF window’s Owner property with

    // the non-WPF owner window

    WindowInteropHelper helper = new WindowInteropHelper(cw);

    helper.Owner = (IntPtr)_applicationObject.MainWindow.HWnd;

    // Show the owned WPF window

    cw.Show();

    When a WPF window has a non-WPF owner, WPF honors the owner window/owned window relationship eg when a non-WPF owner window is minimized, the owned WPF window follows suit. However, if the owned WPF window has its WindowStartupLocation property set to WindowStartupLocation.CenterOwner, WPF does not center the owned WPF window over the non-WPF owner window. Instead, you’ll need to set the WindowStartupLocation of the owned window to WindowStartupLocation.Manual and manually calculate its Top and Left properties with values that make it appear centered:

    using System.Windows; // Window, WindowStartupLocation

    using System.Windows.Interop; // WindowInteropHelper

    ...

    // Instantiate the owned WPF window

    CenteredWindow cw = new CenteredWindow();

    // Get the handle to the non-WPF owner window

    IntPtr ownerWindowHandle = ...; // Get hWnd for non-WPF window

    // Set the owned WPF window’s owner with the non-WPF owner window

    WindowInteropHelper helper = new WindowInteropHelper(cw);

    helper.Owner = ownerWindowHandle;

    // Manually calculate Top/Left to appear centered

    int nonWPFOwnerLeft = ...; // Get non-WPF owner’s Left

    int nonWPFOwnerWidth = ...; // Get non-WPF owner’s Width

    int nonWPFOwnerTop = ...; // Get non-WPF owner’s Top

    int nonWPFOwnerHeight = ...; // Get non-WPF owner’s Height

    cw.WindowStartupLocation = WindowStartupLocation.Manual;

    cw.Left = nonWPFOwnerLeft + (nonWPFOwnerWidth - cw.Width) / 2;

    cw.Top = nonWPFOwnerTop + (nonWPFOwnerHeight - cw.Height) / 2;

    // Show the owned WPF window

    cw.Show();

    There is one issue with this code; WPF supports device-independence, which means that, irrespective of DPI; this code will center a WPF window with respect to a WPF owner window in both low and high DPI. However, this code may not center a WPF window with respect to a non-WPF owner window in high DPI. In this case, you need to perform a little extra work to convert the non-WPF owner window’s location and size into device-independent versions that the WPF owned window can calculate against. This work is facilitated by HwndSource:

    using System.Windows; // Window, WindowStartupLocation, Point

    using System.Windows.Interop; // WindowInteropHelper, HwndSource

    using System.Windows.Media; // Matrix

    ...

    // Instantiate the owned WPF window

    CenteredWindow cw = new CenteredWindow();

    // Get the handle to the non-WPF owner window

    IntPtr ownerWindowHandle = ...; // Get hWnd for non-WPF window

    // Set the owned WPF window’s owner with the non-WPF owner window

    WindowInteropHelper helper = new WindowInteropHelper(cw);

    helper.Owner = ownerWindowHandle;

    // Center window

    // Note - Need to use HwndSource to get handle to WPF owned window,

    //        and the handle only exists when SourceInitialized has been

    //        raised

    cw.SourceInitialized += delegate

    {

        // Get WPF size and location for non-WPF owner window

        int nonWPFOwnerLeft = ...; // Get non-WPF owner’s Left

        int nonWPFOwnerWidth = ...; // Get non-WPF owner’s Width

        int nonWPFOwnerTop = ...; // Get non-WPF owner’s Top

        int nonWPFOwnerHeight = ...; // Get non-WPF owner’s Height

        // Get transform matrix to transform non-WPF owner window

        // size and location units into device-independent WPF

        // size and location units

        HwndSource source = HwndSource.FromHwnd(helper.Handle);

        if (source == null) return;

        Matrix matrix = source.CompositionTarget.TransformFromDevice;

        Point ownerWPFSize = matrix.Transform(

          new Point(nonWPFOwnerWidth, nonWPFOwnerHeight));

        Point ownerWPFPosition = matrix.Transform(

          new Point(nonWPFOwnerLeft, nonWPFOwnerTop));

        // Center WPF window

        cw.WindowStartupLocation = WindowStartupLocation.Manual;

        cw.Left = ownerWPFPosition.X + (ownerWPFSize.X - cw.Width) / 2;

        cw.Top = ownerWPFPosition.Y + (ownerWPFSize.Y - cw.Height) / 2;

    };

    // Show WPF owned window

    cw.Show();

    This code basically converts the non-device-independent size and position of the non-WPF owner window, and converts them to device-independent values. This allows you to calculate the Top and Left values that will cause the owned WPF window to be appeared centered. This requires a little help from HwndSource, which is used to do the co-ordinate system conversion (or transforms). HwndSource relies on the WPF window having a hWnd, which doesn’t happen until the SourceInitialized event is raised. Hence the anonymous delegate code.

    This solution is generalized, but does work in both normal and high DPI.

  • 相关阅读:
    Spring.NET学习笔记
    开源项目地址
    委托的实现匿名函数和朗姆达表达式
    c#事件与委托
    c# 时间戳转换
    List 排序
    DDD的好文章
    【转】理解JMeter聚合报告(Aggregate Report)
    【转】JMeter 通过 JDBC 访问 Oracle 和 MySQL
    【转】使用JMeter测试你的EJB
  • 原文地址:https://www.cnblogs.com/lzjsky/p/1797810.html
Copyright © 2020-2023  润新知