├── .gitignore
├── LICENSE
├── README.md
├── String_64x.png
├── appveyor.yml
└── source
├── CleanAll.bat
├── Demo
├── App.config
├── App.xaml
├── App.xaml.cs
├── Behaviour
│ └── SelectionChangedBehavior.cs .cs
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── Resources
│ └── PencilTool16.png
├── Themes
│ ├── Converters
│ │ ├── BackgroundToForegroundConverter.cs
│ │ ├── MarkupConverter.cs
│ │ └── ToUpperConverter .cs
│ ├── Dark
│ │ ├── Brushes.xaml
│ │ ├── CheckBox.xaml
│ │ ├── ComboBox.xaml
│ │ ├── DarkBrushes.xaml
│ │ ├── GroupBox.xaml
│ │ ├── TabControl.xaml
│ │ ├── TextBlock.xaml
│ │ └── TextBox.xaml
│ ├── DarkTheme.xaml
│ ├── LightTheme.xaml
│ └── Selector
│ │ ├── ThemeResourceDictionary .cs
│ │ └── ThemeSelector.cs
├── ViewModels
│ ├── AppViewModel.cs
│ ├── Base
│ │ ├── RelayCommand.cs
│ │ └── ViewModelBase.cs
│ └── ThemeDefinition.cs
└── WatermarkControlsDemo.csproj
├── Lib
├── AssemblyInfo.cs
├── Controls
│ ├── AutoSelectTextBox
│ │ ├── AutoSelectTextBox.cs
│ │ └── Implementation
│ │ │ ├── AutoSelectBehaviorEnum.cs
│ │ │ └── QueryMoveFocusEventArgs.cs
│ ├── WatermarkComboBox.xaml
│ ├── WatermarkComboBox.xaml.cs
│ ├── WatermarkTextBox.xaml
│ └── WatermarkTextBox.xaml.cs
├── Core
│ └── Utilities
│ │ └── TreeHelper.cs
├── Themes
│ ├── Dark.xaml
│ ├── DarkBrushs.xaml
│ ├── Generic.xaml
│ ├── LightBrushs.xaml
│ └── ResourceKeys.cs
├── WatermarkControlsLib.csproj
└── WatermarkControlsLib.csproj.user
└── WatermarkControlsDemo.sln
/.gitignore:
--------------------------------------------------------------------------------
1 | source/packages/
2 | packages/
3 | 00_Release/
4 | 01_Nuget/
5 | debug/
6 | release/
7 | build/
8 | bin/
9 | obj/
10 | cache/
11 | log/
12 | tmp/
13 | /source/.vs/
14 | .vs/
15 |
16 | *~
17 | *.lock
18 | *.DS_Store
19 | *.swp
20 | *.out
21 | *.sou
22 | *.suo
23 | *.sqlite
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://ci.appveyor.com/project/Dirkster99/watermarkcontrolslib)
2 | [](https://github.com/Dirkster99/watermarkcontrolslib/releases/latest)
3 | [](http://nuget.org/packages/Dirkster.watermarkcontrolslib)
4 |
5 |  
6 |
7 | # WatermarkControlsLib
8 | Provides MVVM/WPF conform textbox and combobox control implementations for dark and light modern UIs
9 |
10 | The controls afre based on a refactored version from the WPF Tool Kit at: http://wpftoolkit.codeplex.com/
11 |
12 | # TextBox with Watermark
13 | 
14 |
15 | # ComboBox with Watermark
16 | 
17 | 
18 | 
19 |
20 |
21 | ## Theming
22 |
23 | Load *Light* or *Dark* brush resources in you resource dictionary to take advantage of existing definitions.
24 |
25 | ```XAML
26 |
27 |
28 |
29 | ```
30 |
31 | ```XAML
32 |
33 |
34 |
35 | ```
36 |
37 | These definitions do not theme all controls used within this library. You should use a standard theming library, such as:
38 | - [MahApps.Metro](https://github.com/MahApps/MahApps.Metro),
39 | - [MLib](https://github.com/Dirkster99/MLib), or
40 | - [MUI](https://github.com/firstfloorsoftware/mui)
41 |
--------------------------------------------------------------------------------
/String_64x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dirkster99/WatermarkControlsLib/8707bee9d277686d53c4ce4d347d1a0a1274a8e8/String_64x.png
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | version: 1.3.{build}
2 |
3 | configuration: Release
4 |
5 | platform: Any CPU
6 |
7 | image: Visual Studio 2019 Preview
8 |
9 | install:
10 | - cmd: choco install dotnetcore-sdk --pre
11 |
12 | before_build:
13 |
14 | - cmd: nuget restore source\WatermarkControlsDemo.sln
15 |
16 | build:
17 |
18 | verbosity: minimal
19 |
20 | artifacts:
21 |
22 | - path: source\Demo\bin\Release
23 | name: WatermarkControlsDemo
24 |
25 | - path: source\Lib\bin\Release
26 | name: WatermarkControlsLib
27 |
--------------------------------------------------------------------------------
/source/CleanAll.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 | pushd "%~dp0"
3 | ECHO.
4 | ECHO.
5 | ECHO.
6 | ECHO This script deletes all temporary build files in the .vs folder and the
7 | ECHO BIN and OBJ folders contained in the following projects
8 | ECHO.
9 | ECHO Demo
10 | ECHO Lib
11 | ECHO.
12 | REM Ask the user if hes really sure to continue beyond this point XXXXXXXX
13 | set /p choice=Are you sure to continue (Y/N)?
14 | if not '%choice%'=='Y' Goto EndOfBatch
15 | REM Script does not continue unless user types 'Y' in upper case letter
16 | ECHO.
17 | ECHO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
18 | ECHO.
19 | ECHO XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
20 | ECHO.
21 | ECHO Removing .vs folder
22 | ECHO.
23 | RMDIR /S /Q .vs
24 |
25 | ECHO.
26 | ECHO Deleting BIN and OBJ Folders in Demo
27 | ECHO.
28 | RMDIR /S /Q "Demo\bin"
29 | RMDIR /S /Q "Demo\obj"
30 |
31 | ECHO.
32 | ECHO Deleting BIN and OBJ Folders in Lib
33 | ECHO.
34 | RMDIR /S /Q "Lib\bin"
35 | RMDIR /S /Q "Lib\obj"
36 |
37 | PAUSE
38 |
39 | :EndOfBatch
40 |
--------------------------------------------------------------------------------
/source/Demo/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source/Demo/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/source/Demo/App.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace WatermarkControlsDemo
2 | {
3 | using System.Windows;
4 |
5 | ///
6 | /// Interaction logic for App.xaml
7 | ///
8 | public partial class App : Application
9 | {
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/source/Demo/Behaviour/SelectionChangedBehavior.cs .cs:
--------------------------------------------------------------------------------
1 | namespace WatermarkControlsDemo.Behaviour
2 | {
3 | using System.Windows;
4 | using System.Windows.Controls;
5 | using System.Windows.Controls.Primitives;
6 | using System.Windows.Input;
7 |
8 | ///
9 | /// Attached behaviour to implement a selection changed command on a combobox.
10 | /// The combobox generates a SelectionChanged event which in turn generates a
11 | /// Command (in this behavior), which in turn is, when bound, invoked on the viewmodel.
12 | ///
13 | public static class SelectionChangedCommand
14 | {
15 | // Field of attached ICommand property
16 | private static readonly DependencyProperty ChangedCommandProperty = DependencyProperty.RegisterAttached(
17 | "ChangedCommand",
18 | typeof(ICommand),
19 | typeof(SelectionChangedCommand),
20 | new PropertyMetadata(null, OnSelectionChangedCommandChange));
21 |
22 |
23 |
24 | ///
25 | /// Setter method of the attached DropCommand property
26 | ///
27 | ///
28 | ///
29 | public static void SetChangedCommand(DependencyObject source, ICommand value)
30 | {
31 | source.SetValue(ChangedCommandProperty, value);
32 | }
33 |
34 | ///
35 | /// Getter method of the attached DropCommand property
36 | ///
37 | ///
38 | ///
39 | public static ICommand GetChangedCommand(DependencyObject source)
40 | {
41 | return (ICommand)source.GetValue(ChangedCommandProperty);
42 | }
43 |
44 | ///
45 | /// This method is hooked in the definition of the .
46 | /// It is called whenever the attached property changes - in our case the event of binding
47 | /// and unbinding the property to a sink is what we are looking for.
48 | ///
49 | ///
50 | ///
51 | private static void OnSelectionChangedCommandChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
52 | {
53 | Selector uiElement = d as Selector; // Remove the handler if it exist to avoid memory leaks
54 |
55 | if (uiElement != null)
56 | {
57 | uiElement.SelectionChanged -= Selection_Changed;
58 | uiElement.KeyUp -= uiElement_KeyUp;
59 |
60 | var command = e.NewValue as ICommand;
61 | if (command != null)
62 | {
63 | // the property is attached so we attach the Drop event handler
64 | uiElement.SelectionChanged += Selection_Changed;
65 | uiElement.KeyUp += uiElement_KeyUp;
66 | }
67 | }
68 | }
69 |
70 | private static void uiElement_KeyUp(object sender, KeyEventArgs e)
71 | {
72 | if (e == null)
73 | return;
74 |
75 | // Forward key event only if user has hit the return, BackSlash, or Slash key
76 | if (e.Key != Key.Return)
77 | return;
78 |
79 | ComboBox uiElement = sender as ComboBox;
80 |
81 | // Sanity check just in case this was somehow send by something else
82 | if (uiElement == null)
83 | return;
84 |
85 | ICommand changedCommand = SelectionChangedCommand.GetChangedCommand(uiElement);
86 |
87 | // There may not be a command bound to this after all
88 | if (changedCommand == null)
89 | return;
90 |
91 | // Check whether this attached behaviour is bound to a RoutedCommand
92 | if (changedCommand is RoutedCommand)
93 | {
94 | // Execute the routed command
95 | (changedCommand as RoutedCommand).Execute(uiElement.Text, uiElement);
96 | }
97 | else
98 | {
99 | // Execute the Command as bound delegate
100 | changedCommand.Execute(uiElement.Text);
101 | }
102 | }
103 |
104 | ///
105 | /// This method is called when the selection changed event occurs. The sender should be the control
106 | /// on which this behaviour is attached - so we convert the sender into a
107 | /// and receive the Command through the getter listed above.
108 | ///
109 | /// This implementation supports binding of delegate commands and routed commands.
110 | ///
111 | ///
112 | ///
113 | private static void Selection_Changed(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
114 | {
115 | Selector uiElement = sender as Selector;
116 |
117 | // Sanity check just in case this was somehow send by something else
118 | if (uiElement == null)
119 | return;
120 |
121 | ICommand changedCommand = SelectionChangedCommand.GetChangedCommand(uiElement);
122 |
123 | // There may not be a command bound to this after all
124 | if (changedCommand == null)
125 | return;
126 |
127 | // Check whether this attached behaviour is bound to a RoutedCommand
128 | if (changedCommand is RoutedCommand)
129 | {
130 | // Execute the routed command
131 | (changedCommand as RoutedCommand).Execute(e.AddedItems, uiElement);
132 | }
133 | else
134 | {
135 | // Execute the Command as bound delegate
136 | changedCommand.Execute(e.AddedItems);
137 | }
138 | }
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/source/Demo/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
38 | The WatermarkTextBox is a TextBox that allows you to sepcify an object, usually a String, to represent null or missing text.
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
53 |
54 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
74 |
75 |
76 |
80 |
81 |
82 |
83 |
85 |
86 |
87 |
88 |
89 |
90 |
96 |
97 |
98 |
101 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
139 |
140 |
141 |
142 |
143 |
144 | The WatermarkComboBox is a ComboBox with a fully customizable watermark.
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
173 |
176 |
184 |
185 |
186 |
187 |
188 |
189 |
195 |
196 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
--------------------------------------------------------------------------------
/source/Demo/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | namespace WatermarkControlsDemo
2 | {
3 | using System.Windows;
4 |
5 | ///
6 | /// Interaction logic for MainWindow.xaml
7 | ///
8 | public partial class MainWindow : Window
9 | {
10 | ///
11 | /// Class Constructor
12 | ///
13 | public MainWindow()
14 | {
15 | this.InitializeComponent();
16 |
17 | this.DataContext = new ViewModels.AppViewModel();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/source/Demo/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Resources;
3 | using System.Runtime.CompilerServices;
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: AssemblyTitle("WatermarkControlsDemo")]
11 | [assembly: AssemblyDescription("")]
12 | [assembly: AssemblyConfiguration("")]
13 | [assembly: AssemblyCompany("")]
14 | [assembly: AssemblyProduct("WatermarkControlsDemo")]
15 | [assembly: AssemblyCopyright("Copyright © 2016")]
16 | [assembly: AssemblyTrademark("")]
17 | [assembly: AssemblyCulture("")]
18 |
19 | // Setting ComVisible to false makes the types in this assembly not visible
20 | // to COM components. If you need to access a type in this assembly from
21 | // COM, set the ComVisible attribute to true on that type.
22 | [assembly: ComVisible(false)]
23 |
24 | //In order to begin building localizable applications, set
25 | //CultureYouAreCodingWith in your .csproj file
26 | //inside a . For example, if you are using US english
27 | //in your source files, set the to en-US. Then uncomment
28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
29 | //the line below to match the UICulture setting in the project file.
30 |
31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
32 |
33 |
34 | [assembly: ThemeInfo(
35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
36 | //(used if a resource is not found in the page,
37 | // or application resource dictionaries)
38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
39 | //(used if a resource is not found in the page,
40 | // app, or any theme specific resource dictionaries)
41 | )]
42 |
43 |
44 | // Version information for an assembly consists of the following four values:
45 | //
46 | // Major Version
47 | // Minor Version
48 | // Build Number
49 | // Revision
50 | //
51 | // You can specify all the values or you can default the Build and Revision Numbers
52 | // by using the '*' as shown below:
53 | // [assembly: AssemblyVersion("1.0.*")]
54 | [assembly: AssemblyVersion("1.0.0.0")]
55 | [assembly: AssemblyFileVersion("1.0.0.0")]
56 |
--------------------------------------------------------------------------------
/source/Demo/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
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 WatermarkControlsDemo.Properties
12 | {
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 |
28 | private static global::System.Resources.ResourceManager resourceMan;
29 |
30 | private static global::System.Globalization.CultureInfo resourceCulture;
31 |
32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
33 | internal Resources()
34 | {
35 | }
36 |
37 | ///
38 | /// Returns the cached ResourceManager instance used by this class.
39 | ///
40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
41 | internal static global::System.Resources.ResourceManager ResourceManager
42 | {
43 | get
44 | {
45 | if ((resourceMan == null))
46 | {
47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WatermarkControlsDemo.Properties.Resources", typeof(Resources).Assembly);
48 | resourceMan = temp;
49 | }
50 | return resourceMan;
51 | }
52 | }
53 |
54 | ///
55 | /// Overrides the current thread's CurrentUICulture property for all
56 | /// resource lookups using this strongly typed resource class.
57 | ///
58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
59 | internal static global::System.Globalization.CultureInfo Culture
60 | {
61 | get
62 | {
63 | return resourceCulture;
64 | }
65 | set
66 | {
67 | resourceCulture = value;
68 | }
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/source/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 |
--------------------------------------------------------------------------------
/source/Demo/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
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 WatermarkControlsDemo.Properties
12 | {
13 |
14 |
15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
18 | {
19 |
20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
21 |
22 | public static Settings Default
23 | {
24 | get
25 | {
26 | return defaultInstance;
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/source/Demo/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/source/Demo/Resources/PencilTool16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dirkster99/WatermarkControlsLib/8707bee9d277686d53c4ce4d347d1a0a1274a8e8/source/Demo/Resources/PencilTool16.png
--------------------------------------------------------------------------------
/source/Demo/Themes/Converters/BackgroundToForegroundConverter.cs:
--------------------------------------------------------------------------------
1 | namespace WatermarkControlsDemo.Themes.Converters
2 | {
3 | using System;
4 | using System.Globalization;
5 | using System.Linq;
6 | using System.Windows;
7 | using System.Windows.Data;
8 | using System.Windows.Media;
9 |
10 | public class BackgroundToForegroundConverter : IValueConverter, IMultiValueConverter
11 | {
12 | private static BackgroundToForegroundConverter _instance;
13 |
14 | // Explicit static constructor to tell C# compiler
15 | // not to mark type as beforefieldinit
16 | static BackgroundToForegroundConverter()
17 | {
18 | }
19 |
20 | private BackgroundToForegroundConverter()
21 | {
22 | }
23 |
24 | public static BackgroundToForegroundConverter Instance
25 | {
26 | get { return _instance ?? (_instance = new BackgroundToForegroundConverter()); }
27 | }
28 |
29 | ///
30 | /// Determining Ideal Text Color Based on Specified Background Color
31 | /// http://www.codeproject.com/KB/GDI-plus/IdealTextColor.aspx
32 | ///
33 | /// The bg.
34 | ///
35 | private Color IdealTextColor(Color bg)
36 | {
37 | const int nThreshold = 105;
38 | var bgDelta = System.Convert.ToInt32((bg.R * 0.299) + (bg.G * 0.587) + (bg.B * 0.114));
39 | var foreColor = (255 - bgDelta < nThreshold) ? Colors.Black : Colors.White;
40 | return foreColor;
41 | }
42 |
43 | public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
44 | {
45 | if (value is SolidColorBrush)
46 | {
47 | var idealForegroundColor = this.IdealTextColor(((SolidColorBrush)value).Color);
48 | var foreGroundBrush = new SolidColorBrush(idealForegroundColor);
49 | foreGroundBrush.Freeze();
50 | return foreGroundBrush;
51 | }
52 | return Brushes.White;
53 | }
54 |
55 | public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
56 | {
57 | return DependencyProperty.UnsetValue;
58 | }
59 |
60 | public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
61 | {
62 | var bgBrush = values.Length > 0 ? values[0] as Brush : null;
63 | var titleBrush = values.Length > 1 ? values[1] as Brush : null;
64 | if (titleBrush != null)
65 | {
66 | return titleBrush;
67 | }
68 | return Convert(bgBrush, targetType, parameter, culture);
69 | }
70 |
71 | public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
72 | {
73 | return targetTypes.Select(t => DependencyProperty.UnsetValue).ToArray();
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/source/Demo/Themes/Converters/MarkupConverter.cs:
--------------------------------------------------------------------------------
1 |
2 | namespace WatermarkControlsDemo.Themes.Converters
3 | {
4 | using System;
5 | using System.Globalization;
6 | using System.Windows;
7 | using System.Windows.Data;
8 | using System.Windows.Markup;
9 |
10 | [MarkupExtensionReturnType(typeof(IValueConverter))]
11 | public abstract class MarkupConverter : MarkupExtension, IValueConverter
12 | {
13 | public override object ProvideValue(IServiceProvider serviceProvider)
14 | {
15 | return this;
16 | }
17 |
18 | protected abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);
19 | protected abstract object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
20 |
21 | object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
22 | {
23 | try
24 | {
25 | return Convert(value, targetType, parameter, culture);
26 | }
27 | catch
28 | {
29 | return DependencyProperty.UnsetValue;
30 | }
31 | }
32 |
33 | object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
34 | {
35 | try
36 | {
37 | return ConvertBack(value, targetType, parameter, culture);
38 | }
39 | catch
40 | {
41 | return DependencyProperty.UnsetValue;
42 | }
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/source/Demo/Themes/Converters/ToUpperConverter .cs:
--------------------------------------------------------------------------------
1 | namespace WatermarkControlsDemo.Themes.Converters
2 | {
3 | using System;
4 | using System.Globalization;
5 | using System.Windows.Data;
6 |
7 | public class ToUpperConverter : MarkupConverter
8 | {
9 | protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
10 | {
11 | var val = value as string;
12 | return val != null ? val.ToUpper() : value;
13 | }
14 |
15 | protected override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
16 | {
17 | return Binding.DoNothing;
18 | }
19 | }
20 |
21 | public class ToLowerConverter : MarkupConverter
22 | {
23 | protected override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
24 | {
25 | var val = value as string;
26 | return val != null ? val.ToLower() : value;
27 | }
28 |
29 | protected override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
30 | {
31 | return Binding.DoNothing;
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/source/Demo/Themes/Dark/Brushes.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
19 |
20 |
21 |
22 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
58 |
59 |
60 |
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 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 | #FFD8F0FA
155 | #10FFFFFF
156 |
157 | #FFF4FAFD
158 | #FFCFEDFD
159 | #FFE2F5FF
160 | #FFC0E7FC
161 | #FF9EDDFF
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 | #FF595959
182 | #FF393939
183 | #FF9BB1C5
184 | #FFCFCFCF
185 |
186 |
187 |
188 | #FFFFFFFF
189 | #FF737373
190 |
191 | #FF000000
192 | #FFFFFFFF
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
--------------------------------------------------------------------------------
/source/Demo/Themes/Dark/CheckBox.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
65 |
66 |
67 |
73 |
74 |
78 |
79 |
--------------------------------------------------------------------------------
/source/Demo/Themes/Dark/DarkBrushes.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 | #1ba1e2
7 |
8 |
9 |
10 |
11 | #151516
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
--------------------------------------------------------------------------------
/source/Demo/Themes/Dark/GroupBox.xaml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
41 |
42 |
43 |
46 |
47 |
48 |
49 |
53 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/source/Demo/Themes/Dark/TabControl.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
62 |
63 | #1ba1e2
64 |
65 |
66 | #808080
67 | #B0B0B0
68 |
69 |
126 |
127 |
--------------------------------------------------------------------------------
/source/Demo/Themes/Dark/TextBlock.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/source/Demo/Themes/Dark/TextBox.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
92 |
93 |
177 |
178 |
261 |
262 |
--------------------------------------------------------------------------------
/source/Demo/Themes/DarkTheme.xaml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/source/Demo/Themes/LightTheme.xaml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/source/Demo/Themes/Selector/ThemeResourceDictionary .cs:
--------------------------------------------------------------------------------
1 | namespace WatermarkControlsDemo.Themes.Selector
2 | {
3 | class ThemeResourceDictionary : System.Windows.ResourceDictionary
4 | {
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/source/Demo/Themes/Selector/ThemeSelector.cs:
--------------------------------------------------------------------------------
1 | namespace WatermarkControlsDemo.Themes.Selector
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Windows;
7 |
8 | ///
9 | /// Source: http://svetoslavsavov.blogspot.de/2009/07/switching-wpf-interface-themes-at.html
10 | ///
11 | public class ThemeSelector : DependencyObject
12 | {
13 | public static readonly DependencyProperty CurrentThemeDictionaryProperty =
14 | DependencyProperty.RegisterAttached("CurrentThemeDictionary",
15 | typeof(Uri),
16 | typeof(ThemeSelector),
17 |
18 | new UIPropertyMetadata(null, CurrentThemeDictionaryChanged));
19 |
20 | public static Uri GetCurrentThemeDictionary(DependencyObject obj)
21 | {
22 | return (Uri)obj.GetValue(CurrentThemeDictionaryProperty);
23 | }
24 |
25 | public static void SetCurrentThemeDictionary(DependencyObject obj, Uri value)
26 | {
27 | obj.SetValue(CurrentThemeDictionaryProperty, value);
28 | }
29 |
30 | private static void CurrentThemeDictionaryChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
31 | {
32 | if (obj is FrameworkElement) // works only on FrameworkElement objects
33 | {
34 | ApplyTheme(obj as FrameworkElement, GetCurrentThemeDictionary(obj));
35 | }
36 | }
37 |
38 | private static void ApplyTheme(FrameworkElement targetElement, Uri dictionaryUri)
39 | {
40 | if (targetElement == null) return;
41 |
42 | try
43 | {
44 | ThemeResourceDictionary themeDictionary = null;
45 | if (dictionaryUri != null)
46 | {
47 | themeDictionary = new ThemeResourceDictionary();
48 | themeDictionary.Source = dictionaryUri;
49 |
50 | // add the new dictionary to the collection of merged dictionaries of the target object
51 | targetElement.Resources.MergedDictionaries.Insert(0, themeDictionary);
52 | }
53 |
54 | // find if the target element already has a theme applied
55 | List existingDictionaries =
56 | (from dictionary in targetElement.Resources.MergedDictionaries.OfType()
57 | select dictionary).ToList();
58 |
59 | // remove the existing dictionaries
60 | foreach (ThemeResourceDictionary thDictionary in existingDictionaries)
61 | {
62 | if (themeDictionary == thDictionary) continue; // don't remove the newly added dictionary
63 | targetElement.Resources.MergedDictionaries.Remove(thDictionary);
64 | }
65 | }
66 | finally { }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/source/Demo/ViewModels/AppViewModel.cs:
--------------------------------------------------------------------------------
1 | namespace WatermarkControlsDemo.ViewModels
2 | {
3 | using Base;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Windows;
7 | using System.Windows.Input;
8 | using Themes.Selector;
9 |
10 | public class AppViewModel : Base.ViewModelBase
11 | {
12 | #region private fields
13 | private List _ListOfThemes = null;
14 | private ICommand _SelectionChanged = null;
15 | private bool _IsThemeSelectionEnabled = false;
16 | #endregion private fields
17 |
18 | #region constructors
19 | public AppViewModel()
20 | {
21 | _ListOfThemes = new List();
22 |
23 | _ListOfThemes.Add(new ThemeDefinition("Light", "/WatermarkControlsDemo;component/Themes/LightTheme.xaml"));
24 | _ListOfThemes.Add(new ThemeDefinition("Dark", "/WatermarkControlsDemo;component/Themes/DarkTheme.xaml"));
25 | }
26 | #endregion constructors
27 |
28 | #region properties
29 | ///
30 | /// Returns a list of theme definitons.
31 | ///
32 | public List ListOfThemes
33 | {
34 | get
35 | {
36 | return this._ListOfThemes;
37 | }
38 | }
39 |
40 | ///
41 | /// Command executes when the user has selected
42 | /// a different UI theme to display.
43 | ///
44 | public ICommand SelectionChanged
45 | {
46 | get
47 | {
48 | if (_SelectionChanged == null)
49 | {
50 | _SelectionChanged = new RelayCommand