private void OnDpiChangedInteranl()
        {
            ScaleFactor = new DPI(CurrentDpi.X / WpfDpi.X, CurrentDpi.Y / WpfDpi.Y);
            UpdateLayoutTransform(ScaleFactor);

            OnDpiChanged();
        }
        /// <summary>
        /// Uodate <see cref="Window.LayoutTransform"/> of the current <see cref="DpiAwareWindow"/>.
        /// </summary>
        /// <param name="scaleFactor"><see cref="DPI"/> representing scale factor.</param>
        private void UpdateLayoutTransform(DPI scaleFactor)
        {
            if (IsPerMonitorEnabled == false)
            {
                return;
            }

            var child = GetVisualChild(0);

            if ((scaleFactor.X != 1.0) || (scaleFactor.Y != 1.0))
            {
                child?.SetValue(LayoutTransformProperty, new ScaleTransform(scaleFactor.X, scaleFactor.Y));
            }
            else
            {
                child?.SetValue(LayoutTransformProperty, null);
            }
        }
        /// <summary>
        /// <see cref="FrameworkElement.Loaded"/> event handler.
        /// </summary>
        /// <param name="sender">event sender.</param>
        /// <param name="args">event arguments.</param>
        protected virtual void OnLoaded(object sender, RoutedEventArgs args)
        {
            // WPF has already scaled window size, graphics and text based on system DPI. In order to scale the window based on monitor DPI, update the
            // window size, graphics and text based on monitor DPI. For example consider an application with size 600 x 400 in device independent pixels
            //		- Size in device independent pixels = 600 x 400
            //		- Size calculated by WPF based on system/WPF DPI = 192 (scale factor = 2)
            //		- Expected size based on monitor DPI = 144 (scale factor = 1.5)

            // Similarly the graphics and text are updated updated by applying appropriate scale transform to the top level node of the WPF application

            // Important Note: This method overwrites the size of the window and the scale transform of the root node of the WPF Window. Hence,
            // this sample may not work "as is" if
            //	- The size of the window impacts other portions of the application like this WPF  Window being hosted inside another application.
            //  - The WPF application that is extending this class is setting some other transform on the root visual; the sample may
            //     overwrite some other transform that is being applied by the WPF application itself.

            SystemDpi = DpiHelper.GetSystemDpi();
            var source = (HwndSource)PresentationSource.FromVisual(this);

            source?.AddHook(WindowProcedureHook);

            // Calculate the DPI used by WPF.
            var transform = source?.CompositionTarget?.TransformToDevice;

            WpfDpi = new DPI(96 * (transform?.M11 ?? 1), 96 * (transform?.M22 ?? 1));

            if (IsPerMonitorEnabled && (source != null))
            {
                // Get the Current DPI of the monitor of the window.
                CurrentDpi = DpiHelper.GetDpiForHwnd(source.Handle);

                // Calculate the scale factor used to modify window size, graphics and text.
                ScaleFactor = new DPI(CurrentDpi.X / WpfDpi.X, CurrentDpi.Y / WpfDpi.Y);
            }

            UpdateWindowSize();
            UpdateLocation();

            // Update graphics and text based on the current DPI of the monitor.
            UpdateLayoutTransform(ScaleFactor);
            OnDpiChanged();
        }
        /// <summary>
        /// Message handler of the Per_Monitor_DPI_Aware window. The handles the WM_DPICHANGED message and adjusts window size, graphics and text
        /// based on the DPI of the monitor. The window message provides the new window size (lparam) and new DPI (wparam)
        /// </summary>
        protected virtual IntPtr WindowProcedureHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            switch ((user32.WinMessages)msg)
            {
            case user32.WinMessages.WM_DPICHANGED:

                if (IsPerMonitorEnabled)
                {
                    user32.RECT newRect = (user32.RECT)Marshal.PtrToStructure(lParam, typeof(user32.RECT));
                    user32.SetWindowPos(hwnd, 0, newRect.Left, newRect.Top, newRect.Right - newRect.Left,
                                        newRect.Bottom - newRect.Top,
                                        user32.SWP_NOZORDER | user32.SWP_NOOWNERZORDER | user32.SWP_NOACTIVATE);

                    // Set the Window's position & size.
                    //Vector ul = source.CompositionTarget.TransformFromDevice.Transform(new Vector(newRect.Left, newRect.Top));
                    //Vector hw = source.CompositionTarget.TransformFromDevice.Transform(new Vector(newRect.Right = newRect.Left, newRect.Bottom - newRect.Top));
                    //Left = ul.X;
                    //Top = ul.Y;
                    //Width = hw.X;
                    //Height = hw.Y;

                    // Remember the current DPI settings.
                    var oldDpi = CurrentDpi;

                    // Get the new DPI settings from wParam
                    CurrentDpi = new DPI(wParam.ToInt32() >> 16, wParam.ToInt32() & 0x0000FFFF);
                    if ((oldDpi.X != CurrentDpi.X) || (oldDpi.Y != CurrentDpi.Y))
                    {
                        OnDpiChangedInteranl();
                    }

                    handled = true;
                }
                break;
            }
            return(IntPtr.Zero);
        }