├── .gitignore
├── Common
├── Borders
│ ├── ClippingBorder.cs
│ ├── InnerGlowBorder.cs
│ └── OuterGlowBorder.cs
├── DropShadowTextBlock.cs
├── HorizontalToggleSwitch.cs
├── Icons
│ ├── ToggleSwitch.HorizontalToggleSwitch.Expression.Large.png
│ ├── ToggleSwitch.HorizontalToggleSwitch.Expression.Small.png
│ └── ToggleSwitch.HorizontalToggleSwitch.VisualStudio.bmp
├── ToggleSwitchBase.cs
├── Utils
│ ├── ActualSizePropertyProxy.cs
│ ├── CornerRadiusValueConverter.cs
│ ├── HelperExtensions.cs
│ └── ScalarValueConverter.cs
└── VerticalToggleSwitch.cs
├── README.md
├── WPF
├── Demo
│ ├── App.xaml
│ ├── App.xaml.cs
│ ├── Assets
│ │ ├── Brushes.xaml
│ │ ├── Fonts.xaml
│ │ ├── Styles.xaml
│ │ └── ToggleSwitchStyles.xaml
│ ├── Demo.csproj
│ ├── DemoViewModel.cs
│ ├── Images
│ │ ├── Knob.png
│ │ ├── lightOff.png
│ │ └── lightOn.png
│ ├── MainWindow.xaml
│ ├── MainWindow.xaml.cs
│ ├── Properties
│ │ ├── AssemblyInfo.cs
│ │ ├── Resources.Designer.cs
│ │ ├── Resources.resx
│ │ ├── Settings.Designer.cs
│ │ └── Settings.settings
│ ├── Views
│ │ ├── Basics.xaml
│ │ ├── Basics.xaml.cs
│ │ ├── Events.xaml
│ │ ├── Events.xaml.cs
│ │ ├── Extending.xaml
│ │ ├── Extending.xaml.cs
│ │ ├── Styling.xaml
│ │ └── Styling.xaml.cs
│ └── app.config
├── ToggleSwitch.sln
└── ToggleSwitch
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── Themes
│ └── Generic.xaml
│ ├── ToggleSwitch.csproj
│ └── ToggleSwitchKey.snk
└── icon.png
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs)
2 | bin
3 | obj
4 |
5 | # mstest test results
6 | TestResults
7 |
8 | # user files
9 | *.user
10 | *.suo
11 | *ReSharper.*
--------------------------------------------------------------------------------
/Common/Borders/ClippingBorder.cs:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------
2 | //
3 | // (c) 2008 Microsoft Corporation. All rights reserved.
4 | // This source is subject to the Microsoft Public License.
5 | // See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
6 | //
7 | // 07-Oct-2008
8 | // Martin Grayson
9 | // A border that clips its contents.
10 | //-----------------------------------------------------------------------
11 | using System;
12 | using System.ComponentModel;
13 | using System.Windows;
14 | using System.Windows.Controls;
15 | using System.Windows.Media;
16 |
17 | namespace ToggleSwitch.Borders
18 | {
19 | ///
20 | /// A border that clips its contents.
21 | ///
22 | public class ClippingBorder : ContentControl
23 | {
24 | ///
25 | /// The corner radius property.
26 | ///
27 | public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register("CornerRadius", typeof(CornerRadius),
28 | typeof(ClippingBorder),
29 | new PropertyMetadata(CornerRadiusChanged));
30 |
31 | ///
32 | /// The clip content property.
33 | ///
34 | public static readonly DependencyProperty ClipContentProperty = DependencyProperty.Register("ClipContent", typeof(bool), typeof(ClippingBorder),
35 | new PropertyMetadata(ClipContentChanged));
36 |
37 | ///
38 | /// Stores the main border.
39 | ///
40 | private Border _border;
41 |
42 | ///
43 | /// Stores the clip responsible for clipping the bottom left corner.
44 | ///
45 | private RectangleGeometry _bottomLeftClip;
46 |
47 | ///
48 | /// Stores the bottom left content control.
49 | ///
50 | private ContentControl _bottomLeftContentControl;
51 |
52 | ///
53 | /// Stores the clip responsible for clipping the bottom right corner.
54 | ///
55 | private RectangleGeometry _bottomRightClip;
56 |
57 | ///
58 | /// Stores the bottom right content control.
59 | ///
60 | private ContentControl _bottomRightContentControl;
61 |
62 | ///
63 | /// Stores the clip responsible for clipping the top left corner.
64 | ///
65 | private RectangleGeometry _topLeftClip;
66 |
67 | ///
68 | /// Stores the top left content control.
69 | ///
70 | private ContentControl _topLeftContentControl;
71 |
72 | ///
73 | /// Stores the clip responsible for clipping the top right corner.
74 | ///
75 | private RectangleGeometry _topRightClip;
76 |
77 | ///
78 | /// Stores the top right content control.
79 | ///
80 | private ContentControl _topRightContentControl;
81 |
82 | ///
83 | /// ClippingBorder constructor.
84 | ///
85 | public ClippingBorder()
86 | {
87 | DefaultStyleKey = typeof(ClippingBorder);
88 | SizeChanged += ClippingBorderSizeChanged;
89 | }
90 |
91 | ///
92 | /// Gets or sets the border corner radius.
93 | /// This is a thickness, as there is a problem parsing CornerRadius types.
94 | ///
95 | [Category("Appearance"), Description("Sets the corner radius on the border.")]
96 | public CornerRadius CornerRadius
97 | {
98 | get
99 | {
100 | return (CornerRadius)GetValue(CornerRadiusProperty);
101 | }
102 |
103 | set
104 | {
105 | SetValue(CornerRadiusProperty, value);
106 | }
107 | }
108 |
109 | ///
110 | /// Gets or sets a value indicating whether the content is clipped.
111 | ///
112 | [Category("Appearance"), Description("Sets whether the content is clipped or not.")]
113 | public bool ClipContent
114 | {
115 | get
116 | {
117 | return (bool)GetValue(ClipContentProperty);
118 | }
119 | set
120 | {
121 | SetValue(ClipContentProperty, value);
122 | }
123 | }
124 |
125 | ///
126 | /// Gets the UI elements out of the template.
127 | ///
128 | public override void OnApplyTemplate()
129 | {
130 | base.OnApplyTemplate();
131 |
132 | _border = GetTemplateChild("PART_Border") as Border;
133 | _topLeftContentControl = GetTemplateChild("PART_TopLeftContentControl") as ContentControl;
134 | _topRightContentControl = GetTemplateChild("PART_TopRightContentControl") as ContentControl;
135 | _bottomRightContentControl = GetTemplateChild("PART_BottomRightContentControl") as ContentControl;
136 | _bottomLeftContentControl = GetTemplateChild("PART_BottomLeftContentControl") as ContentControl;
137 |
138 | if (_topLeftContentControl != null)
139 | {
140 | _topLeftContentControl.SizeChanged += ContentControlSizeChanged;
141 | }
142 |
143 | _topLeftClip = GetTemplateChild("PART_TopLeftClip") as RectangleGeometry;
144 | _topRightClip = GetTemplateChild("PART_TopRightClip") as RectangleGeometry;
145 | _bottomRightClip = GetTemplateChild("PART_BottomRightClip") as RectangleGeometry;
146 | _bottomLeftClip = GetTemplateChild("PART_BottomLeftClip") as RectangleGeometry;
147 |
148 | UpdateClipContent(ClipContent);
149 |
150 | UpdateCornerRadius(CornerRadius);
151 | }
152 |
153 | ///
154 | /// Sets the corner radius.
155 | ///
156 | /// The new corner radius.
157 | internal void UpdateCornerRadius(CornerRadius newCornerRadius)
158 | {
159 | if (_border != null)
160 | {
161 | _border.CornerRadius = newCornerRadius;
162 | }
163 |
164 | if (_topLeftClip != null)
165 | {
166 | _topLeftClip.RadiusX = _topLeftClip.RadiusY = newCornerRadius.TopLeft - (Math.Min(BorderThickness.Left, BorderThickness.Top) / 2);
167 | }
168 |
169 | if (_topRightClip != null)
170 | {
171 | _topRightClip.RadiusX = _topRightClip.RadiusY = newCornerRadius.TopRight - (Math.Min(BorderThickness.Top, BorderThickness.Right) / 2);
172 | }
173 |
174 | if (_bottomRightClip != null)
175 | {
176 | _bottomRightClip.RadiusX = _bottomRightClip.RadiusY = newCornerRadius.BottomRight - (Math.Min(BorderThickness.Right, BorderThickness.Bottom) / 2);
177 | }
178 |
179 | if (_bottomLeftClip != null)
180 | {
181 | _bottomLeftClip.RadiusX = _bottomLeftClip.RadiusY = newCornerRadius.BottomLeft - (Math.Min(BorderThickness.Bottom, BorderThickness.Left) / 2);
182 | }
183 |
184 | UpdateClipSize(new Size(ActualWidth, ActualHeight));
185 | }
186 |
187 | ///
188 | /// Updates whether the content is clipped.
189 | ///
190 | /// Whether the content is clipped.
191 | internal void UpdateClipContent(bool clipContent)
192 | {
193 | if (clipContent)
194 | {
195 | if (_topLeftContentControl != null)
196 | {
197 | _topLeftContentControl.Clip = _topLeftClip;
198 | }
199 |
200 | if (_topRightContentControl != null)
201 | {
202 | _topRightContentControl.Clip = _topRightClip;
203 | }
204 |
205 | if (_bottomRightContentControl != null)
206 | {
207 | _bottomRightContentControl.Clip = _bottomRightClip;
208 | }
209 |
210 | if (_bottomLeftContentControl != null)
211 | {
212 | _bottomLeftContentControl.Clip = _bottomLeftClip;
213 | }
214 |
215 | UpdateClipSize(new Size(ActualWidth, ActualHeight));
216 | }
217 | else
218 | {
219 | if (_topLeftContentControl != null)
220 | {
221 | _topLeftContentControl.Clip = null;
222 | }
223 |
224 | if (_topRightContentControl != null)
225 | {
226 | _topRightContentControl.Clip = null;
227 | }
228 |
229 | if (_bottomRightContentControl != null)
230 | {
231 | _bottomRightContentControl.Clip = null;
232 | }
233 |
234 | if (_bottomLeftContentControl != null)
235 | {
236 | _bottomLeftContentControl.Clip = null;
237 | }
238 | }
239 | }
240 |
241 | ///
242 | /// Updates the corner radius.
243 | ///
244 | /// The clipping border.
245 | /// Dependency Property Changed Event Args
246 | private static void CornerRadiusChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
247 | {
248 | var clippingBorder = (ClippingBorder)dependencyObject;
249 | clippingBorder.UpdateCornerRadius((CornerRadius)eventArgs.NewValue);
250 | }
251 |
252 | ///
253 | /// Updates the content clipping.
254 | ///
255 | /// The clipping border.
256 | /// Dependency Property Changed Event Args
257 | private static void ClipContentChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
258 | {
259 | var clippingBorder = (ClippingBorder)dependencyObject;
260 | clippingBorder.UpdateClipContent((bool)eventArgs.NewValue);
261 | }
262 |
263 | ///
264 | /// Updates the clips.
265 | ///
266 | /// The clipping border
267 | /// Size Changed Event Args.
268 | private void ClippingBorderSizeChanged(object sender, SizeChangedEventArgs e)
269 | {
270 | if (ClipContent)
271 | {
272 | UpdateClipSize(e.NewSize);
273 | }
274 | }
275 |
276 | ///
277 | /// Updates the clip size.
278 | ///
279 | /// A content control.
280 | /// Size Changed Event Args
281 | private void ContentControlSizeChanged(object sender, SizeChangedEventArgs e)
282 | {
283 | if (ClipContent)
284 | {
285 | UpdateClipSize(new Size(ActualWidth, ActualHeight));
286 | }
287 | }
288 |
289 | ///
290 | /// Updates the clip size.
291 | ///
292 | /// The control size.
293 | private void UpdateClipSize(Size size)
294 | {
295 | if (size.Width > 0 || size.Height > 0)
296 | {
297 | double contentWidth = Math.Max(0, size.Width - BorderThickness.Left - BorderThickness.Right);
298 | double contentHeight = Math.Max(0, size.Height - BorderThickness.Top - BorderThickness.Bottom);
299 |
300 | if (_topLeftClip != null)
301 | {
302 | _topLeftClip.Rect = new Rect(0, 0, contentWidth + (CornerRadius.TopLeft * 2), contentHeight + (CornerRadius.TopLeft * 2));
303 | }
304 |
305 | if (_topRightClip != null)
306 | {
307 | _topRightClip.Rect = new Rect(0 - CornerRadius.TopRight, 0, contentWidth + CornerRadius.TopRight, contentHeight + CornerRadius.TopRight);
308 | }
309 |
310 | if (_bottomRightClip != null)
311 | {
312 | _bottomRightClip.Rect = new Rect(0 - CornerRadius.BottomRight, 0 - CornerRadius.BottomRight, contentWidth + CornerRadius.BottomRight,
313 | contentHeight + CornerRadius.BottomRight);
314 | }
315 |
316 | if (_bottomLeftClip != null)
317 | {
318 | _bottomLeftClip.Rect = new Rect(0, 0 - CornerRadius.BottomLeft, contentWidth + CornerRadius.BottomLeft, contentHeight + CornerRadius.BottomLeft);
319 | }
320 | }
321 | }
322 | }
323 | }
--------------------------------------------------------------------------------
/Common/Borders/InnerGlowBorder.cs:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------
2 | //
3 | // (c) 2008 Microsoft Corporation. All rights reserved.
4 | // This source is subject to the Microsoft Public License.
5 | // See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
6 | //
7 | // 03-Oct-2008
8 | // Martin Grayson
9 | // A border that also shows an inner glow.
10 | //-----------------------------------------------------------------------
11 | using System;
12 | using System.ComponentModel;
13 | using System.Windows;
14 | using System.Windows.Controls;
15 | using System.Windows.Media;
16 |
17 | namespace ToggleSwitch.Borders
18 | {
19 | ///
20 | /// Content control that draws a glow around its inside.
21 | ///
22 | public class InnerGlowBorder : ContentControl
23 | {
24 | ///
25 | /// The inner glow opacity property.
26 | ///
27 | public static readonly DependencyProperty InnerGlowOpacityProperty = DependencyProperty.Register("InnerGlowOpacity", typeof(double),
28 | typeof(InnerGlowBorder), null);
29 |
30 | ///
31 | /// The inner glow size property.
32 | ///
33 | public static readonly DependencyProperty InnerGlowSizeProperty = DependencyProperty.Register("InnerGlowSize", typeof(Thickness),
34 | typeof(InnerGlowBorder),
35 | new PropertyMetadata(InnerGlowSizeChanged));
36 |
37 | ///
38 | /// The corner radius property.
39 | ///
40 | public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register("CornerRadius", typeof(CornerRadius),
41 | typeof(InnerGlowBorder), null);
42 |
43 | ///
44 | /// The inner glow color.
45 | ///
46 | public static readonly DependencyProperty InnerGlowColorProperty = DependencyProperty.Register("InnerGlowColor", typeof(Color),
47 | typeof(InnerGlowBorder),
48 | new PropertyMetadata(
49 | Colors.Black,
50 | InnerGlowColorChanged));
51 |
52 | ///
53 | /// The clip content property.
54 | ///
55 | public static readonly DependencyProperty ClipContentProperty = DependencyProperty.Register("ClipContent", typeof(bool), typeof(InnerGlowBorder), null);
56 |
57 | ///
58 | /// The content z-index property.
59 | ///
60 | public static readonly DependencyProperty ContentZIndexProperty = DependencyProperty.Register("ContentZIndex", typeof(int), typeof(InnerGlowBorder), null);
61 |
62 | ///
63 | /// Stores the bottom glow border.
64 | ///
65 | private Border _bottomGlow;
66 |
67 | ///
68 | /// Stores the bottom glow stop 0;
69 | ///
70 | private GradientStop _bottomGlowStop0;
71 |
72 | ///
73 | /// Stores the bottom glow stop 1.
74 | ///
75 | private GradientStop _bottomGlowStop1;
76 |
77 | ///
78 | /// Stores the left glow border.
79 | ///
80 | private Border _leftGlow;
81 |
82 | ///
83 | /// Stores the left glow stop 0;
84 | ///
85 | private GradientStop _leftGlowStop0;
86 |
87 | ///
88 | /// Stores the left glow stop 1;
89 | ///
90 | private GradientStop _leftGlowStop1;
91 |
92 | ///
93 | /// Stores the right glow border.
94 | ///
95 | private Border _rightGlow;
96 |
97 | ///
98 | /// Stores the right glow stop 0;
99 | ///
100 | private GradientStop _rightGlowStop0;
101 |
102 | ///
103 | /// Stores the right glow stop 1.
104 | ///
105 | private GradientStop _rightGlowStop1;
106 |
107 | ///
108 | /// Stores the top glow border.
109 | ///
110 | private Border _topGlow;
111 |
112 | ///
113 | /// Stores the top glow stop 0;
114 | ///
115 | private GradientStop _topGlowStop0;
116 |
117 | ///
118 | /// Stores the top glow stop 1;
119 | ///
120 | private GradientStop _topGlowStop1;
121 |
122 | ///
123 | /// InnerGlowBorder constructor.
124 | ///
125 | public InnerGlowBorder()
126 | {
127 | DefaultStyleKey = typeof(InnerGlowBorder);
128 | }
129 |
130 | ///
131 | /// Gets or sets a value indicating whether the content is clipped.
132 | ///
133 | [Category("Appearance"), Description("Sets whether the content is clipped or not.")]
134 | public bool ClipContent
135 | {
136 | get
137 | {
138 | return (bool)GetValue(ClipContentProperty);
139 | }
140 | set
141 | {
142 | SetValue(ClipContentProperty, value);
143 | }
144 | }
145 |
146 | ///
147 | /// Gets or sets the content z-index. 0 for behind shadow, 1 for in-front.
148 | ///
149 | [Category("Appearance"), Description("Set 0 for behind the shadow, 1 for in front.")]
150 | public int ContentZIndex
151 | {
152 | get
153 | {
154 | return (int)GetValue(ContentZIndexProperty);
155 | }
156 | set
157 | {
158 | SetValue(ContentZIndexProperty, value);
159 | }
160 | }
161 |
162 | ///
163 | /// Gets or sets the inner glow opacity.
164 | ///
165 | [Category("Appearance"), Description("The inner glow opacity.")]
166 | public double InnerGlowOpacity
167 | {
168 | get
169 | {
170 | return (double)GetValue(InnerGlowOpacityProperty);
171 | }
172 | set
173 | {
174 | SetValue(InnerGlowOpacityProperty, value);
175 | }
176 | }
177 |
178 | ///
179 | /// Gets or sets the inner glow color.
180 | ///
181 | [Category("Appearance"), Description("The inner glow color.")]
182 | public Color InnerGlowColor
183 | {
184 | get
185 | {
186 | return (Color)GetValue(InnerGlowColorProperty);
187 | }
188 |
189 | set
190 | {
191 | SetValue(InnerGlowColorProperty, value);
192 | }
193 | }
194 |
195 | ///
196 | /// Gets or sets the inner glow size.
197 | ///
198 | [Category("Appearance"), Description("The inner glow size.")]
199 | public Thickness InnerGlowSize
200 | {
201 | get
202 | {
203 | return (Thickness)GetValue(InnerGlowSizeProperty);
204 | }
205 |
206 | set
207 | {
208 | SetValue(InnerGlowSizeProperty, value);
209 | UpdateGlowSize(value);
210 | }
211 | }
212 |
213 | ///
214 | /// Gets or sets the border corner radius.
215 | /// This is a thickness, as there is a problem parsing CornerRadius types.
216 | ///
217 | [Category("Appearance"), Description("Sets the corner radius on the border.")]
218 | public CornerRadius CornerRadius
219 | {
220 | get
221 | {
222 | return (CornerRadius)GetValue(CornerRadiusProperty);
223 | }
224 |
225 | set
226 | {
227 | SetValue(CornerRadiusProperty, value);
228 | }
229 | }
230 |
231 | ///
232 | /// Gets the template parts out.
233 | ///
234 | public override void OnApplyTemplate()
235 | {
236 | base.OnApplyTemplate();
237 |
238 | _leftGlow = GetTemplateChild("PART_LeftGlow") as Border;
239 | _topGlow = GetTemplateChild("PART_TopGlow") as Border;
240 | _rightGlow = GetTemplateChild("PART_RightGlow") as Border;
241 | _bottomGlow = GetTemplateChild("PART_BottomGlow") as Border;
242 |
243 | _leftGlowStop0 = GetTemplateChild("PART_LeftGlowStop0") as GradientStop;
244 | _leftGlowStop1 = GetTemplateChild("PART_LeftGlowStop1") as GradientStop;
245 | _topGlowStop0 = GetTemplateChild("PART_TopGlowStop0") as GradientStop;
246 | _topGlowStop1 = GetTemplateChild("PART_TopGlowStop1") as GradientStop;
247 | _rightGlowStop0 = GetTemplateChild("PART_RightGlowStop0") as GradientStop;
248 | _rightGlowStop1 = GetTemplateChild("PART_RightGlowStop1") as GradientStop;
249 | _bottomGlowStop0 = GetTemplateChild("PART_BottomGlowStop0") as GradientStop;
250 | _bottomGlowStop1 = GetTemplateChild("PART_BottomGlowStop1") as GradientStop;
251 |
252 | UpdateGlowColor(InnerGlowColor);
253 | UpdateGlowSize(InnerGlowSize);
254 | }
255 |
256 | ///
257 | /// Updates the inner glow color.
258 | ///
259 | /// The new color.
260 | internal void UpdateGlowColor(Color color)
261 | {
262 | if (_leftGlowStop0 != null)
263 | {
264 | _leftGlowStop0.Color = color;
265 | }
266 |
267 | if (_leftGlowStop1 != null)
268 | {
269 | _leftGlowStop1.Color = Color.FromArgb(0, color.R, color.G, color.B);
270 | }
271 |
272 | if (_topGlowStop0 != null)
273 | {
274 | _topGlowStop0.Color = color;
275 | }
276 |
277 | if (_topGlowStop1 != null)
278 | {
279 | _topGlowStop1.Color = Color.FromArgb(0, color.R, color.G, color.B);
280 | }
281 |
282 | if (_rightGlowStop0 != null)
283 | {
284 | _rightGlowStop0.Color = color;
285 | }
286 |
287 | if (_rightGlowStop1 != null)
288 | {
289 | _rightGlowStop1.Color = Color.FromArgb(0, color.R, color.G, color.B);
290 | }
291 |
292 | if (_bottomGlowStop0 != null)
293 | {
294 | _bottomGlowStop0.Color = color;
295 | }
296 |
297 | if (_bottomGlowStop1 != null)
298 | {
299 | _bottomGlowStop1.Color = Color.FromArgb(0, color.R, color.G, color.B);
300 | }
301 | }
302 |
303 | ///
304 | /// Sets the glow size.
305 | ///
306 | /// The new glow size.
307 | internal void UpdateGlowSize(Thickness newGlowSize)
308 | {
309 | if (_leftGlow != null)
310 | {
311 | _leftGlow.Width = Math.Abs(newGlowSize.Left);
312 | }
313 |
314 | if (_topGlow != null)
315 | {
316 | _topGlow.Height = Math.Abs(newGlowSize.Top);
317 | }
318 |
319 | if (_rightGlow != null)
320 | {
321 | _rightGlow.Width = Math.Abs(newGlowSize.Right);
322 | }
323 |
324 | if (_bottomGlow != null)
325 | {
326 | _bottomGlow.Height = Math.Abs(newGlowSize.Bottom);
327 | }
328 | }
329 |
330 | ///
331 | /// Updates the inner glow color when the DP changes.
332 | ///
333 | /// The inner glow border.
334 | /// The new property event args.
335 | private static void InnerGlowColorChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
336 | {
337 | if (eventArgs.NewValue != null)
338 | {
339 | var innerGlowBorder = (InnerGlowBorder)dependencyObject;
340 | innerGlowBorder.UpdateGlowColor((Color)eventArgs.NewValue);
341 | }
342 | }
343 |
344 | ///
345 | /// Updates the glow size.
346 | ///
347 | /// The inner glow border.
348 | /// Dependency Property Changed Event Args
349 | private static void InnerGlowSizeChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
350 | {
351 | var innerGlowBorder = (InnerGlowBorder)dependencyObject;
352 | innerGlowBorder.UpdateGlowSize((Thickness)eventArgs.NewValue);
353 | }
354 | }
355 | }
--------------------------------------------------------------------------------
/Common/Borders/OuterGlowBorder.cs:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------
2 | //
3 | // (c) 2008 Microsoft Corporation. All rights reserved.
4 | // This source is subject to the Microsoft Public License.
5 | // See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
6 | //
7 | // 15-Sep-2008
8 | // Martin Grayson
9 | // A border that also shows an outer glow.
10 | //-----------------------------------------------------------------------
11 | using System;
12 | using System.ComponentModel;
13 | using System.Windows;
14 | using System.Windows.Controls;
15 | using System.Windows.Media;
16 |
17 | namespace ToggleSwitch.Borders
18 | {
19 | ///
20 | /// Content control that draws and outer glow around itself.
21 | ///
22 | public class OuterGlowBorder : ContentControl
23 | {
24 | ///
25 | /// The outer glow opacity property.
26 | ///
27 | public static readonly DependencyProperty OuterGlowOpacityProperty = DependencyProperty.Register("OuterGlowOpacity", typeof(double),
28 | typeof(OuterGlowBorder), null);
29 |
30 | ///
31 | /// The outer glow size property.
32 | ///
33 | public static readonly DependencyProperty OuterGlowSizeProperty = DependencyProperty.Register("OuterGlowSize", typeof(double),
34 | typeof(OuterGlowBorder), null);
35 |
36 | ///
37 | /// The corner radius property.
38 | ///
39 | public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register("CornerRadius", typeof(CornerRadius),
40 | typeof(OuterGlowBorder), null);
41 |
42 | ///
43 | /// The shadow corner radius property.
44 | ///
45 | public static readonly DependencyProperty ShadowCornerRadiusProperty = DependencyProperty.Register("ShadowCornerRadius", typeof(CornerRadius),
46 | typeof(OuterGlowBorder), null);
47 |
48 | ///
49 | /// The outer glow color.
50 | ///
51 | public static readonly DependencyProperty OuterGlowColorProperty = DependencyProperty.Register("OuterGlowColor", typeof(Color),
52 | typeof(OuterGlowBorder),
53 | new PropertyMetadata(
54 | Colors.Black,
55 | OuterGlowColorChanged));
56 |
57 | ///
58 | /// The clip content property.
59 | ///
60 | public static readonly DependencyProperty ClipContentProperty = DependencyProperty.Register("ClipContent", typeof(bool), typeof(OuterGlowBorder),
61 | null);
62 |
63 | ///
64 | /// Stores the outer glow border.
65 | ///
66 | private Border _outerGlowBorder;
67 |
68 | ///
69 | /// Stores the left gradient stop.
70 | ///
71 | private GradientStop _shadowHorizontal1;
72 |
73 | ///
74 | /// Stores the right gradient stop.
75 | ///
76 | private GradientStop _shadowHorizontal2;
77 |
78 | ///
79 | /// The top out gradient stop.
80 | ///
81 | private GradientStop _shadowOuterStop1;
82 |
83 | ///
84 | /// The bottom outer gradient stop.
85 | ///
86 | private GradientStop _shadowOuterStop2;
87 |
88 | ///
89 | /// Stores the top gradient stop.
90 | ///
91 | private GradientStop _shadowVertical1;
92 |
93 | ///
94 | /// Stores the bottom gradient stop.
95 | ///
96 | private GradientStop _shadowVertical2;
97 |
98 | ///
99 | /// Out glow border constructor.
100 | ///
101 | public OuterGlowBorder()
102 | {
103 | DefaultStyleKey = typeof(OuterGlowBorder);
104 | SizeChanged += OuterGlowContentControlSizeChanged;
105 | }
106 |
107 | ///
108 | /// Gets or sets a value indicating whether the content is clipped.
109 | ///
110 | [Category("Appearance"), Description("Sets whether the content is clipped or not.")]
111 | public bool ClipContent
112 | {
113 | get
114 | {
115 | return (bool)GetValue(ClipContentProperty);
116 | }
117 | set
118 | {
119 | SetValue(ClipContentProperty, value);
120 | }
121 | }
122 |
123 | ///
124 | /// Gets or sets the outer glow opacity.
125 | ///
126 | [Category("Appearance"), Description("The outer glow opacity.")]
127 | public double OuterGlowOpacity
128 | {
129 | get
130 | {
131 | return (double)GetValue(OuterGlowOpacityProperty);
132 | }
133 | set
134 | {
135 | SetValue(OuterGlowOpacityProperty, value);
136 | }
137 | }
138 |
139 | ///
140 | /// Gets or sets the outer glow size.
141 | ///
142 | [Category("Appearance"), Description("The outer glow size.")]
143 | public double OuterGlowSize
144 | {
145 | get
146 | {
147 | return (double)GetValue(OuterGlowSizeProperty);
148 | }
149 |
150 | set
151 | {
152 | SetValue(OuterGlowSizeProperty, value);
153 | UpdateGlowSize(OuterGlowSize);
154 | UpdateStops(new Size(ActualWidth, ActualHeight));
155 | }
156 | }
157 |
158 | ///
159 | /// Gets or sets the outer glow color.
160 | ///
161 | [Category("Appearance"), Description("The outer glow color.")]
162 | public Color OuterGlowColor
163 | {
164 | get
165 | {
166 | return (Color)GetValue(OuterGlowColorProperty);
167 | }
168 |
169 | set
170 | {
171 | SetValue(OuterGlowColorProperty, value);
172 | }
173 | }
174 |
175 | ///
176 | /// Gets or sets the border corner radius.
177 | /// This is a thickness, as there is a problem parsing CornerRadius types.
178 | ///
179 | [Category("Appearance"), Description("Sets the corner radius on the border.")]
180 | public CornerRadius CornerRadius
181 | {
182 | get
183 | {
184 | return (CornerRadius)GetValue(CornerRadiusProperty);
185 | }
186 |
187 | set
188 | {
189 | SetValue(CornerRadiusProperty, value);
190 |
191 | ShadowCornerRadius = new CornerRadius(Math.Abs(value.TopLeft * 1.5), Math.Abs(value.TopRight * 1.5), Math.Abs(value.BottomRight * 1.5),
192 | Math.Abs(value.BottomLeft * 1.5));
193 | }
194 | }
195 |
196 | ///
197 | /// Gets or sets the border corner radius.
198 | /// This is a thickness, as there is a problem parsing CornerRadius types.
199 | ///
200 | [Category("Appearance"), Description("Sets the corner radius on the border.")]
201 | public CornerRadius ShadowCornerRadius
202 | {
203 | get
204 | {
205 | return (CornerRadius)GetValue(ShadowCornerRadiusProperty);
206 | }
207 |
208 | set
209 | {
210 | SetValue(ShadowCornerRadiusProperty, value);
211 | }
212 | }
213 |
214 | ///
215 | /// Gets the parts out of the template.
216 | ///
217 | public override void OnApplyTemplate()
218 | {
219 | base.OnApplyTemplate();
220 | _shadowOuterStop1 = (GradientStop)GetTemplateChild("PART_ShadowOuterStop1");
221 | _shadowOuterStop2 = (GradientStop)GetTemplateChild("PART_ShadowOuterStop2");
222 | _shadowVertical1 = (GradientStop)GetTemplateChild("PART_ShadowVertical1");
223 | _shadowVertical2 = (GradientStop)GetTemplateChild("PART_ShadowVertical2");
224 | _shadowHorizontal1 = (GradientStop)GetTemplateChild("PART_ShadowHorizontal1");
225 | _shadowHorizontal2 = (GradientStop)GetTemplateChild("PART_ShadowHorizontal2");
226 | _outerGlowBorder = (Border)GetTemplateChild("PART_OuterGlowBorder");
227 | UpdateGlowSize(OuterGlowSize);
228 | UpdateGlowColor(OuterGlowColor);
229 | }
230 |
231 | ///
232 | /// Updates the glow size.
233 | ///
234 | /// The new size.
235 | internal void UpdateGlowSize(double size)
236 | {
237 | if (_outerGlowBorder != null)
238 | {
239 | _outerGlowBorder.Margin = new Thickness(-Math.Abs(size));
240 | }
241 | }
242 |
243 | ///
244 | /// Updates the outer glow color.
245 | ///
246 | /// The new color.
247 | internal void UpdateGlowColor(Color color)
248 | {
249 | if (_shadowVertical1 != null)
250 | {
251 | _shadowVertical1.Color = color;
252 | }
253 |
254 | if (_shadowVertical2 != null)
255 | {
256 | _shadowVertical2.Color = color;
257 | }
258 |
259 | if (_shadowOuterStop1 != null)
260 | {
261 | _shadowOuterStop1.Color = Color.FromArgb(0, color.R, color.G, color.B);
262 | }
263 |
264 | if (_shadowOuterStop2 != null)
265 | {
266 | _shadowOuterStop2.Color = Color.FromArgb(0, color.R, color.G, color.B);
267 | }
268 | }
269 |
270 | ///
271 | /// Updates the outer glow color when the DP changes.
272 | ///
273 | /// The outer glow border.
274 | /// The new property event args.
275 | private static void OuterGlowColorChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
276 | {
277 | if (eventArgs.NewValue != null)
278 | {
279 | var outerGlowBorder = (OuterGlowBorder)dependencyObject;
280 | outerGlowBorder.UpdateGlowColor((Color)eventArgs.NewValue);
281 | }
282 | }
283 |
284 | ///
285 | /// Updates the gradient stops on the drop shadow.
286 | ///
287 | /// The outer glow border.
288 | /// Size changed event args.
289 | private void OuterGlowContentControlSizeChanged(object sender, SizeChangedEventArgs e)
290 | {
291 | UpdateStops(e.NewSize);
292 | }
293 |
294 | ///
295 | /// Updates the gradient stops.
296 | ///
297 | /// The size of the control.
298 | private void UpdateStops(Size size)
299 | {
300 | if (size.Width > 0 && size.Height > 0)
301 | {
302 | if (_shadowHorizontal1 != null)
303 | {
304 | _shadowHorizontal1.Offset = Math.Abs(OuterGlowSize) / (size.Width + Math.Abs(OuterGlowSize) + Math.Abs(OuterGlowSize));
305 | }
306 |
307 | if (_shadowHorizontal2 != null)
308 | {
309 | _shadowHorizontal2.Offset = 1 - (Math.Abs(OuterGlowSize) / (size.Width + Math.Abs(OuterGlowSize) + Math.Abs(OuterGlowSize)));
310 | }
311 |
312 | if (_shadowVertical1 != null)
313 | {
314 | _shadowVertical1.Offset = Math.Abs(OuterGlowSize) / (size.Height + Math.Abs(OuterGlowSize) + Math.Abs(OuterGlowSize));
315 | }
316 |
317 | if (_shadowVertical2 != null)
318 | {
319 | _shadowVertical2.Offset = 1 - (Math.Abs(OuterGlowSize) / (size.Height + Math.Abs(OuterGlowSize) + Math.Abs(OuterGlowSize)));
320 | }
321 | }
322 | }
323 | }
324 | }
--------------------------------------------------------------------------------
/Common/DropShadowTextBlock.cs:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------
2 | //
3 | // (c) 2008 Microsoft Corporation. All rights reserved.
4 | // This source is subject to the Microsoft Public License.
5 | // See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
6 | //
7 | // 09-Oct-2008
8 | // Martin Grayson
9 | // A control that displays text, with a drop shadow.
10 | //-----------------------------------------------------------------------
11 | using System;
12 | using System.ComponentModel;
13 | using System.Windows;
14 | using System.Windows.Controls;
15 | using System.Windows.Media;
16 |
17 | namespace Demo.Controls
18 | {
19 | ///
20 | /// A control that displays text, with a drop shadow.
21 | ///
22 | public class DropShadowTextBlock : Control
23 | {
24 | ///
25 | /// The drop shadow color property.
26 | ///
27 | public static readonly DependencyProperty DropShadowColorProperty = DependencyProperty.Register("DropShadowColor", typeof(Color), typeof(DropShadowTextBlock), new PropertyMetadata(DropShadowColorChanged));
28 |
29 | ///
30 | /// The drop shadow opacity property.
31 | ///
32 | public static readonly DependencyProperty DropShadowOpacityProperty = DependencyProperty.Register("DropShadowOpacity", typeof(double), typeof(DropShadowTextBlock), new PropertyMetadata(DropShadowOpacityChanged));
33 |
34 | ///
35 | /// The text property.
36 | ///
37 | public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(DropShadowTextBlock), null);
38 |
39 | ///
40 | /// The text decorations property.
41 | ///
42 | public static readonly DependencyProperty TextDecorationsProperty = DependencyProperty.Register("TextDecorations", typeof(TextDecorationCollection), typeof(DropShadowTextBlock), null);
43 |
44 | ///
45 | /// The text wrapping property.
46 | ///
47 | public static readonly DependencyProperty TextWrappingProperty = DependencyProperty.Register("TextWrapping", typeof(TextWrapping), typeof(DropShadowTextBlock), null);
48 |
49 | ///
50 | /// The drop shadow distance property.
51 | ///
52 | public static readonly DependencyProperty DropShadowDistanceProperty = DependencyProperty.Register("DropShadowDistance", typeof(double), typeof(DropShadowTextBlock), new PropertyMetadata(DropShadowDistanceChanged));
53 |
54 | ///
55 | /// The drop shadow angle property.
56 | ///
57 | public static readonly DependencyProperty DropShadowAngleProperty = DependencyProperty.Register("DropShadowAngle", typeof(double), typeof(DropShadowTextBlock), new PropertyMetadata(DropShadowAngleChanged));
58 |
59 | ///
60 | /// Stores the drop shadow brush.
61 | ///
62 | private SolidColorBrush _dropShadowBrush;
63 |
64 | ///
65 | /// Stores the drop shadow translate transform.
66 | ///
67 | private TranslateTransform _dropShadowTranslate;
68 |
69 | ///
70 | /// DropShadowTextBlock constructor.
71 | ///
72 | public DropShadowTextBlock()
73 | {
74 | DefaultStyleKey = typeof(DropShadowTextBlock);
75 | }
76 |
77 | ///
78 | /// Gets or sets the drop shadow color.
79 | ///
80 | [Category("Appearance"), Description("The drop shadow color.")]
81 | public Color DropShadowColor
82 | {
83 | get
84 | {
85 | return (Color)GetValue(DropShadowColorProperty);
86 | }
87 | set
88 | {
89 | SetValue(DropShadowColorProperty, value);
90 | }
91 | }
92 |
93 | ///
94 | /// Gets or sets the drop shadow opacity.
95 | ///
96 | [Category("Appearance"), Description("The drop shadow opacity.")]
97 | public double DropShadowOpacity
98 | {
99 | get
100 | {
101 | return (double)GetValue(DropShadowOpacityProperty);
102 | }
103 | set
104 | {
105 | SetValue(DropShadowOpacityProperty, value);
106 | }
107 | }
108 |
109 | ///
110 | /// Gets or sets the link text.
111 | ///
112 | [Category("Common Properties"), Description("The text content.")]
113 | public string Text
114 | {
115 | get
116 | {
117 | return (string)GetValue(TextProperty);
118 | }
119 | set
120 | {
121 | SetValue(TextProperty, value);
122 | }
123 | }
124 |
125 | ///
126 | /// Gets or sets the text decorations.
127 | ///
128 | [Category("Common Properties"), Description("The text decorations.")]
129 | public TextDecorationCollection TextDecorations
130 | {
131 | get
132 | {
133 | return (TextDecorationCollection)GetValue(TextDecorationsProperty);
134 | }
135 | set
136 | {
137 | SetValue(TextDecorationsProperty, value);
138 | }
139 | }
140 |
141 | ///
142 | /// Gets or sets the text wrapping.
143 | ///
144 | [Category("Common Properties"), Description("Whether the text wraps.")]
145 | public TextWrapping TextWrapping
146 | {
147 | get
148 | {
149 | return (TextWrapping)GetValue(TextWrappingProperty);
150 | }
151 | set
152 | {
153 | SetValue(TextWrappingProperty, value);
154 | }
155 | }
156 |
157 | ///
158 | /// Gets or sets the drop shadow distance.
159 | ///
160 | [Category("Appearance"), Description("The drop shadow distance.")]
161 | public double DropShadowDistance
162 | {
163 | get
164 | {
165 | return (double)GetValue(DropShadowDistanceProperty);
166 | }
167 | set
168 | {
169 | SetValue(DropShadowDistanceProperty, value);
170 | }
171 | }
172 |
173 | ///
174 | /// Gets or sets the drop shadow angle.
175 | ///
176 | [Category("Appearance"), Description("The drop shadow angle.")]
177 | public double DropShadowAngle
178 | {
179 | get
180 | {
181 | return (double)GetValue(DropShadowAngleProperty);
182 | }
183 | set
184 | {
185 | SetValue(DropShadowAngleProperty, value);
186 | }
187 | }
188 |
189 | ///
190 | /// Gets the UI elements out of the template.
191 | ///
192 | public override void OnApplyTemplate()
193 | {
194 | base.OnApplyTemplate();
195 | _dropShadowTranslate = GetTemplateChild("PART_DropShadowTranslate") as TranslateTransform;
196 | _dropShadowBrush = GetTemplateChild("PART_DropShadowBrush") as SolidColorBrush;
197 | UpdateDropShadowPosition();
198 | UpdateDropShadowBrush();
199 | }
200 |
201 | ///
202 | /// Converts degrees into radians.
203 | ///
204 | /// The degree value.
205 | /// The degrees as radians.
206 | private static double DegreesToRadians(double degrees)
207 | {
208 | return degrees * (Math.PI / 180);
209 | }
210 |
211 | ///
212 | /// Gets a point offset by a distance and angle (in degrees).
213 | ///
214 | /// The angle in degrees.
215 | /// The distance.
216 | /// The offset point.
217 | private static Point GetOffset(double angle, double distance)
218 | {
219 | double x = Math.Cos(DegreesToRadians(angle)) * distance;
220 | double y = Math.Tan(DegreesToRadians(angle)) * x;
221 | return new Point(x, y);
222 | }
223 |
224 | ///
225 | /// Updates the drop shadow.
226 | ///
227 | internal void UpdateDropShadowPosition()
228 | {
229 | if (_dropShadowTranslate != null)
230 | {
231 | Point offset = GetOffset(DropShadowAngle, DropShadowDistance);
232 |
233 | _dropShadowTranslate.X = offset.X;
234 | _dropShadowTranslate.Y = offset.Y;
235 | }
236 | }
237 |
238 | ///
239 | /// Updates the drop shadow brush.
240 | ///
241 | internal void UpdateDropShadowBrush()
242 | {
243 | if (_dropShadowBrush != null)
244 | {
245 | _dropShadowBrush.Color = DropShadowColor;
246 | _dropShadowBrush.Opacity = DropShadowOpacity;
247 | }
248 | }
249 |
250 | ///
251 | /// Updates the drop shadow.
252 | ///
253 | /// The drop shadow text block.
254 | /// Dependency Property Changed Event Args
255 | private static void DropShadowDistanceChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
256 | {
257 | var dropShadowTextBlock = (DropShadowTextBlock)dependencyObject;
258 | dropShadowTextBlock.UpdateDropShadowPosition();
259 | }
260 |
261 | ///
262 | /// Updates the drop shadow.
263 | ///
264 | /// The drop shadow text block.
265 | /// Dependency Property Changed Event Args
266 | private static void DropShadowAngleChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
267 | {
268 | var dropShadowTextBlock = (DropShadowTextBlock)dependencyObject;
269 | dropShadowTextBlock.UpdateDropShadowPosition();
270 | }
271 |
272 | ///
273 | /// Updates the drop shadow.
274 | ///
275 | /// The drop shadow text block.
276 | /// Dependency Property Changed Event Args
277 | private static void DropShadowColorChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
278 | {
279 | var dropShadowTextBlock = (DropShadowTextBlock)dependencyObject;
280 | dropShadowTextBlock.UpdateDropShadowBrush();
281 | }
282 |
283 | ///
284 | /// Updates the drop shadow.
285 | ///
286 | /// The drop shadow text block.
287 | /// Dependency Property Changed Event Args
288 | private static void DropShadowOpacityChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
289 | {
290 | var dropShadowTextBlock = (DropShadowTextBlock)dependencyObject;
291 | dropShadowTextBlock.UpdateDropShadowBrush();
292 | }
293 | }
294 | }
--------------------------------------------------------------------------------
/Common/HorizontalToggleSwitch.cs:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------
2 | //
3 | // (c) 2011 Eric Jensen. All rights reserved.
4 | // This source is subject to the Microsoft Public License.
5 | // See http://www.opensource.org/licenses/MS-PL.
6 | //
7 | // 15-Sept-2011
8 | // Eric Jensen
9 | // Horizontally oriented toggle switch control.
10 | //-----------------------------------------------------------------------
11 | using System;
12 | using System.Windows;
13 | using System.Windows.Controls;
14 | using System.Windows.Controls.Primitives;
15 |
16 | namespace ToggleSwitch
17 | {
18 | ///
19 | /// Horizontally oriented toggle switch control.
20 | ///
21 | public class HorizontalToggleSwitch : ToggleSwitchBase
22 | {
23 | public HorizontalToggleSwitch()
24 | {
25 | DefaultStyleKey = typeof(HorizontalToggleSwitch);
26 | }
27 |
28 | protected override double Offset
29 | {
30 | get { return Canvas.GetLeft(SwitchThumb); }
31 | set
32 | {
33 | SwitchTrack.BeginAnimation(Canvas.LeftProperty, null);
34 | SwitchThumb.BeginAnimation(Canvas.LeftProperty, null);
35 | Canvas.SetLeft(SwitchTrack, value);
36 | Canvas.SetLeft(SwitchThumb, value);
37 | }
38 | }
39 |
40 | protected override PropertyPath SlidePropertyPath
41 | {
42 | get { return new PropertyPath("(Canvas.Left)"); }
43 | }
44 |
45 | protected override void OnDragDelta(object sender, DragDeltaEventArgs e)
46 | {
47 | DragOffset += e.HorizontalChange;
48 | Offset = Math.Max(UncheckedOffset, Math.Min(CheckedOffset, DragOffset));
49 | }
50 |
51 | protected override void LayoutControls()
52 | {
53 | if (SwitchThumb == null || SwitchRoot == null)
54 | {
55 | return;
56 | }
57 |
58 | double fullThumbWidth = SwitchThumb.ActualWidth + SwitchThumb.BorderThickness.Left + SwitchThumb.BorderThickness.Right;
59 |
60 | if (SwitchChecked != null && SwitchUnchecked != null)
61 | {
62 | SwitchChecked.Width = SwitchUnchecked.Width = Math.Max(0, SwitchRoot.ActualWidth - fullThumbWidth / 2);
63 | SwitchChecked.Padding = new Thickness(0, 0, (SwitchThumb.ActualWidth + SwitchThumb.BorderThickness.Left) / 2, 0);
64 | SwitchUnchecked.Padding = new Thickness((SwitchThumb.ActualWidth + SwitchThumb.BorderThickness.Right) / 2, 0, 0, 0);
65 | }
66 |
67 | SwitchThumb.Margin = new Thickness(SwitchRoot.ActualWidth - fullThumbWidth, SwitchThumb.Margin.Top, 0, SwitchThumb.Margin.Bottom);
68 | UncheckedOffset = -SwitchRoot.ActualWidth + fullThumbWidth - SwitchThumb.BorderThickness.Left;
69 | CheckedOffset = SwitchThumb.BorderThickness.Right;
70 |
71 | if (!IsDragging)
72 | {
73 | Offset = IsChecked ? CheckedOffset : UncheckedOffset;
74 | ChangeCheckStates(false);
75 | }
76 | }
77 |
78 | protected override void OnDragCompleted(object sender, DragCompletedEventArgs e)
79 | {
80 | IsDragging = false;
81 | bool click = false;
82 | double fullThumbWidth = SwitchThumb.ActualWidth + SwitchThumb.BorderThickness.Left + SwitchThumb.BorderThickness.Right;
83 |
84 | if ((!IsChecked && DragOffset > (SwitchRoot.ActualWidth - fullThumbWidth) * (Elasticity - 1.0))
85 | || (IsChecked && DragOffset < (SwitchRoot.ActualWidth - fullThumbWidth) * -Elasticity))
86 | {
87 | double edge = IsChecked ? CheckedOffset : UncheckedOffset;
88 | if (Offset != edge)
89 | {
90 | click = true;
91 | }
92 | }
93 | else if (DragOffset == CheckedOffset || DragOffset == UncheckedOffset)
94 | {
95 | click = true;
96 | }
97 | else
98 | {
99 | ChangeCheckStates(true);
100 | }
101 |
102 | if (click)
103 | {
104 | OnClick();
105 | }
106 |
107 | DragOffset = 0;
108 | }
109 | }
110 | }
--------------------------------------------------------------------------------
/Common/Icons/ToggleSwitch.HorizontalToggleSwitch.Expression.Large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ejensen/toggle-switch-control/1761c450de096c7cea7ec1d81f337ed7f9e69624/Common/Icons/ToggleSwitch.HorizontalToggleSwitch.Expression.Large.png
--------------------------------------------------------------------------------
/Common/Icons/ToggleSwitch.HorizontalToggleSwitch.Expression.Small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ejensen/toggle-switch-control/1761c450de096c7cea7ec1d81f337ed7f9e69624/Common/Icons/ToggleSwitch.HorizontalToggleSwitch.Expression.Small.png
--------------------------------------------------------------------------------
/Common/Icons/ToggleSwitch.HorizontalToggleSwitch.VisualStudio.bmp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ejensen/toggle-switch-control/1761c450de096c7cea7ec1d81f337ed7f9e69624/Common/Icons/ToggleSwitch.HorizontalToggleSwitch.VisualStudio.bmp
--------------------------------------------------------------------------------
/Common/ToggleSwitchBase.cs:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------
2 | //
3 | // (c) 2011 Eric Jensen. All rights reserved.
4 | // This source is subject to the Microsoft Public License.
5 | // See http://www.opensource.org/licenses/MS-PL.
6 | //
7 | // 15-Sept-2011
8 | // Eric Jensen
9 | // Base class for the toggle switch control.
10 | //-----------------------------------------------------------------------
11 | using System;
12 | using System.ComponentModel;
13 | using System.Windows;
14 | using System.Windows.Controls;
15 | using System.Windows.Controls.Primitives;
16 | using System.Windows.Input;
17 | using System.Windows.Media;
18 | using System.Windows.Media.Animation;
19 | using ToggleSwitch.Utils;
20 |
21 | namespace ToggleSwitch
22 | {
23 | ///
24 | /// Base class for the toggle switch control.
25 | ///
26 | [TemplateVisualState(Name = NormalState, GroupName = CommonStates)]
27 | [TemplateVisualState(Name = DisabledState, GroupName = CommonStates)]
28 | [TemplateVisualState(Name = MouseOverState, GroupName = CommonStates)]
29 | [TemplateVisualState(Name = FocusedState, GroupName = FocusStates)]
30 | [TemplateVisualState(Name = UnfocusedState, GroupName = FocusStates)]
31 | [TemplateVisualState(Name = CheckedState, GroupName = CheckStates)]
32 | [TemplateVisualState(Name = UncheckedState, GroupName = CheckStates)]
33 | [TemplateVisualState(Name = DraggingState + CheckedState, GroupName = CheckStates)]
34 | [TemplateVisualState(Name = DraggingState + UncheckedState, GroupName = CheckStates)]
35 | [TemplatePart(Name = SwitchCheckedPart, Type = typeof(Control))]
36 | [TemplatePart(Name = SwitchUncheckedPart, Type = typeof(Control))]
37 | [TemplatePart(Name = SwitchThumbPart, Type = typeof(Thumb))]
38 | [TemplatePart(Name = SwitchRootPart, Type = typeof(FrameworkElement))]
39 | [TemplatePart(Name = SwitchTrackPart, Type = typeof(FrameworkElement))]
40 | [Description("A control which when clicked or dragged toggles between on and off states.")]
41 | public abstract class ToggleSwitchBase : Control
42 | {
43 | #region Constants
44 |
45 | private const string CommonStates = "CommonStates";
46 | private const string NormalState = "Normal";
47 | private const string DisabledState = "Disabled";
48 | private const string MouseOverState = "MouseOver";
49 |
50 | private const string CheckStates = "CheckStates";
51 | private const string CheckedState = "Checked";
52 | private const string DraggingState = "Dragging";
53 | private const string UncheckedState = "Unchecked";
54 |
55 | private const string FocusStates = "FocusStates";
56 | private const string FocusedState = "Focused";
57 | private const string UnfocusedState = "Unfocused";
58 |
59 | private const string SwitchRootPart = "SwitchRoot";
60 | private const string SwitchCheckedPart = "SwitchChecked";
61 | private const string SwitchUncheckedPart = "SwitchUnchecked";
62 | private const string SwitchThumbPart = "SwitchThumb";
63 | private const string SwitchTrackPart = "SwitchTrack";
64 |
65 | private const string CommonPropertiesCategory = "Common Properties";
66 | private const string AppearanceCategory = "Appearance";
67 |
68 | #endregion
69 |
70 | #region Fields
71 |
72 | ///
73 | /// True if the mouse has been captured by this control, false otherwise.
74 | ///
75 | private bool _isMouseCaptured;
76 |
77 | ///
78 | /// True if the SPACE key is currently pressed, false otherwise.
79 | ///
80 | private bool _isSpaceKeyDown;
81 |
82 | ///
83 | /// True if the mouse's left button is currently down, false otherwise.
84 | ///
85 | private bool _isMouseLeftButtonDown;
86 |
87 | ///
88 | /// Last known position of the mouse with respect to this Button.
89 | ///
90 | private Point _mousePosition;
91 |
92 | ///
93 | /// True if visual state changes are suspended; false otherwise.
94 | ///
95 | private bool _suspendStateChanges;
96 |
97 | #endregion
98 |
99 | #region Properties
100 |
101 | protected Thumb SwitchThumb { get; set; }
102 | protected Control SwitchChecked { get; set; }
103 | protected Control SwitchUnchecked { get; set; }
104 | protected FrameworkElement SwitchRoot { get; set; }
105 | protected FrameworkElement SwitchTrack { get; set; }
106 |
107 | ///
108 | /// The current offset of the Thumb.
109 | ///
110 | protected abstract double Offset { get; set; }
111 |
112 | ///
113 | /// The current offset of the Thumb when it's in the Checked state.
114 | ///
115 | protected double CheckedOffset { get; set; }
116 |
117 | ///
118 | /// The current offset of the Thumb when it's in the Unchecked state.
119 | ///
120 | protected double UncheckedOffset { get; set; }
121 |
122 | ///
123 | /// The offset of the thumb while it's being dragged.
124 | ///
125 | protected double DragOffset { get; set; }
126 |
127 | ///
128 | /// Gets or sets whether the thumb position is being manipulated.
129 | ///
130 | protected bool IsDragging { get; set; }
131 |
132 | ///
133 | /// Gets a value that indicates whether a ToggleSwitch is currently pressed.
134 | ///
135 | public bool IsPressed { get; protected set; }
136 |
137 | protected abstract PropertyPath SlidePropertyPath { get; }
138 |
139 | #endregion
140 |
141 | #region Dependency Properties
142 |
143 | #region ContentTemplate (DependencyProperty)
144 |
145 | ///
146 | /// DependencyProperty for the ControlTemplate property.
147 | ///
148 | public static readonly DependencyProperty ContentTemplateProperty =
149 | DependencyProperty.Register("ContentTemplate", typeof(ControlTemplate), typeof(ToggleSwitchBase),
150 | new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure, OnLayoutDependancyPropertyChanged));
151 |
152 | ///
153 | /// The template applied to the Checked and Unchecked content properties.
154 | ///
155 | [Description("The template applied to the Checked and Unchecked content properties.")]
156 | public ControlTemplate ContentTemplate
157 | {
158 | get { return (ControlTemplate)GetValue(ContentTemplateProperty); }
159 | set { SetValue(ContentTemplateProperty, value); }
160 | }
161 |
162 | #endregion
163 |
164 | #region CheckedContent (Dependency Property)
165 |
166 | ///
167 | /// DependencyProperty for the CheckedContent property.
168 | ///
169 | public static readonly DependencyProperty CheckedContentProperty =
170 | DependencyProperty.Register("CheckedContent", typeof(object), typeof(ToggleSwitchBase),
171 | new FrameworkPropertyMetadata("ON", FrameworkPropertyMetadataOptions.AffectsArrange, OnLayoutDependancyPropertyChanged));
172 |
173 | ///
174 | /// The content shown on the checked side of the toggle switch
175 | ///
176 | [Category(CommonPropertiesCategory)]
177 | [Description("The content shown on the checked side of the toggle switch")]
178 | public object CheckedContent
179 | {
180 | get { return GetValue(CheckedContentProperty); }
181 | set { SetValue(CheckedContentProperty, value); }
182 | }
183 |
184 | #endregion
185 |
186 | #region CheckedForeground (Dependency Property)
187 |
188 | ///
189 | /// DependencyProperty for the CheckedForeground property.
190 | ///
191 | public static readonly DependencyProperty CheckedForegroundProperty =
192 | DependencyProperty.Register("CheckedForeground", typeof(Brush), typeof(ToggleSwitchBase), null);
193 |
194 | ///
195 | /// The brush used for the foreground of the checked side of the toggle switch.
196 | ///
197 | [Description("The brush used for the foreground of the checked side of the toggle switch.")]
198 | public Brush CheckedForeground
199 | {
200 | get { return (Brush)GetValue(CheckedForegroundProperty); }
201 | set { SetValue(CheckedForegroundProperty, value); }
202 | }
203 |
204 | #endregion
205 |
206 | #region CheckedBackground (Dependency Property)
207 |
208 | ///
209 | /// DependencyProperty for the CheckedBackground property.
210 | ///
211 | public static readonly DependencyProperty CheckedBackgroundProperty =
212 | DependencyProperty.Register("CheckedBackground", typeof(Brush), typeof(ToggleSwitchBase), null);
213 |
214 | ///
215 | /// The brush used for the background of the checked side of the toggle switch.
216 | ///
217 | [Description("The brush used for the background of the checked side of the toggle switch.")]
218 | public Brush CheckedBackground
219 | {
220 | get { return (Brush)GetValue(CheckedBackgroundProperty); }
221 | set { SetValue(CheckedBackgroundProperty, value); }
222 | }
223 |
224 | #endregion
225 |
226 | #region UncheckedContent (Dependency Property)
227 |
228 | ///
229 | /// DependencyProperty for the UncheckedContent property.
230 | ///
231 | public static readonly DependencyProperty UncheckedContentProperty =
232 | DependencyProperty.Register("UncheckedContent", typeof(object), typeof(ToggleSwitchBase),
233 | new FrameworkPropertyMetadata("OFF", FrameworkPropertyMetadataOptions.AffectsArrange, OnLayoutDependancyPropertyChanged));
234 |
235 | ///
236 | /// The content shown on the unchecked side of the toggle switch.
237 | ///
238 | [Category(CommonPropertiesCategory)]
239 | [Description("The content shown on the unchecked side of the toggle switch.")]
240 | public object UncheckedContent
241 | {
242 | get { return GetValue(UncheckedContentProperty); }
243 | set { SetValue(UncheckedContentProperty, value); }
244 | }
245 |
246 | #endregion
247 |
248 | #region UncheckedForeground (Dependency Property)
249 |
250 | ///
251 | /// DependencyProperty for the UncheckedForeground property.
252 | ///
253 | public static readonly DependencyProperty UncheckedForegroundProperty =
254 | DependencyProperty.Register("UncheckedForeground", typeof(Brush), typeof(ToggleSwitchBase), null);
255 |
256 | ///
257 | /// The brush used for the foreground of the Unchecked side of the toggle switch.
258 | ///
259 | [Description("The brush used for the foreground of the Unchecked side of the toggle switch.")]
260 | public Brush UncheckedForeground
261 | {
262 | get { return (Brush)GetValue(UncheckedForegroundProperty); }
263 | set { SetValue(UncheckedForegroundProperty, value); }
264 | }
265 |
266 | #endregion
267 |
268 | #region UncheckedBackground (Dependency Property)
269 |
270 | ///
271 | /// DependencyProperty for the UncheckedBackground property.
272 | ///
273 | public static readonly DependencyProperty UncheckedBackgroundProperty =
274 | DependencyProperty.Register("UncheckedBackground", typeof(Brush), typeof(ToggleSwitchBase), null);
275 |
276 | ///
277 | /// The brush used for the background of the Unchecked side of the toggle switch.
278 | ///
279 | [Description("The brush used for the background of the Unchecked side of the toggle switch.")]
280 | public Brush UncheckedBackground
281 | {
282 | get { return (Brush)GetValue(UncheckedBackgroundProperty); }
283 | set { SetValue(UncheckedBackgroundProperty, value); }
284 | }
285 |
286 | #endregion
287 |
288 | #region Elasticity (Dependency Property)
289 |
290 | ///
291 | /// DependencyProperty for the Elasticity property.
292 | ///
293 | public static readonly DependencyProperty ElasticityProperty =
294 | DependencyProperty.Register("Elasticity", typeof(double), typeof(ToggleSwitchBase), new PropertyMetadata(0.5));
295 |
296 | ///
297 | /// Determines the percentage of the way the thumb must be dragged before the switch changes it's IsChecked state.
298 | ///
299 | ///
300 | /// This value must be within the range of 0.0 - 1.0.
301 | ///
302 | [Category(CommonPropertiesCategory)]
303 | [Description("Determines the percentage of the way the thumb must be dragged before the switch changes it's IsChecked state.")]
304 | public double Elasticity
305 | {
306 | get { return ((double)GetValue(ElasticityProperty)).Clamp(0.0, 1.0); }
307 | set { SetValue(ElasticityProperty, value.Clamp(0, 1.0)); }
308 | }
309 |
310 | #endregion
311 |
312 | #region ThumbTemplate (DependencyProperty)
313 |
314 | ///
315 | /// DependencyProperty for the ThumbTemplate property.
316 | ///
317 | public static readonly DependencyProperty ThumbTemplateProperty =
318 | DependencyProperty.Register("ThumbTemplate", typeof(ControlTemplate), typeof(ToggleSwitchBase),
319 | new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure, OnLayoutDependancyPropertyChanged));
320 |
321 | ///
322 | /// The thumb's control template.
323 | ///
324 | [Description("The thumb's control template.")]
325 | public ControlTemplate ThumbTemplate
326 | {
327 | get { return (ControlTemplate)GetValue(ThumbTemplateProperty); }
328 | set { SetValue(ThumbTemplateProperty, value); }
329 | }
330 |
331 | #endregion
332 |
333 | #region ThumbBrush (Dependency Property)
334 |
335 | ///
336 | /// DependencyProperty for the ThumbBrush property.
337 | ///
338 | public static readonly DependencyProperty ThumbBrushProperty =
339 | DependencyProperty.Register("ThumbBrush", typeof(Brush), typeof(ToggleSwitchBase), null);
340 |
341 | ///
342 | /// The brush used to fill the thumb.
343 | ///
344 | [Description("The brush used to fill the thumb.")]
345 | public Brush ThumbBrush
346 | {
347 | get { return (Brush)GetValue(ThumbBrushProperty); }
348 | set { SetValue(ThumbBrushProperty, value); }
349 | }
350 |
351 | #endregion
352 |
353 | #region ThumbSize (DependencyProperty)
354 |
355 | ///
356 | /// DependencyProperty for the ThumbSize property.
357 | ///
358 | public static readonly DependencyProperty ThumbSizeProperty =
359 | DependencyProperty.Register("ThumbSize", typeof(double), typeof(ToggleSwitchBase),
360 | new FrameworkPropertyMetadata(40.0, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsMeasure, OnLayoutDependancyPropertyChanged));
361 |
362 | ///
363 | /// The size of the toggle switch's thumb.
364 | ///
365 | [Category(AppearanceCategory)]
366 | [Description("The size of the toggle switch's thumb.")]
367 | public double ThumbSize
368 | {
369 | get { return (double)GetValue(ThumbSizeProperty); }
370 | set { SetValue(ThumbSizeProperty, value); }
371 | }
372 |
373 | #endregion
374 |
375 | #region IsChecked (DependencyProperty)
376 |
377 | ///
378 | /// DependencyProperty for the IsChecked property.
379 | ///
380 | public static readonly DependencyProperty IsCheckedProperty =
381 | DependencyProperty.Register("IsChecked", typeof(bool), typeof(ToggleSwitchBase),
382 | new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsCheckedChanged));
383 |
384 | ///
385 | /// Gets or sets whether the control is in the checked state.
386 | ///
387 | [Category(CommonPropertiesCategory)]
388 | [Description("Gets or sets whether the control is in the checked state.")]
389 | public bool IsChecked
390 | {
391 | get { return (bool)GetValue(IsCheckedProperty); }
392 | set { SetValue(IsCheckedProperty, value); }
393 | }
394 |
395 | private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
396 | {
397 | var control = (ToggleSwitchBase)d;
398 |
399 | if (e.NewValue != e.OldValue)
400 | {
401 | if ((bool)e.NewValue)
402 | {
403 | control.InvokeChecked(new RoutedEventArgs());
404 | }
405 | else
406 | {
407 | control.InvokeUnchecked(new RoutedEventArgs());
408 | }
409 | }
410 |
411 | control.ChangeCheckStates(true);
412 | }
413 |
414 | #endregion
415 |
416 | #endregion
417 |
418 | #region Events
419 |
420 | ///
421 | /// Event raised when the toggle switch is unchecked.
422 | ///
423 | public event RoutedEventHandler Unchecked;
424 |
425 | protected void InvokeUnchecked(RoutedEventArgs e)
426 | {
427 | Unchecked?.Invoke(this, e);
428 | }
429 |
430 | ///
431 | /// Event raised when the toggle switch is checked.
432 | ///
433 | public event RoutedEventHandler Checked;
434 |
435 | protected void InvokeChecked(RoutedEventArgs e)
436 | {
437 | Checked?.Invoke(this, e);
438 | }
439 |
440 | #endregion
441 |
442 | ///
443 | /// Initializes a new instance of the ToggleSwitchBase class.
444 | ///
445 | protected ToggleSwitchBase()
446 | {
447 | Loaded += delegate { UpdateVisualState(false); };
448 | IsEnabledChanged += OnIsEnabledChanged;
449 | }
450 |
451 | ///
452 | /// Raised while dragging the Thumb.
453 | ///
454 | ///
455 | ///
456 | protected abstract void OnDragDelta(object sender, DragDeltaEventArgs e);
457 |
458 | ///
459 | /// Raised when the dragging of the Thumb has completed.
460 | ///
461 | ///
462 | ///
463 | protected abstract void OnDragCompleted(object sender, DragCompletedEventArgs e);
464 |
465 | ///
466 | /// Recalculated the layout of the control.
467 | ///
468 | protected abstract void LayoutControls();
469 |
470 | public override void OnApplyTemplate()
471 | {
472 | base.OnApplyTemplate();
473 |
474 | RemoveEventHandlers();
475 | GetTemplateChildren();
476 | AddEventHandlers();
477 |
478 | LayoutControls();
479 |
480 | VisualStateManager.GoToState(this, IsEnabled ? NormalState : DisabledState, false);
481 | ChangeCheckStates(false);
482 | }
483 |
484 | ///
485 | /// Initializes the control's template parts.
486 | ///
487 | protected virtual void GetTemplateChildren()
488 | {
489 | SwitchRoot = GetTemplateChild(SwitchRootPart) as FrameworkElement;
490 | SwitchThumb = GetTemplateChild(SwitchThumbPart) as Thumb;
491 | SwitchChecked = GetTemplateChild(SwitchCheckedPart) as Control;
492 | SwitchUnchecked = GetTemplateChild(SwitchUncheckedPart) as Control;
493 | SwitchTrack = GetTemplateChild(SwitchTrackPart) as FrameworkElement;
494 | }
495 |
496 | ///
497 | /// Subscribe event listeners.
498 | ///
499 | protected virtual void AddEventHandlers()
500 | {
501 | if (SwitchThumb != null)
502 | {
503 | SwitchThumb.DragStarted += OnDragStarted;
504 | SwitchThumb.DragDelta += OnDragDelta;
505 | SwitchThumb.DragCompleted += OnDragCompleted;
506 | }
507 | SizeChanged += OnSizeChanged;
508 | }
509 |
510 | ///
511 | /// Unsubscribe event listeners.
512 | ///
513 | protected virtual void RemoveEventHandlers()
514 | {
515 | if (SwitchThumb != null)
516 | {
517 | SwitchThumb.DragStarted -= OnDragStarted;
518 | SwitchThumb.DragDelta -= OnDragDelta;
519 | SwitchThumb.DragCompleted -= OnDragCompleted;
520 | }
521 | SizeChanged -= OnSizeChanged;
522 | }
523 |
524 | ///
525 | /// Raised when a drag has started on the Thumb.
526 | ///
527 | ///
528 | ///
529 | protected virtual void OnDragStarted(object sender, DragStartedEventArgs e)
530 | {
531 | IsDragging = true;
532 | DragOffset = Offset;
533 | ChangeCheckStates(false);
534 | }
535 |
536 | ///
537 | /// Called when the control is clicked.
538 | ///
539 | protected void OnClick()
540 | {
541 | SetCurrentValue(IsCheckedProperty, !IsChecked);
542 | }
543 |
544 | ///
545 | /// Raised when the size of the control has changed.
546 | ///
547 | ///
548 | ///
549 | protected virtual void OnSizeChanged(object sender, SizeChangedEventArgs e)
550 | {
551 | LayoutControls();
552 | }
553 |
554 | ///
555 | /// Capture the mouse.
556 | ///
557 | internal void CaptureMouseInternal()
558 | {
559 | if (!_isMouseCaptured)
560 | {
561 | _isMouseCaptured = CaptureMouse();
562 | }
563 | }
564 |
565 | ///
566 | /// Release mouse capture if we already had it.
567 | ///
568 | protected internal void ReleaseMouseCaptureInternal()
569 | {
570 | ReleaseMouseCapture();
571 | _isMouseCaptured = false;
572 | }
573 |
574 | ///
575 | /// Raised when a dependency property that affects the control's layout has changed.
576 | ///
577 | /// The ToggleSwitch control
578 | ///
579 | private static void OnLayoutDependancyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
580 | {
581 | if (e.NewValue != e.OldValue)
582 | {
583 | ((ToggleSwitchBase)d).LayoutControls();
584 | }
585 | }
586 |
587 | ///
588 | /// Called when the IsEnabled property changes.
589 | ///
590 | ///
591 | ///
592 | private void OnIsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
593 | {
594 | _suspendStateChanges = true;
595 | if (!IsEnabled)
596 | {
597 | IsPressed = false;
598 | _isMouseCaptured = false;
599 | _isSpaceKeyDown = false;
600 | _isMouseLeftButtonDown = false;
601 | }
602 |
603 | _suspendStateChanges = false;
604 | UpdateVisualState();
605 | }
606 |
607 | ///
608 | /// Responds to the LostFocus event.
609 | ///
610 | /// The event data for the LostFocus event.
611 | protected override void OnLostFocus(RoutedEventArgs e)
612 | {
613 | base.OnLostFocus(e);
614 | IsPressed = false;
615 | ReleaseMouseCaptureInternal();
616 | _isSpaceKeyDown = false;
617 |
618 | _suspendStateChanges = false;
619 | UpdateVisualState();
620 | }
621 |
622 | ///
623 | /// Responds to the KeyDown event.
624 | ///
625 | /// The event data for the KeyDown event.
626 | protected override void OnKeyDown(KeyEventArgs e)
627 | {
628 | base.OnKeyDown(e);
629 | if (e.Handled)
630 | {
631 | return;
632 | }
633 |
634 | if (OnKeyDownInternal(e.Key))
635 | {
636 | e.Handled = true;
637 | }
638 | }
639 |
640 | ///
641 | /// Handles the KeyDown event for ButtonBase.
642 | ///
643 | ///
644 | /// The keyboard key associated with the event.
645 | ///
646 | /// True if the event was handled, false otherwise.
647 | ///
648 | /// This method exists for the purpose of unit testing since we can't
649 | /// set KeyEventArgs.Key to simulate key press events.
650 | ///
651 | private bool OnKeyDownInternal(Key key)
652 | {
653 | bool handled = false;
654 |
655 | if (IsEnabled)
656 | {
657 | if (key == Key.Space)
658 | {
659 | if (!_isMouseCaptured && !_isSpaceKeyDown)
660 | {
661 | _isSpaceKeyDown = true;
662 | IsPressed = true;
663 | CaptureMouseInternal();
664 |
665 | handled = true;
666 | }
667 | }
668 | else if (key == Key.Enter)
669 | {
670 | _isSpaceKeyDown = false;
671 | IsPressed = false;
672 | ReleaseMouseCaptureInternal();
673 |
674 | OnClick();
675 |
676 | handled = true;
677 | }
678 | else if (_isSpaceKeyDown)
679 | {
680 | IsPressed = false;
681 | _isSpaceKeyDown = false;
682 | ReleaseMouseCaptureInternal();
683 | }
684 | }
685 |
686 | return handled;
687 | }
688 |
689 | ///
690 | /// Responds to the KeyUp event.
691 | ///
692 | /// The event data for the KeyUp event.
693 | protected override void OnKeyUp(KeyEventArgs e)
694 | {
695 | base.OnKeyUp(e);
696 | if (e.Handled)
697 | {
698 | return;
699 | }
700 |
701 | if (OnKeyUpInternal(e.Key))
702 | {
703 | e.Handled = true;
704 | }
705 | }
706 |
707 | ///
708 | /// Handles the KeyUp event for ButtonBase.
709 | ///
710 | /// The keyboard key associated with the event.
711 | /// True if the event was handled, false otherwise.
712 | ///
713 | /// This method exists for the purpose of unit testing since we can't
714 | /// set KeyEventArgs.Key to simulate key press events.
715 | ///
716 | private bool OnKeyUpInternal(Key key)
717 | {
718 | bool handled = false;
719 |
720 | if (IsEnabled && (key == Key.Space))
721 | {
722 | _isSpaceKeyDown = false;
723 |
724 | if (!_isMouseLeftButtonDown)
725 | {
726 | ReleaseMouseCaptureInternal();
727 | if (IsPressed)
728 | {
729 | OnClick();
730 | }
731 |
732 | IsPressed = false;
733 | }
734 | else if (_isMouseCaptured)
735 | {
736 | bool isValid = IsValidMousePosition();
737 | IsPressed = isValid;
738 | if (!isValid)
739 | {
740 | ReleaseMouseCaptureInternal();
741 | }
742 | }
743 |
744 | handled = true;
745 | }
746 |
747 | return handled;
748 | }
749 |
750 | ///
751 | /// Responds to the MouseLeftButtonDown event.
752 | ///
753 | ///
754 | /// The event data for the MouseLeftButtonDown event.
755 | ///
756 | protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
757 | {
758 | base.OnMouseLeftButtonDown(e);
759 | if (e.Handled)
760 | {
761 | return;
762 | }
763 |
764 | _isMouseLeftButtonDown = true;
765 |
766 | if (!IsEnabled)
767 | {
768 | return;
769 | }
770 |
771 | e.Handled = true;
772 | _suspendStateChanges = true;
773 | Focus();
774 |
775 | CaptureMouseInternal();
776 | if (_isMouseCaptured)
777 | {
778 | IsPressed = true;
779 | }
780 |
781 | _suspendStateChanges = false;
782 | UpdateVisualState();
783 | }
784 |
785 | ///
786 | /// Responds to the MouseLeftButtonUp event.
787 | ///
788 | ///
789 | /// The event data for the MouseLeftButtonUp event.
790 | ///
791 | protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
792 | {
793 | base.OnMouseLeftButtonUp(e);
794 | if (e.Handled)
795 | {
796 | return;
797 | }
798 |
799 | _isMouseLeftButtonDown = false;
800 |
801 | if (!IsEnabled)
802 | {
803 | return;
804 | }
805 |
806 | e.Handled = true;
807 | if (!_isSpaceKeyDown && IsPressed)
808 | {
809 | OnClick();
810 | }
811 |
812 | if (!_isSpaceKeyDown)
813 | {
814 | ReleaseMouseCaptureInternal();
815 | IsPressed = false;
816 | }
817 | }
818 |
819 | ///
820 | /// Responds to the MouseMove event.
821 | ///
822 | /// The event data for the MouseMove event.
823 | protected override void OnMouseMove(MouseEventArgs e)
824 | {
825 | base.OnMouseMove(e);
826 | _mousePosition = e.GetPosition(this);
827 |
828 | if (_isMouseLeftButtonDown &&
829 | IsEnabled &&
830 | _isMouseCaptured &&
831 | !_isSpaceKeyDown)
832 | {
833 | IsPressed = IsValidMousePosition();
834 | }
835 | }
836 |
837 | ///
838 | /// Determine if the mouse is above the button based on its last known
839 | /// position.
840 | ///
841 | ///
842 | /// True if the mouse is considered above the button, false otherwise.
843 | ///
844 | private bool IsValidMousePosition()
845 | {
846 | return (_mousePosition.X >= 0.0) &&
847 | (_mousePosition.X <= ActualWidth) &&
848 | (_mousePosition.Y >= 0.0) &&
849 | (_mousePosition.Y <= ActualHeight);
850 | }
851 |
852 | protected bool GoToState(bool useTransitions, string stateName)
853 | {
854 | return VisualStateManager.GoToState(this, stateName, useTransitions);
855 | }
856 |
857 | protected virtual void ChangeVisualState(bool useTransitions)
858 | {
859 | if (!IsEnabled)
860 | {
861 | GoToState(useTransitions, DisabledState);
862 | }
863 | else
864 | {
865 | GoToState(useTransitions, IsMouseOver ? MouseOverState : NormalState);
866 | }
867 |
868 | if (IsFocused && IsEnabled)
869 | {
870 | GoToState(useTransitions, FocusedState);
871 | }
872 | else
873 | {
874 | GoToState(useTransitions, UnfocusedState);
875 | }
876 | }
877 |
878 | protected void UpdateVisualState(bool useTransitions = true)
879 | {
880 | if (!_suspendStateChanges)
881 | {
882 | ChangeVisualState(useTransitions);
883 | }
884 | }
885 |
886 | ///
887 | /// Updates the control's layout to reflect the current IsChecked state.
888 | ///
889 | /// Whether to use transitions during the layout change.
890 | protected virtual void ChangeCheckStates(bool useTransitions)
891 | {
892 | var state = IsChecked ? CheckedState : UncheckedState;
893 |
894 | if (IsDragging)
895 | {
896 | VisualStateManager.GoToState(this, DraggingState + state, useTransitions);
897 | }
898 | else
899 | {
900 | VisualStateManager.GoToState(this, state, useTransitions);
901 | if (SwitchThumb != null)
902 | {
903 | VisualStateManager.GoToState(SwitchThumb, state, useTransitions);
904 | }
905 | }
906 |
907 | if (SwitchThumb == null || SwitchTrack == null)
908 | {
909 | return;
910 | }
911 |
912 | var storyboard = new Storyboard();
913 | var duration = new Duration(useTransitions ? TimeSpan.FromMilliseconds(100) : TimeSpan.Zero);
914 | var backgroundAnimation = new DoubleAnimation();
915 | var thumbAnimation = new DoubleAnimation();
916 |
917 | backgroundAnimation.Duration = duration;
918 | thumbAnimation.Duration = duration;
919 |
920 | double offset = IsChecked ? CheckedOffset : UncheckedOffset;
921 | backgroundAnimation.To = offset;
922 | thumbAnimation.To = offset;
923 |
924 | storyboard.Children.Add(backgroundAnimation);
925 | storyboard.Children.Add(thumbAnimation);
926 |
927 | Storyboard.SetTarget(backgroundAnimation, SwitchTrack);
928 | Storyboard.SetTarget(thumbAnimation, SwitchThumb);
929 |
930 | Storyboard.SetTargetProperty(backgroundAnimation, SlidePropertyPath);
931 | Storyboard.SetTargetProperty(thumbAnimation, SlidePropertyPath);
932 |
933 | storyboard.Begin();
934 | }
935 | }
936 | }
937 |
--------------------------------------------------------------------------------
/Common/Utils/ActualSizePropertyProxy.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel;
2 | using System.Windows;
3 |
4 | namespace ToggleSwitch.Utils
5 | {
6 | public class ActualSizePropertyProxy : FrameworkElement, INotifyPropertyChanged
7 | {
8 | public event PropertyChangedEventHandler PropertyChanged;
9 |
10 | #region ElementProperty (Dependancy Property)
11 |
12 | public static readonly DependencyProperty ElementProperty =
13 | DependencyProperty.Register("Element", typeof(FrameworkElement), typeof(ActualSizePropertyProxy),
14 | new PropertyMetadata(null, OnElementPropertyChanged));
15 |
16 | private static void OnElementPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
17 | {
18 | if (d != null)
19 | {
20 | ((ActualSizePropertyProxy)d).OnElementChanged(e);
21 | }
22 | }
23 |
24 | public FrameworkElement Element
25 | {
26 | get { return (FrameworkElement)GetValue(ElementProperty); }
27 | set { SetValue(ElementProperty, value); }
28 | }
29 |
30 | #endregion
31 |
32 | public double ActualHeightValue
33 | {
34 | get { return Element == null ? 0 : Element.ActualHeight; }
35 | }
36 |
37 | public double ActualWidthValue
38 | {
39 | get { return Element == null ? 0 : Element.ActualWidth; }
40 | }
41 |
42 | private void OnElementChanged(DependencyPropertyChangedEventArgs e)
43 | {
44 | var oldElement = (FrameworkElement)e.OldValue;
45 | var newElement = (FrameworkElement)e.NewValue;
46 |
47 | if (oldElement != null)
48 | {
49 | oldElement.SizeChanged -= ElementSizeChanged;
50 | }
51 |
52 | if (newElement != null)
53 | {
54 | newElement.SizeChanged += ElementSizeChanged;
55 | }
56 |
57 | NotifyPropertyChanged();
58 | }
59 |
60 | private void ElementSizeChanged(object sender, SizeChangedEventArgs e)
61 | {
62 | NotifyPropertyChanged();
63 | }
64 |
65 | private void NotifyPropertyChanged()
66 | {
67 | if (PropertyChanged != null)
68 | {
69 | PropertyChanged(this, new PropertyChangedEventArgs(nameof(ActualWidthValue)));
70 | PropertyChanged(this, new PropertyChangedEventArgs(nameof(ActualHeightValue)));
71 | }
72 | }
73 | }
74 | }
--------------------------------------------------------------------------------
/Common/Utils/CornerRadiusValueConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Windows;
4 | using System.Windows.Data;
5 |
6 | namespace Demo.Utils
7 | {
8 | public class CornerRadiusValueConverter : IValueConverter
9 | {
10 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
11 | {
12 | var radius = Double.Parse(value.ToString(), culture);
13 | if (parameter != null)
14 | {
15 | radius *= Double.Parse(parameter.ToString(), culture);
16 | }
17 | return new CornerRadius(radius);
18 | }
19 |
20 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
21 | {
22 | throw new NotImplementedException();
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Common/Utils/HelperExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace ToggleSwitch.Utils
4 | {
5 | internal static class HelperExtensions
6 | {
7 | public static T Clamp(this T val, T min, T max) where T : IComparable
8 | {
9 | return val.CompareTo(min) < 0 ? min : (val.CompareTo(max) > 0 ? max : val);
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/Common/Utils/ScalarValueConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Windows.Data;
4 |
5 | namespace Demo.Utils
6 | {
7 | public class ScalarValueConverter : IValueConverter
8 | {
9 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
10 | {
11 | var oldValue = Double.Parse(value.ToString(), culture);
12 | if (parameter != null)
13 | {
14 | oldValue *= Double.Parse(parameter.ToString(), culture);
15 | }
16 | return oldValue;
17 | }
18 |
19 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
20 | {
21 | var oldValue = Double.Parse(value.ToString(), culture);
22 | if (parameter != null)
23 | {
24 | oldValue /= Double.Parse(parameter.ToString(), culture);
25 | }
26 | return oldValue;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Common/VerticalToggleSwitch.cs:
--------------------------------------------------------------------------------
1 | //-----------------------------------------------------------------------
2 | //
3 | // (c) 2011 Eric Jensen. All rights reserved.
4 | // This source is subject to the Microsoft Public License.
5 | // See http://www.opensource.org/licenses/MS-PL.
6 | //
7 | // 15-Sept-2011
8 | // Eric Jensen
9 | // Vertically oriented toggle switch control.
10 | //-----------------------------------------------------------------------
11 | using System;
12 | using System.Windows;
13 | using System.Windows.Controls;
14 | using System.Windows.Controls.Primitives;
15 | using ToggleSwitch;
16 |
17 | namespace Demo.Controls
18 | {
19 | ///
20 | /// Vertically oriented toggle switch control.
21 | ///
22 | public class VerticalToggleSwitch : ToggleSwitchBase
23 | {
24 | public VerticalToggleSwitch()
25 | {
26 | DefaultStyleKey = typeof(VerticalToggleSwitch);
27 | }
28 |
29 | protected override double Offset
30 | {
31 | get { return Canvas.GetTop(SwitchThumb); }
32 | set
33 | {
34 | SwitchTrack.BeginAnimation(Canvas.TopProperty, null);
35 | SwitchThumb.BeginAnimation(Canvas.TopProperty, null);
36 | Canvas.SetTop(SwitchThumb, value);
37 | Canvas.SetTop(SwitchTrack, value);
38 | }
39 | }
40 |
41 | protected override PropertyPath SlidePropertyPath
42 | {
43 | get { return new PropertyPath("(Canvas.Top)"); }
44 | }
45 |
46 | protected override void OnDragDelta(object sender, DragDeltaEventArgs e)
47 | {
48 | DragOffset += e.VerticalChange;
49 | Offset = Math.Min(UncheckedOffset, Math.Max(CheckedOffset, DragOffset));
50 | }
51 |
52 | protected override void LayoutControls()
53 | {
54 | if (SwitchThumb == null || SwitchRoot == null)
55 | {
56 | return;
57 | }
58 |
59 | double fullThumbHeight = SwitchThumb.ActualHeight + SwitchThumb.BorderThickness.Top + SwitchThumb.BorderThickness.Bottom;
60 |
61 | if (SwitchChecked != null && SwitchUnchecked != null)
62 | {
63 | SwitchChecked.Height = SwitchUnchecked.Height = Math.Max(0, SwitchRoot.ActualHeight - fullThumbHeight / 2);
64 | SwitchChecked.Padding = new Thickness(0, 0, 0, (SwitchThumb.ActualHeight + +SwitchThumb.BorderThickness.Bottom) / 2);
65 | SwitchUnchecked.Padding = new Thickness(0, (SwitchThumb.ActualHeight + +SwitchThumb.BorderThickness.Top) / 2, 0, 0);
66 | }
67 |
68 | UncheckedOffset = SwitchRoot.ActualHeight - SwitchThumb.ActualHeight - SwitchThumb.Margin.Top - SwitchThumb.Margin.Bottom;
69 | CheckedOffset = 0;
70 |
71 | if (!IsDragging)
72 | {
73 | Offset = IsChecked ? CheckedOffset : UncheckedOffset;
74 | ChangeCheckStates(false);
75 | }
76 | }
77 |
78 | protected override void OnDragCompleted(object sender, DragCompletedEventArgs e)
79 | {
80 | IsDragging = false;
81 | bool click = false;
82 |
83 | if ((!IsChecked && DragOffset < ((SwitchRoot.ActualHeight - SwitchThumb.ActualHeight) * (1.0 - Elasticity)))
84 | || (IsChecked && DragOffset > ((SwitchRoot.ActualHeight - SwitchThumb.ActualHeight) * Elasticity)))
85 | {
86 | double edge = IsChecked ? CheckedOffset : UncheckedOffset;
87 | if (Offset != edge)
88 | {
89 | click = true;
90 | }
91 | }
92 | else if (DragOffset == CheckedOffset || DragOffset == UncheckedOffset)
93 | {
94 | click = true;
95 | }
96 | else
97 | {
98 | ChangeCheckStates(true);
99 | }
100 |
101 | if (click)
102 | {
103 | OnClick();
104 | }
105 |
106 | DragOffset = 0;
107 | }
108 | }
109 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Toggle Switch Control Library
2 | =====================
3 | The Toggle Switch Control Library creates highly customizable toggle switch controls for WPF ~~and Silverlight~~ apps.
4 |
5 | 
6 |
7 | Available as a [NuGet package](https://www.nuget.org/packages/ToggleSwitch).
--------------------------------------------------------------------------------
/WPF/Demo/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/WPF/Demo/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace Demo
4 | {
5 | public partial class App : Application
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/WPF/Demo/Assets/Brushes.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/WPF/Demo/Assets/Fonts.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 | Segoe UI, Lucida Sans Unicode, Verdana
7 | Segoe UI, Lucida Sans Unicode, Verdana
8 | 32
9 |
10 |
--------------------------------------------------------------------------------
/WPF/Demo/Assets/Styles.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
97 |
98 |
99 |
117 |
118 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 | M -5,-10.5 L 5,-10.5 L 5,10.5 L -5,10.5 Z
164 | M 4.5,-8.5 L -4.5,-8.5 L -4.5,4.5 L -0.5,8.5 L 0.5,8.5 L 4.5,4.5 Z
165 | M 4.5,-7.5 A 1 1 0 0 0 3.5,-8.5 L -3.5,-8.5 A 1 1 0 0 0 -4.5,-7.5 L -4.5,4.5 L -0.5,8.5 L 0.5,8.5 L 4.5,4.5 Z
166 |
167 |
168 |
169 |
170 |
171 | M 3.5,-7.5 L -3.5,-7.5 L -3.5,4.5 L 0,8 L 3.5,4.5 Z
172 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
278 |
279 |
291 | M -5,-9.5 A 1 1 0 0 1 -4,-10.5 L 4,-10.5 A 1 1 0 0 1 5,-9.5 L 5,9.5 A 1 1 0 0 1 4,10.5 L -4,10.5 A 1 1 0 0 1 -5,9.5 Z
292 | M -4,-9.5 L 4,-9.5 L 4,9.5 L -4,9.5 Z
293 |
316 |
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
379 |
380 |
381 |
382 |
383 |
384 |
385 |
386 |
387 |
388 |
389 |
390 |
391 |
392 |
393 |
394 |
442 |
443 |
444 |
445 |
446 |
494 |
606 |
--------------------------------------------------------------------------------
/WPF/Demo/Demo.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | WinExe
5 | netcoreapp3.1
6 | true
7 |
8 |
9 | Toggle Switch Demo
10 | Toggle Switch Demo
11 | Copyright © Eric Jensen 2020
12 | 1.2.0.0
13 | 1.2.0.0
14 | https://github.com/ejensen/toggle-switch-control
15 | https://github.com/ejensen/toggle-switch-control
16 | Eric Jensen
17 | Yeti Labs
18 | Demo.App
19 | 1.2.0
20 | MIT
21 | git
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | Controls\DropShadowTextBlock.cs
30 |
31 |
32 | Utils\CornerRadiusValueConverter.cs
33 |
34 |
35 | Utils\ScalarValueConverter.cs
36 |
37 |
38 | Controls\VerticalToggleSwitch.cs
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/WPF/Demo/DemoViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.ComponentModel;
3 | using System.Windows.Threading;
4 |
5 | namespace Demo
6 | {
7 | public class DemoViewModel : INotifyPropertyChanged
8 | {
9 | private readonly DispatcherTimer _restartEventTimer = new DispatcherTimer();
10 |
11 | public DemoViewModel()
12 | {
13 | _restartEventTimer.Interval = TimeSpan.FromSeconds(1.5);
14 | _restartEventTimer.Tick += delegate { _restartEventTimer.Stop(); RestartToggleChecked = false; };
15 | }
16 |
17 | private bool _restartToggleChecked;
18 | public bool RestartToggleChecked
19 | {
20 | get
21 | {
22 | return _restartToggleChecked;
23 | }
24 | set
25 | {
26 | if (_restartToggleChecked != value)
27 | {
28 | _restartToggleChecked = value;
29 | InvokePropertyChanged("RestartToggleChecked");
30 |
31 | if (_restartToggleChecked)
32 | {
33 | _restartEventTimer.Start();
34 | }
35 | }
36 | }
37 | }
38 |
39 | public event PropertyChangedEventHandler PropertyChanged;
40 | public void InvokePropertyChanged(string propertyName)
41 | {
42 | PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/WPF/Demo/Images/Knob.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ejensen/toggle-switch-control/1761c450de096c7cea7ec1d81f337ed7f9e69624/WPF/Demo/Images/Knob.png
--------------------------------------------------------------------------------
/WPF/Demo/Images/lightOff.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ejensen/toggle-switch-control/1761c450de096c7cea7ec1d81f337ed7f9e69624/WPF/Demo/Images/lightOff.png
--------------------------------------------------------------------------------
/WPF/Demo/Images/lightOn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ejensen/toggle-switch-control/1761c450de096c7cea7ec1d81f337ed7f9e69624/WPF/Demo/Images/lightOn.png
--------------------------------------------------------------------------------
/WPF/Demo/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/WPF/Demo/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows;
2 |
3 | namespace Demo
4 | {
5 | public partial class MainWindow : Window
6 | {
7 | public MainWindow()
8 | {
9 | InitializeComponent();
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/WPF/Demo/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.InteropServices;
4 | using System.Windows;
5 |
6 | // General Information about an assembly is controlled through the following
7 | // set of attributes. Change these attribute values to modify the information
8 | // associated with an assembly.
9 | [assembly: AssemblyTrademark("")]
10 | [assembly: AssemblyCulture("")]
11 |
12 | // Setting ComVisible to false makes the types in this assembly not visible
13 | // to COM components. If you need to access a type in this assembly from
14 | // COM, set the ComVisible attribute to true on that type.
15 | [assembly: ComVisible(false)]
16 |
17 | //In order to begin building localizable applications, set
18 | //CultureYouAreCodingWith in your .csproj file
19 | //inside a . For example, if you are using US english
20 | //in your source files, set the to en-US. Then uncomment
21 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
22 | //the line below to match the UICulture setting in the project file.
23 |
24 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
25 |
26 |
27 | [assembly: ThemeInfo(
28 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
29 | //(used if a resource is not found in the page,
30 | // or application resource dictionaries)
31 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
32 | //(used if a resource is not found in the page,
33 | // app, or any theme specific resource dictionaries)
34 | )]
35 |
36 |
37 | // Version information for an assembly consists of the following four values:
38 | //
39 | // Major Version
40 | // Minor Version
41 | // Build Number
42 | // Revision
43 | //
44 | // You can specify all the values or you can default the Build and Revision Numbers
45 | // by using the '*' as shown below:
46 | // [assembly: AssemblyVersion("1.0.*")]
47 | [assembly: NeutralResourcesLanguageAttribute("en")]
48 |
--------------------------------------------------------------------------------
/WPF/Demo/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.225
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Demo.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | internal class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | internal static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Demo.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | internal static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/WPF/Demo/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
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 | text/microsoft-resx
107 |
108 |
109 | 2.0
110 |
111 |
112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
113 |
114 |
115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
--------------------------------------------------------------------------------
/WPF/Demo/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.225
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Demo.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/WPF/Demo/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/WPF/Demo/Views/Basics.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
26 |
27 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/WPF/Demo/Views/Basics.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace Demo
4 | {
5 | public partial class Basics : UserControl
6 | {
7 | public Basics()
8 | {
9 | InitializeComponent();
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/WPF/Demo/Views/Events.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/WPF/Demo/Views/Events.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace Demo
4 | {
5 | public partial class Events : UserControl
6 | {
7 | public Events()
8 | {
9 | InitializeComponent();
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/WPF/Demo/Views/Extending.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
18 |
19 |
--------------------------------------------------------------------------------
/WPF/Demo/Views/Extending.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace Demo
4 | {
5 | public partial class Extending : UserControl
6 | {
7 | public Extending()
8 | {
9 | InitializeComponent();
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/WPF/Demo/Views/Styling.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
27 |
28 |
29 |
30 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
64 |
65 |
66 |
67 |
70 |
71 |
72 |
73 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/WPF/Demo/Views/Styling.xaml.cs:
--------------------------------------------------------------------------------
1 | using System.Windows.Controls;
2 |
3 | namespace Demo
4 | {
5 | public partial class Styling : UserControl
6 | {
7 | public Styling()
8 | {
9 | InitializeComponent();
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/WPF/Demo/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/WPF/ToggleSwitch.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 11.00
3 | # Visual Studio 2010
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Demo", "Demo\Demo.csproj", "{41423C97-80FA-4D0E-81A6-6E173A97A5B0}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ToggleSwitch", "ToggleSwitch\ToggleSwitch.csproj", "{F9426059-27DB-45F0-9012-B1234965FBE0}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {41423C97-80FA-4D0E-81A6-6E173A97A5B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {41423C97-80FA-4D0E-81A6-6E173A97A5B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {41423C97-80FA-4D0E-81A6-6E173A97A5B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {41423C97-80FA-4D0E-81A6-6E173A97A5B0}.Release|Any CPU.Build.0 = Release|Any CPU
18 | {F9426059-27DB-45F0-9012-B1234965FBE0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {F9426059-27DB-45F0-9012-B1234965FBE0}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {F9426059-27DB-45F0-9012-B1234965FBE0}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {F9426059-27DB-45F0-9012-B1234965FBE0}.Release|Any CPU.Build.0 = Release|Any CPU
22 | EndGlobalSection
23 | GlobalSection(SolutionProperties) = preSolution
24 | HideSolutionNode = FALSE
25 | EndGlobalSection
26 | EndGlobal
27 |
--------------------------------------------------------------------------------
/WPF/ToggleSwitch/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reflection;
3 | using System.Resources;
4 | using System.Runtime.InteropServices;
5 | using System.Windows;
6 |
7 | // General Information about an assembly is controlled through the following
8 | // set of attributes. Change these attribute values to modify the information
9 | // associated with an assembly.
10 | [assembly: AssemblyTrademark("")]
11 | [assembly: AssemblyCulture("")]
12 | [assembly: ThemeInfo(ResourceDictionaryLocation.SourceAssembly, ResourceDictionaryLocation.SourceAssembly)]
13 |
14 | // Setting ComVisible to false makes the types in this assembly not visible
15 | // to COM components. If you need to access a type in this assembly from
16 | // COM, set the ComVisible attribute to true on that type.
17 | [assembly: ComVisible(false)]
18 |
19 | // The following GUID is for the ID of the typelib if this project is exposed to COM
20 | [assembly: Guid("528c2286-1b0e-4419-972a-b28dd5a33232")]
21 |
22 | [assembly: NeutralResourcesLanguageAttribute("en")]
23 | [assembly: CLSCompliant(true)]
--------------------------------------------------------------------------------
/WPF/ToggleSwitch/Themes/Generic.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
64 |
65 |
66 |
149 |
150 |
151 |
201 |
202 |
203 |
207 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
223 |
224 |
225 |
226 |
227 |
231 |
232 |
233 |
234 |
235 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
269 |
270 |
275 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
283 |
289 |
296 |
301 |
302 |
303 |
304 |
305 |
306 |
307 |
308 |
309 |
310 |
311 |
312 |
313 |
314 |
315 |
316 | Visible
317 |
318 |
319 |
320 |
321 |
322 |
323 |
324 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 |
337 |
338 |
339 |
340 |
344 |
406 |
407 |
411 |
412 |
413 |
459 |
--------------------------------------------------------------------------------
/WPF/ToggleSwitch/ToggleSwitch.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Library
4 | net46;netcoreapp3.1
5 | true
6 |
7 |
8 | Toggle Switch Control Library
9 | Toggle Switch Control Library
10 | Copyright © Eric Jensen 2020
11 | 1.2.0.0
12 | 1.2.0.0
13 | true
14 | https://github.com/ejensen/toggle-switch-control
15 | https://github.com/ejensen/toggle-switch-control
16 | Yeti Labs
17 | true
18 | Eric Jensen
19 | 1.2.0
20 | icon.png
21 | MIT
22 | git
23 |
24 |
25 |
26 | Borders\ClippingBorder.cs
27 |
28 |
29 | Borders\InnerGlowBorder.cs
30 |
31 |
32 | Borders\OuterGlowBorder.cs
33 |
34 |
35 | HorizontalToggleSwitch.cs
36 |
37 |
38 | ToggleSwitchBase.cs
39 |
40 |
41 | Utils\ActualSizePropertyProxy.cs
42 |
43 |
44 | Utils\HelperExtensions.cs
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 | True
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/WPF/ToggleSwitch/ToggleSwitchKey.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ejensen/toggle-switch-control/1761c450de096c7cea7ec1d81f337ed7f9e69624/WPF/ToggleSwitch/ToggleSwitchKey.snk
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ejensen/toggle-switch-control/1761c450de096c7cea7ec1d81f337ed7f9e69624/icon.png
--------------------------------------------------------------------------------