bovender framework
C# framework that implements MVVM and more
WindowState.cs
1 /* WindowState.cs
2  * part of Daniel's XL Toolbox NG
3  *
4  * Copyright 2014-2018 Daniel Kraus
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 using System;
19 using System.Collections.Generic;
20 using System.Linq;
21 using System.Text;
22 using System.Windows;
23 using System.Windows.Forms;
24 using System.Windows.Interop;
25 using System.Windows.Media;
26 
27 namespace Bovender.Mvvm.Views.Settings
28 {
33  public static class WindowState
34  {
35  #region Attached property "Save"
36 
37  public static readonly DependencyProperty SaveProperty = DependencyProperty.RegisterAttached(
38  "Save", typeof(bool), typeof(WindowState), new PropertyMetadata(OnSavePropertyChanged));
39 
40  [AttachedPropertyBrowsableForType(typeof(Window))]
41  public static bool GetSave(UIElement element)
42  {
43  return (bool)element.GetValue(SaveProperty);
44  }
45 
46  public static void SetSave(UIElement element, bool value)
47  {
48  element.SetValue(SaveProperty, value);
49  }
50 
51  private static void OnSavePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
52  {
53  if (e.Property == SaveProperty)
54  {
55  Window window = obj as Window;
56  if (window != null)
57  {
58  if ((bool)e.NewValue == true)
59  {
60  window.Closed += SaveWindowGeometry;
61  window.Initialized += LoadWindowGeometry;
62  }
63  else
64  {
65  window.Closed -= SaveWindowGeometry;
66  window.Initialized -= LoadWindowGeometry;
67  }
68  }
69  }
70  }
71 
72  #endregion
73 
74  #region Attached property "CenterScreen"
75 
76  public static readonly DependencyProperty CenterScreenProperty = DependencyProperty.RegisterAttached(
77  "CenterScreen", typeof(bool), typeof(WindowState), new PropertyMetadata(OnCenterScreenPropertyChanged));
78 
87  [AttachedPropertyBrowsableForType(typeof(Window))]
88  public static bool GetCenterScreen(UIElement element)
89  {
90  return (bool)element.GetValue(CenterScreenProperty);
91  }
92 
93  public static void SetCenterScreen(UIElement element, bool value)
94  {
95  element.SetValue(CenterScreenProperty, value);
96  }
97 
98  private static void OnCenterScreenPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
99  {
100  if (e.Property == CenterScreenProperty)
101  {
102  Window window = obj as Window;
103  if (window != null)
104  {
105  if ((bool)e.NewValue == true)
106  {
107  // Must not use the Initialized event here
108  // Only when Loaded is raised, the window handle will be accessible
109  window.Loaded += CenterWindow;
110  }
111  }
112  }
113  }
114 
115  private static void CenterWindow(object sender, EventArgs e)
116  {
117  Window w = sender as Window;
118  Screen screen = Screen.FromHandle(new WindowInteropHelper(w).Handle);
119  PresentationSource ps = PresentationSource.FromVisual(w);
120  CompositionTarget ct = ps.CompositionTarget;
121  Matrix t = ct.TransformFromDevice;
122  Point screenGeo = t.Transform(new Point(screen.Bounds.Width, screen.Bounds.Height));
123  double screenWidth = screenGeo.X;
124  double screenHeight = screenGeo.Y;
125  w.Left = Math.Max((screenWidth - w.ActualWidth) / 2, 0);
126  w.Top = Math.Max((screenHeight - w.ActualHeight) / 2, 0);
127  }
128 
129  #endregion
130 
131  #region Event handlers
132 
133  static void LoadWindowGeometry(object sender, EventArgs e)
134  {
135  WindowSettings s = WindowSettingsFactory(sender);
136  Window w = sender as Window;
137  s.Reload();
138  if (s.Rect != Rect.Empty)
139  {
140  w.Left = s.Rect.Left;
141  w.Top = s.Rect.Top;
142  w.Width = s.Rect.Width;
143  w.Height = s.Rect.Height;
144  SanitizeWindowGeometry(w);
145 
146  // Since the CenterScreen function is hooked to the
147  // Window.Loaded event, which is raised after the
148  // Window.Initialize event that leads to the current
149  // function call, we need to make sure that the window
150  // is not centered if we use previously saved geometry.
151  w.Loaded -= CenterWindow;
152  }
153  w.WindowState = s.State;
154  }
155 
156  static void SaveWindowGeometry(object sender, EventArgs e)
157  {
158  WindowSettings s = WindowSettingsFactory(sender);
159  Window w = sender as Window;
160  s.Rect = new Rect(w.Left, w.Top, w.Width, w.Height);
161  s.State = w.WindowState;
162  s.Screen = Screen.FromHandle(new WindowInteropHelper(w).Handle);
163  s.Save();
164  }
165 
166  #endregion
167 
168  #region Private methods
169 
170  static WindowSettings WindowSettingsFactory(object obj)
171  {
172  Window w = obj as Window;
173  if (w != null)
174  {
175  return new WindowSettings(w);
176  }
177  else
178  {
179  throw new InvalidOperationException("The WindowState.Save property must be attached to Windows only.");
180  }
181  }
182 
187  static void SanitizeWindowGeometry(Window window)
188  {
189  Window w = window;
190  double vleft = SystemParameters.VirtualScreenLeft;
191  double vright = vleft + SystemParameters.VirtualScreenWidth;
192  double vtop = SystemParameters.VirtualScreenTop;
193  double vbottom = vtop + SystemParameters.VirtualScreenHeight;
194 
195  // Make sure that the top left corner of the window
196  // is inside the virtual screen.
197  // Note: Cannot use Window.ActualWidth and Window.ActualHeight
198  // as these won't be initialized yet when this function is called
199  // as a consequence of the Window.Initialize event.
200  if (w.Left < vleft)
201  {
202  w.Left = vleft;
203  }
204  if (w.Left > vright - w.Width)
205  {
206  w.Left = vright - w.Width;
207  }
208  if (w.Top < vtop)
209  {
210  w.Top = vtop;
211  }
212  if (w.Top > vbottom - w.Height)
213  {
214  w.Top = vbottom - w.Height;
215  }
216 
217  // TODO: Make sure the window location is mapped to an actual screen
218  // The virtual screen represents a bounding rectangle that does not
219  // necessarily need to be entirely mapped to physical screens, e.g.
220  // if two monitors are aligned diagonally.
221  }
222 
223  #endregion
224 
225  }
226 }
Provides an attached property to enable Windows to save and restore their screen position and state...
Definition: WindowState.cs:33
static bool GetCenterScreen(UIElement element)
Centers the Window that the property is attached to on the screen that the window is currently being ...
Definition: WindowState.cs:88
Rect Rect
The rectangle describing the window&#39;s coordinates.