-
Notifications
You must be signed in to change notification settings - Fork 24
/
WindowControl.cs
208 lines (186 loc) · 10.3 KB
/
WindowControl.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace DevZest.Windows
{
/// <summary>Represents a movable and resizable window hosted in <see cref="WindowPanel"/>.</summary>
/// <remarks>
/// <para>
/// Use <see cref="Left"/> and <see cref="Top"/> to specify the location of the window.
/// <see cref="Double.NaN"/> value results in auto location - the location will be
/// decided by its containing <see cref="WindowPanel"/>. The containing <see cref="WindowPanel"/>
/// sets the window's <see cref="ActualLeft"/> and <see cref="ActualTop"/> properties.
/// </para>
/// <para>
/// Use <see cref="P:DevZest.Windows.WindowControl.Hotspot"/> attached property to specify the <see cref="WindowHotspot"/>
/// mouse dragging value for elements in the control template. By default,
/// <see cref="WindowControl"/> inherits <see cref="ContentControl"/>'s control template which
/// provides no movable or resizable user interface.
/// </para>
/// </remarks>
/// <example>
/// This example demostrates use of <see cref="WindowPanel"/> and <see cref="WindowControl"/>
/// (reference to assembly PresentationFramework.Classic.dll required):
/// <code lang="xaml" source="..\..\Samples\Common\CSharp\WindowPanelAndWindowControlSample\Window1.xaml" />
/// </example>
public partial class WindowControl : ContentControl, IWindow
{
/// <summary>Identifies the <see cref="P:DevZest.Windows.WindowControl.Hotspot"/> attached property.</summary>
/// <AttachedPropertyComments>
/// <summary>Gets or sets the the <see cref="WindowHotspot"/> value.</summary>
/// <value>One of the <see cref="WindowHotspot"/> values. The default value is <see cref="WindowHotspot.None"/>.</value>
/// </AttachedPropertyComments>
public static readonly DependencyProperty HotspotProperty;
/// <summary>Identifies the <see cref="Left"/> dependency property.</summary>
public static readonly DependencyProperty LeftProperty;
/// <summary>Identifies the <see cref="Top"/> dependency property.</summary>
public static readonly DependencyProperty TopProperty;
private static readonly DependencyPropertyKey ActualLeftPropertyKey;
private static readonly DependencyPropertyKey ActualTopPropertyKey;
/// <summary>Identifies the <see cref="ActualLeft"/> dependency property.</summary>
public static readonly DependencyProperty ActualLeftProperty;
/// <summary>Identifies the <see cref="ActualTop"/> dependency property.</summary>
public static readonly DependencyProperty ActualTopProperty;
[SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
static WindowControl()
{
HotspotProperty = DependencyProperty.RegisterAttached("Hotspot", typeof(WindowHotspot), typeof(WindowControl),
new FrameworkPropertyMetadata(WindowHotspot.None));
TopProperty = DependencyProperty.Register("Top", typeof(double), typeof(WindowControl),
new FrameworkPropertyMetadata(double.NaN, FrameworkPropertyMetadataOptions.AffectsParentArrange));
LeftProperty = DependencyProperty.Register("Left", typeof(double), typeof(WindowControl),
new FrameworkPropertyMetadata(double.NaN, FrameworkPropertyMetadataOptions.AffectsParentArrange));
ActualLeftPropertyKey = DependencyProperty.RegisterReadOnly("ActualLeft", typeof(double), typeof(WindowControl),
new FrameworkPropertyMetadata(double.NaN));
ActualTopPropertyKey = DependencyProperty.RegisterReadOnly("ActualTop", typeof(double), typeof(WindowControl),
new FrameworkPropertyMetadata(double.NaN));
ActualLeftProperty = ActualLeftPropertyKey.DependencyProperty;
ActualTopProperty = ActualTopPropertyKey.DependencyProperty;
FocusableProperty.OverrideMetadata(typeof(WindowControl), new FrameworkPropertyMetadata(BooleanBoxes.False));
FocusManager.IsFocusScopeProperty.OverrideMetadata(typeof(WindowControl), new FrameworkPropertyMetadata(BooleanBoxes.False));
}
/// <summary>Gets the value of <see cref="P:DevZest.Windows.WindowControl.Hotspot"/> attached property for a given <see cref="DependencyObject"/>.</summary>
/// <param name="element">The element from which the property value is read.</param>
/// <returns>The value of <see cref="P:DevZest.Windows.WindowControl.Hotspot"/> attached property.</returns>
public static WindowHotspot GetHotspot(DependencyObject element)
{
return (WindowHotspot)element.GetValue(HotspotProperty);
}
/// <summary>Sets the value of <see cref="P:DevZest.Windows.WindowControl.Hotspot"/> attached property for a given dependency object.</summary>
/// <param name="element">The element to which the property value is written.</param>
/// <param name="value">The value of <see cref="P:DevZest.Windows.WindowControl.Hotspot"/> attached property.</param>
public static void SetHotspot(DependencyObject element, WindowHotspot value)
{
element.SetValue(HotspotProperty, value);
}
/// <summary>Gets or sets a value that represents the distance between the left side of <see cref="WindowControl"/> and the left side of its parent <see cref="WindowPanel"/>. This is a dependency property.</summary>
/// <value>A <see cref="Double"/> that represents the offset position from the left side of a parent <see cref="WindowPanel"/>. The default value is <see cref="Double.NaN"/>.</value>
public double Left
{
get { return (double)GetValue(LeftProperty); }
set { SetValue(LeftProperty, value); }
}
/// <summary>Gets or sets a value that represents the distance between the top side of <see cref="WindowControl"/> and the top side of its parent <see cref="WindowPanel"/>. This is a dependency property.</summary>
/// <value>A <see cref="Double"/> that represents the offset position from the top side of a parent <see cref="WindowPanel"/>. The default value is <see cref="Double.NaN"/>.</value>
public double Top
{
get { return (double)GetValue(TopProperty); }
set { SetValue(TopProperty, value); }
}
/// <summary>Gets the actual left position of this <see cref="WindowControl"/>.</summary>
/// <value>The <see cref="WindowControl"/>'s left position, as a value in device-independent units (1/96th inch per unit).</value>
public double ActualLeft
{
get { return (double)GetValue(ActualLeftProperty); }
internal set { SetValue(ActualLeftPropertyKey, value); }
}
/// <summary>Gets the actual top position of this <see cref="WindowControl"/>.</summary>
/// <value>The <see cref="WindowControl"/>'s top position, as a value in device-independent units (1/96th inch per unit).</value>
public double ActualTop
{
get { return (double)GetValue(ActualTopProperty); }
internal set { SetValue(ActualTopPropertyKey, value); }
}
/// <exclude/>
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
if (e.Handled)
return;
BeginDrag(this, TopLevelWindow, e);
}
internal static bool BeginDrag(UIElement container, IWindow topLevelWindow, MouseButtonEventArgs e)
{
UIElement element = e.OriginalSource as UIElement;
WindowHotspot hotspot = WindowHotspot.None;
while (element != null && element != container)
{
hotspot = GetHotspot(element);
if (hotspot != WindowHotspot.None)
break;
element = VisualTreeHelper.GetParent(element) as UIElement;
}
if (hotspot == WindowHotspot.None)
return false;
if (e.ClickCount == 1)
{
DragHandler.Default.BeginDrag(topLevelWindow, element, e);
e.Handled = true;
return true;
}
return false;
}
IWindow TopLevelWindow
{
get
{
IWindow topLevelWindow = this;
for (DependencyObject parent = VisualTreeHelper.GetParent(this); parent != null; parent = VisualTreeHelper.GetParent(parent))
{
if (parent is IWindow)
topLevelWindow = parent as IWindow;
}
return topLevelWindow;
}
}
/// <summary>Gets the adjusted location to ensure the window is visible in its container.</summary>
/// <param name="containerSize">The size of its container.</param>
/// <param name="windowBounds">The window bounds.</param>
/// <returns>The adjusted location.</returns>
protected internal virtual Point EnsureVisibleLocation(Size containerSize, Rect windowBounds)
{
double x = windowBounds.X;
if (x > containerSize.Width - SystemParameters.CaptionWidth)
x = containerSize.Width - SystemParameters.CaptionWidth;
if (x < SystemParameters.CaptionWidth - windowBounds.Width)
x = SystemParameters.CaptionWidth - windowBounds.Width;
double y = windowBounds.Y;
if (y > containerSize.Height - SystemParameters.CaptionHeight)
y = containerSize.Height - SystemParameters.CaptionHeight;
if (y < 0)
y = 0;
return new Point(x, y);
}
Rect IWindow.Bounds
{
get { return new Rect(Left, Top, Width, Height); }
}
Rect IWindow.ActualBounds
{
get { return new Rect(ActualLeft, ActualTop, ActualWidth, ActualHeight); }
}
void IWindow.SetBounds(Rect bounds)
{
BeginInit();
Left = bounds.Left;
Top = bounds.Top;
Width = bounds.Width;
Height = bounds.Height;
EndInit();
}
}
}