Beispiel #1
0
        internal void Initialize(Window window, FrameworkElement element = null)
        {
            if (window == null)
            {
                throw new ArgumentNullException(nameof(window));
            }

            if (!window.IsInitialized)
            {
                throw new InvalidOperationException("Target Window has not been initialized.");
            }

            _targetWindow  = window;
            _targetElement = element;

            ForbearScaling = WillForbearScalingIfUnnecessary && BuiltinFunction.IsScalingSupported(_targetWindow);

            if (IsPerMonitorDpiAware)
            {
                MonitorDpi = DpiChecker.GetDpiFromVisual(_targetWindow);

                if (MonitorDpi.Equals(SystemDpi) || ForbearScaling)
                {
                    WindowDpi = MonitorDpi;
                }
                else
                {
                    var newInfo = new WindowInfo
                    {
                        Dpi    = MonitorDpi,
                        Width  = _targetWindow.Width * (double)MonitorDpi.X / SystemDpi.X,
                        Height = _targetWindow.Height * (double)MonitorDpi.Y / SystemDpi.Y,
                    };

                    Interlocked.Exchange(ref _dueInfo, newInfo);

                    ChangeDpi();
                }
            }
            else
            {
                MonitorDpi = SystemDpi;
                WindowDpi  = MonitorDpi;
            }

            ColorProfilePath = ColorProfileChecker.GetColorProfilePath(_targetWindow);

            _targetSource = PresentationSource.FromVisual(_targetWindow) as HwndSource;
            _targetSource?.AddHook(WndProc);
        }
Beispiel #2
0
        private void ChangeDpi(WindowStatus status = WindowStatus.None)
        {
            if (Interlocked.CompareExchange(ref _blocker, new object(), null) != null)
            {
                return;
            }

            try
            {
                // Take information which is to be tested from _dueInfo and set null in return.
                var testInfo = Interlocked.Exchange(ref _dueInfo, null);

                while (testInfo != null)
                {
                    var testRect = new Rect(new Point(_targetWindow.Left, _targetWindow.Top), testInfo.Size);

                    bool changesNow = true;

                    switch (status)
                    {
                    case WindowStatus.None:
                    case WindowStatus.SizeChanged:
                        // None.
                        break;

                    case WindowStatus.LocationChanged:
                        // Determine whether to reflect information now.
                        var testDpi = DpiChecker.GetDpiFromRect(testRect);

                        changesNow = testInfo.Dpi.Equals(testDpi);
                        break;
                    }

                    if (changesNow)
                    {
                        // Update WindowDpi first so that it can provide new DPI during succeeding changes in target
                        // Window.
                        var oldDpi = WindowDpi;
                        WindowDpi = testInfo.Dpi;

                        switch (status)
                        {
                        case WindowStatus.None:
                        case WindowStatus.LocationChanged:
                            // Change location and size of target Window. Setting these properties may fire
                            // LocationChanged and SizeChanged events twice in target Window. However, to use
                            // SetWindowPos function, a complicated conversion of coordinates is required.
                            // Also, it may cause a problem in applying styles if used in OnSourceInitialized
                            // method.
                            Debug.WriteLine($"Old Size: {_targetWindow.Width}-{_targetWindow.Height}");

                            _targetWindow.Left   = testRect.Left;
                            _targetWindow.Top    = testRect.Top;
                            _targetWindow.Width  = testRect.Width;
                            _targetWindow.Height = testRect.Height;

                            Debug.WriteLine($"New Size: {_targetWindow.Width}-{_targetWindow.Height}");
                            break;

                        case WindowStatus.SizeChanged:
                            // None.
                            break;
                        }

                        // Scale contents of target Window.
                        var content = _targetElement ?? _targetWindow.Content as FrameworkElement;
                        if (content != null)
                        {
                            content.LayoutTransform = (testInfo.Dpi.Equals(SystemDpi))
                                                                ? Transform.Identity
                                                                : new ScaleTransform(
                                (double)WindowDpi.X / SystemDpi.X,
                                (double)WindowDpi.Y / SystemDpi.Y);
                        }

                        // Fire DpiChanged event last so that it can be utilized to supplement preceding changes
                        // in target Window.
                        DpiChanged?.Invoke(this, new DpiChangedEventArgs(oldDpi, WindowDpi));

                        // Take new information which is to be tested from _dueInfo again for the case where new
                        // information has been stored during this operation. If there is new information, repeat
                        // the operation.
                        testInfo = Interlocked.Exchange(ref _dueInfo, null);
                    }
                    else
                    {
                        // Store old information which has been tested but determined not to be reflected now to
                        // _dueInfo and take new information in return. If there is new information, repeat
                        // the operation. If not, old information stored back may be overwritten by new information
                        // later but has a chance to be tested again in the case where it is the last information
                        // at this move/resize. In such case, the information may be tested at next move/resize.
                        testInfo = Interlocked.Exchange(ref _dueInfo, testInfo);
                    }
                }
            }
            finally
            {
                Interlocked.Exchange(ref _blocker, null);
            }
        }