none
Workaround: Silverlight OOB error when maximizing second monitor with borderless chrome

    Question

  • There is a bug in Silverlight that occurs when an out-of-browser (OOB) app that has a borderless chrome  maximizes the window on a second monitor.  The window either doesn't display at all or only a small part of it displays. 

    I developed a workaround.  It seems to work OK with my laptop and second monitor, but I haven't tested it anywhere else. 

    Caveats:

    It may not work if the primary window is an attached monitor.  Further tweaking will address that.

    It gets information from Windows, so I don't know if it will work with any computers that aren't running Windows, such as Apple.

            void MinimizeButton_Click(object sender, RoutedEventArgs e)
            {
                // Silverlight Bug:  
                //   This is supposed to work just by setting to WindowState.Minimized.
                //   But if it has borderless chrome, it doesn't display properly when restored from tray.
                // Work-around:  
                //   Set to WindowState.Normal, and set window to reduced monitor dimensions before minimizing. 
                //   Then it will restore properly from tray using these dimensions.
                if (Application.Current.IsRunningOutOfBrowser)
                {
                    Application.Current.MainWindow.WindowState = WindowState.Normal;
    
                    // Get the dimensions for the monitor that the window is on.
                    Win32Rect myWin32Rect = GetMonitorDimensions();
    
                    // Give Windows the Top and Left positions so that it knows which monitor its on.
                    // Give it the monitor resolution -- the monitor's height and width.
                    Window winZ = Application.Current.MainWindow;
                    winZ.Top = myWin32Rect.Top;
                    winZ.Height = myWin32Rect.Bottom;
                    winZ.Left = myWin32Rect.Left;
                    winZ.Width = myWin32Rect.Right - myWin32Rect.Left;
    
                    // Shrink the dimensions to create a 'Normal' size.
                    winZ.Height = winZ.Height - (0.30 * winZ.Height);
                    winZ.Top = winZ.Top + (0.15 * winZ.Height);
                    winZ.Left = winZ.Left + (0.15 * winZ.Left);
                    winZ.Width = winZ.Width - (0.30 * winZ.Width);
    
                    // Minimize the window
                    Application.Current.MainWindow.WindowState = WindowState.Minimized;
                }
            }
    
            void MaximizeButton_Click(object sender, RoutedEventArgs e)
            {
                if (Application.Current.IsRunningOutOfBrowser)
                {
                    if (Application.Current.MainWindow.WindowState == WindowState.Maximized)
                    {
                        Application.Current.MainWindow.WindowState = WindowState.Normal;
                    }
                    else
                    {
                        if (Application.Current.HasElevatedPermissions)
                        {
                            // Silverlight Bug:  
                            //   Window won't maximize on second monitor if borderless chrome.  The window is hidden.
                            // Work-around.
                            //   Setting to WindowState.Maximized causes the problem.
                            //   So make it work by setting the window to the monitor dimensions.
    
                            // Let Windows think it's in maximized state,
                            //    since we're going to set the dimensions to maximize the window.
                            Application.Current.MainWindow.WindowState = WindowState.Maximized;
    
                            // Get the dimensions for the monitor that the window is on.
                            Win32Rect myWin32Rect = GetMonitorDimensions();
    
                            // Give Windows the Top and Left positions so that it knows which monitor its on.
                            // Give it the monitor resolution -- the monitor's height and width.
                            Window winZ = Application.Current.MainWindow;
                            winZ.Top = myWin32Rect.Top;
                            winZ.Height = myWin32Rect.Bottom;
                            winZ.Left = myWin32Rect.Left;
                            winZ.Width = myWin32Rect.Right - myWin32Rect.Left;
                        }
                        else
                        {
                            MessageBox.Show("Cannot maximize window without elevated permissions.");
                        }
                    }
                }
            }
            
            void CloseButton_Click(object sender, RoutedEventArgs e)
            {
                if (Application.Current.IsRunningOutOfBrowser)
                    Application.Current.MainWindow.Close();
            }
    
            /// <summary>
            /// Get the Dimensions for the monitor that is displaying the left side of the window.
            /// </summary>
            /// <returns></returns>
            private Win32Rect GetMonitorDimensions()
            {
                // Get information from Windows about ALL of the monitors.
                DisplayManager.Displays.Clear();
                DisplayManager.LoadDisplays();
    
                Window winX = Application.Current.MainWindow;
                Win32Rect myWin32Rect = new Win32Rect();
    
                // Scan the list of displays.  
                // Get the dimensions of the monitor that contains the left edge of the window.
                // Application.Current.MainWindow.Left = Left edge of where window is now.
                foreach (DisplayInfo myDisplayInfo in DisplayManager.Displays)
                {
                    // If the leftmost position of the current window is within the dimensions 
                    // of this monitor, get the dimensions of the monitor.
                    if (winX.Left >= myDisplayInfo.MonitorArea.Left && 
                        winX.Left <= myDisplayInfo.MonitorArea.Right)
                    {
                        myWin32Rect.Top = myDisplayInfo.MonitorArea.Top;
                        myWin32Rect.Bottom = myDisplayInfo.MonitorArea.Bottom;
                        myWin32Rect.Left = myDisplayInfo.MonitorArea.Left;
                        myWin32Rect.Right = myDisplayInfo.MonitorArea.Right;
                    }
                }
                return myWin32Rect;
            }
    using System;
    using System.Collections.ObjectModel;
    using System.Net;
    using System.Runtime.InteropServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    
    // This module was created by copying code from a post by Pete Brown.
    // http://10rem.net/blog/2012/02/07/creating-big-silverlight-windows-and-getting-monitor-resolutions-and-positions-with-pinvoke 
    
    namespace NW6ViewModel
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct Win32Rect
        {
            public int Left { get; set; }
            public int Top { get; set; }
            public int Right { get; set; }
            public int Bottom { get; set; }
    
            public override string ToString()
            {
                return string.Format("{0}, {1}, {2}, {3}", Left, Top, Right, Bottom);
            }
        }
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
        internal struct MonitorInfoEx
        {
            public int Size;
            public Win32Rect Monitor;
            public Win32Rect WorkArea;
            public uint Flags;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = DisplayManager.DeviceNameCharacterCount)]
            public string DeviceName;
    
            public void Init()
            {
                this.Size = 40 + 2 * DisplayManager.DeviceNameCharacterCount;
                this.DeviceName = string.Empty;
            }
        }
    
        public class DisplayInfo
        {
            public string MonitorName { get; internal set; }
            public Win32Rect MonitorArea { get; internal set; }
            public Win32Rect WorkArea { get; internal set; }
            public int Width { get; internal set; }
            public int Height { get; internal set; }
            public bool IsPrimary { get; internal set; }
        }
    
    
        /// <summary>
        /// This class is used to get information about all of the monitors attached to a PC.
        /// </summary>
        public class DisplayManager
        {
            // size of a device name string
            internal const int DeviceNameCharacterCount = 32;
    
            private delegate bool MonitorEnumProcDelegate(IntPtr hMonitor, IntPtr hdcMonitor, ref Win32Rect lprcMonitor, uint dwData);
    
            [DllImport("user32.dll")]
            private static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, MonitorEnumProcDelegate lpfnEnum, uint dwData);
    
            [DllImport("user32.dll", CharSet = CharSet.Auto)]
            private static extern bool GetMonitorInfo(IntPtr hMonitor, ref MonitorInfoEx lpmi);
    
            private static ObservableCollection<DisplayInfo> _displays = new ObservableCollection<DisplayInfo>();
            public static ObservableCollection<DisplayInfo> Displays
            {
                get { return _displays; }
            }
    
    
            /// <summary>
            /// Get information about all of the monitors on the PC.
            /// Copy it into the Displays ObservableCollection.
            /// </summary>
            public static void LoadDisplays()
            {
                EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, MonitorEnumProc, 0);
            }
    
            [AllowReversePInvokeCalls]
            internal static bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdcMonitor, ref Win32Rect lprcMonitor, uint dwData)
            {
                var monitor = new MonitorInfoEx();
                monitor.Init();
    
                bool success = GetMonitorInfo(hMonitor, ref monitor);
    
                if (success)
                {
                    var display = new DisplayInfo();
    
                    display.MonitorName = monitor.DeviceName;
    
                    display.Width = monitor.Monitor.Right - monitor.Monitor.Left;
                    display.Height = monitor.Monitor.Bottom - monitor.Monitor.Top;
    
                    display.MonitorArea = monitor.Monitor;
                    display.WorkArea = monitor.WorkArea;
                    display.IsPrimary = (monitor.Flags > 0);
    
                    _displays.Add(display);
                }
    
                return true;
            }
        }
    }
    
    If you try this, let me know if it has any problems. Also, how can it be improved?  Or do you know of a better workaround?

     

     


    Gary Frank

    Friday, August 16, 2013 8:02 PM

Answers

  • It seems to work fine for me.  If you try this, let me know if it has any problems. Also, how can it be improved?  Or do you know of a better workaround?


    Gary Frank

    18 hours 29 minutes ago