├── .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 | [![Build status](https://ci.appveyor.com/api/projects/status/c44414w3s1ow8eb5?svg=true)](https://ci.appveyor.com/project/Dirkster99/watermarkcontrolslib) 2 | [![Release](https://img.shields.io/github/release/Dirkster99/watermarkcontrolslib.svg)](https://github.com/Dirkster99/watermarkcontrolslib/releases/latest) 3 | [![NuGet](https://img.shields.io/nuget/dt/Dirkster.watermarkcontrolslib.svg)](http://nuget.org/packages/Dirkster.watermarkcontrolslib) 4 | 5 | ![Net4](https://badgen.net/badge/Framework/.Net 4/blue) ![NetCore3](https://badgen.net/badge/Framework/NetCore 3/blue) 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 | ![](https://github.com/Dirkster99/Docu/blob/master/WatermarkControlsLib/screenshot.png) 14 | 15 | # ComboBox with Watermark 16 | ![](https://github.com/Dirkster99/Docu/blob/master/WatermarkControlsLib/screenshot1.png) 17 | ![](https://github.com/Dirkster99/Docu/blob/master/WatermarkControlsLib/screenshot2.png) 18 | ![](https://github.com/Dirkster99/Docu/blob/master/WatermarkControlsLib/screenshot3.png) 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((p) => 51 | { 52 | object[] paramets = p as object[]; 53 | 54 | if (paramets != null) 55 | { 56 | ThemeDefinition ts = paramets[0] as ThemeDefinition; 57 | 58 | if (ts != null) 59 | { 60 | IsThemeSelectionEnabled = false; 61 | try 62 | { 63 | ThemeSelector.SetCurrentThemeDictionary(Application.Current.MainWindow 64 | , new Uri(ts.Source, UriKind.RelativeOrAbsolute)); 65 | } 66 | catch (Exception) 67 | { 68 | } 69 | finally 70 | { 71 | IsThemeSelectionEnabled = true; 72 | } 73 | } 74 | } 75 | }); 76 | } 77 | 78 | return _SelectionChanged; 79 | } 80 | } 81 | 82 | /// 83 | /// Gets whether a different theme can be selected right now or not. 84 | /// This property should be bound to the UI that selects a different 85 | /// theme to avoid the case in which a user could select a theme and 86 | /// select a different theme while the first theme change request is 87 | /// still processed. 88 | /// 89 | public bool IsThemeSelectionEnabled 90 | { 91 | get { return _IsThemeSelectionEnabled; } 92 | 93 | private set 94 | { 95 | if (this._IsThemeSelectionEnabled != value) 96 | { 97 | _IsThemeSelectionEnabled = value; 98 | RaisePropertyChanged(() => this._IsThemeSelectionEnabled); 99 | } 100 | } 101 | } 102 | #endregion properties 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /source/Demo/ViewModels/Base/RelayCommand.cs: -------------------------------------------------------------------------------- 1 | namespace WatermarkControlsDemo.ViewModels.Base 2 | { 3 | using System; 4 | using System.Diagnostics; 5 | using System.Windows.Input; 6 | 7 | /// 8 | /// A command whose sole purpose is to 9 | /// relay its functionality to other 10 | /// objects by invoking delegates. The 11 | /// default return value for the CanExecute 12 | /// method is 'true'. 13 | /// 14 | /// Source: http://www.codeproject.com/Articles/31837/Creating-an-Internationalized-Wizard-in-WPF 15 | /// 16 | internal class RelayCommand : ICommand 17 | { 18 | #region Fields 19 | private readonly Action mExecute = null; 20 | private readonly Predicate mCanExecute = null; 21 | #endregion // Fields 22 | 23 | #region Constructors 24 | /// 25 | /// Class constructor 26 | /// 27 | /// 28 | public RelayCommand(Action execute) 29 | : this(execute, null) 30 | { 31 | } 32 | 33 | /// 34 | /// Creates a new command. 35 | /// 36 | /// The execution logic. 37 | /// The execution status logic. 38 | public RelayCommand(Action execute, Predicate canExecute) 39 | { 40 | if (execute == null) 41 | throw new ArgumentNullException("execute"); 42 | 43 | this.mExecute = execute; 44 | this.mCanExecute = canExecute; 45 | } 46 | 47 | #endregion // Constructors 48 | 49 | #region events 50 | /// 51 | /// Eventhandler to re-evaluate whether this command can execute or not 52 | /// 53 | public event EventHandler CanExecuteChanged 54 | { 55 | add 56 | { 57 | if (this.mCanExecute != null) 58 | CommandManager.RequerySuggested += value; 59 | } 60 | 61 | remove 62 | { 63 | if (this.mCanExecute != null) 64 | CommandManager.RequerySuggested -= value; 65 | } 66 | } 67 | #endregion 68 | 69 | #region methods 70 | /// 71 | /// Determine whether this pre-requisites to execute this command are given or not. 72 | /// 73 | /// 74 | /// 75 | [DebuggerStepThrough] 76 | public bool CanExecute(object parameter) 77 | { 78 | return this.mCanExecute == null ? true : this.mCanExecute((T)parameter); 79 | } 80 | 81 | /// 82 | /// Execute the command method managed in this class. 83 | /// 84 | /// 85 | public void Execute(object parameter) 86 | { 87 | this.mExecute((T)parameter); 88 | } 89 | #endregion methods 90 | } 91 | 92 | /// 93 | /// A command whose sole purpose is to 94 | /// relay its functionality to other 95 | /// objects by invoking delegates. The 96 | /// default return value for the CanExecute 97 | /// method is 'true'. 98 | /// 99 | internal class RelayCommand : ICommand 100 | { 101 | #region Fields 102 | private readonly Action mExecute; 103 | private readonly Func mCanExecute; 104 | #endregion Fields 105 | 106 | #region Constructors 107 | 108 | /// 109 | /// Creates a new command that can always execute. 110 | /// 111 | /// The execution logic. 112 | public RelayCommand(Action execute) 113 | : this(execute, null) 114 | { 115 | } 116 | 117 | /// 118 | /// Copy constructor 119 | /// 120 | /// 121 | public RelayCommand(RelayCommand inputRC) 122 | : this(inputRC.mExecute, inputRC.mCanExecute) 123 | { 124 | } 125 | 126 | /// 127 | /// Creates a new command. 128 | /// 129 | /// The execution logic. 130 | /// The execution status logic. 131 | public RelayCommand(Action execute, Func canExecute) 132 | { 133 | if (execute == null) 134 | throw new ArgumentNullException("execute"); 135 | 136 | this.mExecute = execute; 137 | this.mCanExecute = canExecute; 138 | } 139 | 140 | #endregion Constructors 141 | 142 | #region Events 143 | /// 144 | /// Eventhandler to re-evaluate whether this command can execute or not 145 | /// 146 | public event EventHandler CanExecuteChanged 147 | { 148 | add 149 | { 150 | if (this.mCanExecute != null) 151 | CommandManager.RequerySuggested += value; 152 | } 153 | 154 | remove 155 | { 156 | if (this.mCanExecute != null) 157 | CommandManager.RequerySuggested -= value; 158 | } 159 | } 160 | #endregion Events 161 | 162 | #region Methods 163 | /// 164 | /// Execute the attached CanExecute methode delegate (or always return true) 165 | /// to determine whether the command managed in this object can execute or not. 166 | /// 167 | /// 168 | /// 169 | [DebuggerStepThrough] 170 | public bool CanExecute(object parameter) 171 | { 172 | return this.mCanExecute == null ? true : this.mCanExecute(); 173 | } 174 | 175 | /// 176 | /// Return the attached delegate method. 177 | /// 178 | /// 179 | public void Execute(object parameter) 180 | { 181 | this.mExecute(); 182 | } 183 | #endregion Methods 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /source/Demo/ViewModels/Base/ViewModelBase.cs: -------------------------------------------------------------------------------- 1 | namespace WatermarkControlsDemo.ViewModels.Base 2 | { 3 | using System; 4 | using System.ComponentModel; 5 | using System.Linq.Expressions; 6 | 7 | /// 8 | /// Implements a base class for all viewmodel classes 9 | /// that implements interface for binding. 10 | /// 11 | public class ViewModelBase : INotifyPropertyChanged 12 | { 13 | /// 14 | /// Standard implementation of . 15 | /// 16 | public event PropertyChangedEventHandler PropertyChanged; 17 | 18 | /// 19 | /// Tell bound controls (via WPF binding) to refresh their display. 20 | /// 21 | /// Sample call: this.NotifyPropertyChanged(() => this.IsSelected); 22 | /// where 'this' is derived from 23 | /// and IsSelected is a property. 24 | /// 25 | /// 26 | /// 27 | public void RaisePropertyChanged(Expression> property) 28 | { 29 | var lambda = (LambdaExpression)property; 30 | MemberExpression memberExpression; 31 | 32 | if (lambda.Body is UnaryExpression) 33 | { 34 | var unaryExpression = (UnaryExpression)lambda.Body; 35 | memberExpression = (MemberExpression)unaryExpression.Operand; 36 | } 37 | else 38 | memberExpression = (MemberExpression)lambda.Body; 39 | 40 | this.RaisePropertyChanged(memberExpression.Member.Name); 41 | } 42 | 43 | /// 44 | /// Tell bound controls (via WPF binding) to refresh their display. 45 | /// Standard implementation through . 46 | /// 47 | /// 48 | protected virtual void RaisePropertyChanged(string propertyName) 49 | { 50 | if (this.PropertyChanged != null) 51 | this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /source/Demo/ViewModels/ThemeDefinition.cs: -------------------------------------------------------------------------------- 1 | namespace WatermarkControlsDemo.ViewModels 2 | { 3 | /// 4 | /// Defines a theme by its name, source etc... 5 | /// 6 | public class ThemeDefinition 7 | { 8 | /// 9 | /// Hidden standard constructor. 10 | /// 11 | private ThemeDefinition() 12 | { 13 | } 14 | 15 | /// 16 | /// Parameterized constructor. 17 | /// 18 | /// 19 | /// 20 | public ThemeDefinition(string name, string source) 21 | { 22 | this.Name = (name != null ? name : string.Empty); 23 | this.Source = (source != null ? source : string.Empty); 24 | } 25 | 26 | /// 27 | /// Identifies a theme by a Name that can be used as a key. 28 | /// 29 | public string Name { get; private set; } 30 | 31 | /// 32 | /// Uri formatted source for this theme. 33 | /// 34 | public string Source { get; private set; } 35 | } 36 | } -------------------------------------------------------------------------------- /source/Demo/WatermarkControlsDemo.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {2B19B61D-4BC1-4D3E-8464-F0028BE8C767} 8 | WinExe 9 | Properties 10 | WatermarkControlsDemo 11 | WatermarkControlsDemo 12 | v4.5.2 13 | 512 14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 4 16 | true 17 | 18 | 19 | AnyCPU 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | 28 | 29 | AnyCPU 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 4.0 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | MSBuild:Compile 56 | Designer 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | MSBuild:Compile 70 | Designer 71 | 72 | 73 | App.xaml 74 | Code 75 | 76 | 77 | MainWindow.xaml 78 | Code 79 | 80 | 81 | Designer 82 | MSBuild:Compile 83 | 84 | 85 | Designer 86 | MSBuild:Compile 87 | 88 | 89 | Designer 90 | MSBuild:Compile 91 | 92 | 93 | Designer 94 | MSBuild:Compile 95 | 96 | 97 | Designer 98 | MSBuild:Compile 99 | 100 | 101 | Designer 102 | MSBuild:Compile 103 | 104 | 105 | Designer 106 | MSBuild:Compile 107 | 108 | 109 | Designer 110 | MSBuild:Compile 111 | 112 | 113 | MSBuild:Compile 114 | Designer 115 | 116 | 117 | Designer 118 | MSBuild:Compile 119 | 120 | 121 | 122 | 123 | Code 124 | 125 | 126 | True 127 | True 128 | Resources.resx 129 | 130 | 131 | True 132 | Settings.settings 133 | True 134 | 135 | 136 | ResXFileCodeGenerator 137 | Resources.Designer.cs 138 | 139 | 140 | SettingsSingleFileGenerator 141 | Settings.Designer.cs 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | {a9354a6b-50be-44c0-9039-f46329108e1f} 151 | WatermarkControlsLib 152 | 153 | 154 | 155 | 156 | 157 | 158 | 165 | -------------------------------------------------------------------------------- /source/Lib/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Windows; 2 | 3 | [assembly: ThemeInfo( 4 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 5 | //(used if a resource is not found in the page, 6 | // or application resource dictionaries) 7 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 8 | //(used if a resource is not found in the page, 9 | // app, or any theme specific resource dictionaries) 10 | )] 11 | -------------------------------------------------------------------------------- /source/Lib/Controls/AutoSelectTextBox/AutoSelectTextBox.cs: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | 3 | Extended WPF Toolkit 4 | 5 | Copyright (C) 2007-2013 Xceed Software Inc. 6 | 7 | This program is provided to you under the terms of the Microsoft Public 8 | License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license 9 | 10 | For more features, controls, and fast professional support, 11 | pick up the Plus Edition at http://xceed.com/wpf_toolkit 12 | 13 | Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids 14 | 15 | ***********************************************************************************/ 16 | 17 | namespace WatermarkControlsLib.Controls.AutoSelectTextBox 18 | { 19 | using System.Windows; 20 | using System.Windows.Automation; 21 | using System.Windows.Controls; 22 | using System.Windows.Input; 23 | using WatermarkControlsLib.Controls.AutoSelectTextBox.Implementation; 24 | using WatermarkControlsLib.Core.Utilities; 25 | 26 | public class AutoSelectTextBox : TextBox 27 | { 28 | static AutoSelectTextBox() 29 | { 30 | AutomationProperties.AutomationIdProperty.OverrideMetadata(typeof(AutoSelectTextBox), new UIPropertyMetadata("AutoSelectTextBox")); 31 | } 32 | 33 | #region AutoSelectBehavior PROPERTY 34 | 35 | public AutoSelectBehavior AutoSelectBehavior 36 | { 37 | get 38 | { 39 | return (AutoSelectBehavior)GetValue(AutoSelectBehaviorProperty); 40 | } 41 | set 42 | { 43 | SetValue(AutoSelectBehaviorProperty, value); 44 | } 45 | } 46 | 47 | public static readonly DependencyProperty AutoSelectBehaviorProperty = 48 | DependencyProperty.Register("AutoSelectBehavior", typeof(AutoSelectBehavior), typeof(AutoSelectTextBox), 49 | new UIPropertyMetadata(AutoSelectBehavior.Never)); 50 | 51 | #endregion AutoSelectBehavior PROPERTY 52 | 53 | #region AutoMoveFocus PROPERTY 54 | 55 | public bool AutoMoveFocus 56 | { 57 | get 58 | { 59 | return (bool)GetValue(AutoMoveFocusProperty); 60 | } 61 | set 62 | { 63 | SetValue(AutoMoveFocusProperty, value); 64 | } 65 | } 66 | 67 | public static readonly DependencyProperty AutoMoveFocusProperty = 68 | DependencyProperty.Register("AutoMoveFocus", typeof(bool), typeof(AutoSelectTextBox), new UIPropertyMetadata(false)); 69 | 70 | #endregion AutoMoveFocus PROPERTY 71 | 72 | #region QueryMoveFocus EVENT 73 | 74 | public static readonly RoutedEvent QueryMoveFocusEvent = EventManager.RegisterRoutedEvent("QueryMoveFocus", 75 | RoutingStrategy.Bubble, 76 | typeof(QueryMoveFocusEventHandler), 77 | typeof(AutoSelectTextBox)); 78 | #endregion QueryMoveFocus EVENT 79 | 80 | protected override void OnPreviewKeyDown(KeyEventArgs e) 81 | { 82 | if (!this.AutoMoveFocus) 83 | { 84 | base.OnPreviewKeyDown(e); 85 | return; 86 | } 87 | 88 | if ((e.Key == Key.Left) 89 | && ((Keyboard.Modifiers == ModifierKeys.None) 90 | || (Keyboard.Modifiers == ModifierKeys.Control))) 91 | { 92 | e.Handled = this.MoveFocusLeft(); 93 | } 94 | 95 | if ((e.Key == Key.Right) 96 | && ((Keyboard.Modifiers == ModifierKeys.None) 97 | || (Keyboard.Modifiers == ModifierKeys.Control))) 98 | { 99 | e.Handled = this.MoveFocusRight(); 100 | } 101 | 102 | if (((e.Key == Key.Up) || (e.Key == Key.PageUp)) 103 | && ((Keyboard.Modifiers == ModifierKeys.None) 104 | || (Keyboard.Modifiers == ModifierKeys.Control))) 105 | { 106 | e.Handled = this.MoveFocusUp(); 107 | } 108 | 109 | if (((e.Key == Key.Down) || (e.Key == Key.PageDown)) 110 | && ((Keyboard.Modifiers == ModifierKeys.None) 111 | || (Keyboard.Modifiers == ModifierKeys.Control))) 112 | { 113 | e.Handled = this.MoveFocusDown(); 114 | } 115 | 116 | base.OnPreviewKeyDown(e); 117 | } 118 | 119 | protected override void OnPreviewGotKeyboardFocus(KeyboardFocusChangedEventArgs e) 120 | { 121 | base.OnPreviewGotKeyboardFocus(e); 122 | 123 | if (this.AutoSelectBehavior == AutoSelectBehavior.OnFocus) 124 | { 125 | // If the focus was not in one of our child ( or popup ), we select all the text. 126 | if (!TreeHelper.IsDescendantOf(e.OldFocus as DependencyObject, this)) 127 | { 128 | this.SelectAll(); 129 | } 130 | } 131 | } 132 | 133 | protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) 134 | { 135 | base.OnPreviewMouseLeftButtonDown(e); 136 | 137 | if (this.AutoSelectBehavior == AutoSelectBehavior.Never) 138 | return; 139 | 140 | if (this.IsKeyboardFocusWithin == false) 141 | { 142 | this.Focus(); 143 | e.Handled = true; //prevent from removing the selection 144 | } 145 | } 146 | 147 | protected override void OnTextChanged(TextChangedEventArgs e) 148 | { 149 | base.OnTextChanged(e); 150 | 151 | if (!this.AutoMoveFocus) 152 | return; 153 | 154 | if ((this.Text.Length != 0) 155 | && (this.Text.Length == this.MaxLength) 156 | && (this.CaretIndex == this.MaxLength)) 157 | { 158 | if (this.CanMoveFocus(FocusNavigationDirection.Right, true) == true) 159 | { 160 | FocusNavigationDirection direction = (this.FlowDirection == FlowDirection.LeftToRight) 161 | ? FocusNavigationDirection.Right 162 | : FocusNavigationDirection.Left; 163 | 164 | this.MoveFocus(new TraversalRequest(direction)); 165 | } 166 | } 167 | } 168 | 169 | private bool CanMoveFocus(FocusNavigationDirection direction, bool reachedMax) 170 | { 171 | QueryMoveFocusEventArgs e = new QueryMoveFocusEventArgs(direction, reachedMax); 172 | this.RaiseEvent(e); 173 | return e.CanMoveFocus; 174 | } 175 | 176 | private bool MoveFocusLeft() 177 | { 178 | if (this.FlowDirection == FlowDirection.LeftToRight) 179 | { 180 | //occurs only if the cursor is at the beginning of the text 181 | if ((this.CaretIndex == 0) && (this.SelectionLength == 0)) 182 | { 183 | if (ComponentCommands.MoveFocusBack.CanExecute(null, this)) 184 | { 185 | ComponentCommands.MoveFocusBack.Execute(null, this); 186 | return true; 187 | } 188 | else if (this.CanMoveFocus(FocusNavigationDirection.Left, false)) 189 | { 190 | this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Left)); 191 | return true; 192 | } 193 | } 194 | } 195 | else 196 | { 197 | //occurs only if the cursor is at the end of the text 198 | if ((this.CaretIndex == this.Text.Length) && (this.SelectionLength == 0)) 199 | { 200 | if (ComponentCommands.MoveFocusBack.CanExecute(null, this)) 201 | { 202 | ComponentCommands.MoveFocusBack.Execute(null, this); 203 | return true; 204 | } 205 | else if (this.CanMoveFocus(FocusNavigationDirection.Left, false)) 206 | { 207 | this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Left)); 208 | return true; 209 | } 210 | } 211 | } 212 | 213 | return false; 214 | } 215 | 216 | private bool MoveFocusRight() 217 | { 218 | if (this.FlowDirection == FlowDirection.LeftToRight) 219 | { 220 | //occurs only if the cursor is at the beginning of the text 221 | if ((this.CaretIndex == this.Text.Length) && (this.SelectionLength == 0)) 222 | { 223 | if (ComponentCommands.MoveFocusForward.CanExecute(null, this)) 224 | { 225 | ComponentCommands.MoveFocusForward.Execute(null, this); 226 | return true; 227 | } 228 | else if (this.CanMoveFocus(FocusNavigationDirection.Right, false)) 229 | { 230 | this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Right)); 231 | return true; 232 | } 233 | } 234 | } 235 | else 236 | { 237 | //occurs only if the cursor is at the end of the text 238 | if ((this.CaretIndex == 0) && (this.SelectionLength == 0)) 239 | { 240 | if (ComponentCommands.MoveFocusForward.CanExecute(null, this)) 241 | { 242 | ComponentCommands.MoveFocusForward.Execute(null, this); 243 | return true; 244 | } 245 | else if (this.CanMoveFocus(FocusNavigationDirection.Right, false)) 246 | { 247 | this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Right)); 248 | return true; 249 | } 250 | } 251 | } 252 | 253 | return false; 254 | } 255 | 256 | private bool MoveFocusUp() 257 | { 258 | int lineNumber = this.GetLineIndexFromCharacterIndex(this.SelectionStart); 259 | 260 | //occurs only if the cursor is on the first line 261 | if (lineNumber == 0) 262 | { 263 | if (ComponentCommands.MoveFocusUp.CanExecute(null, this)) 264 | { 265 | ComponentCommands.MoveFocusUp.Execute(null, this); 266 | return true; 267 | } 268 | else if (this.CanMoveFocus(FocusNavigationDirection.Up, false)) 269 | { 270 | this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Up)); 271 | return true; 272 | } 273 | } 274 | 275 | return false; 276 | } 277 | 278 | private bool MoveFocusDown() 279 | { 280 | int lineNumber = this.GetLineIndexFromCharacterIndex(this.SelectionStart); 281 | 282 | //occurs only if the cursor is on the first line 283 | if (lineNumber == (this.LineCount - 1)) 284 | { 285 | if (ComponentCommands.MoveFocusDown.CanExecute(null, this)) 286 | { 287 | ComponentCommands.MoveFocusDown.Execute(null, this); 288 | return true; 289 | } 290 | else if (this.CanMoveFocus(FocusNavigationDirection.Down, false)) 291 | { 292 | this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Down)); 293 | return true; 294 | } 295 | } 296 | 297 | return false; 298 | } 299 | } 300 | } 301 | 302 | -------------------------------------------------------------------------------- /source/Lib/Controls/AutoSelectTextBox/Implementation/AutoSelectBehaviorEnum.cs: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | 3 | Extended WPF Toolkit 4 | 5 | Copyright (C) 2007-2013 Xceed Software Inc. 6 | 7 | This program is provided to you under the terms of the Microsoft Public 8 | License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license 9 | 10 | For more features, controls, and fast professional support, 11 | pick up the Plus Edition at http://xceed.com/wpf_toolkit 12 | 13 | Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids 14 | 15 | ***********************************************************************************/ 16 | 17 | namespace WatermarkControlsLib.Controls.AutoSelectTextBox.Implementation 18 | { 19 | public enum AutoSelectBehavior 20 | { 21 | Never, 22 | OnFocus 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /source/Lib/Controls/AutoSelectTextBox/Implementation/QueryMoveFocusEventArgs.cs: -------------------------------------------------------------------------------- 1 | /************************************************************************************* 2 | 3 | Extended WPF Toolkit 4 | 5 | Copyright (C) 2007-2013 Xceed Software Inc. 6 | 7 | This program is provided to you under the terms of the Microsoft Public 8 | License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license 9 | 10 | For more features, controls, and fast professional support, 11 | pick up the Plus Edition at http://xceed.com/wpf_toolkit 12 | 13 | Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids 14 | 15 | ***********************************************************************************/ 16 | 17 | namespace WatermarkControlsLib.Controls.AutoSelectTextBox.Implementation 18 | { 19 | using System.Windows; 20 | using System.Windows.Input; 21 | 22 | [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1003:UseGenericEventHandlerInstances")] 23 | public delegate void QueryMoveFocusEventHandler(object sender, QueryMoveFocusEventArgs e); 24 | 25 | public class QueryMoveFocusEventArgs : RoutedEventArgs 26 | { 27 | //default CTOR private to prevent its usage. 28 | private QueryMoveFocusEventArgs() 29 | { 30 | } 31 | 32 | //internal to prevent anybody from building this type of event. 33 | internal QueryMoveFocusEventArgs(FocusNavigationDirection direction, bool reachedMaxLength) 34 | : base(AutoSelectTextBox.QueryMoveFocusEvent) 35 | { 36 | m_navigationDirection = direction; 37 | m_reachedMaxLength = reachedMaxLength; 38 | } 39 | 40 | public FocusNavigationDirection FocusNavigationDirection 41 | { 42 | get 43 | { 44 | return m_navigationDirection; 45 | } 46 | } 47 | 48 | public bool ReachedMaxLength 49 | { 50 | get 51 | { 52 | return m_reachedMaxLength; 53 | } 54 | } 55 | 56 | public bool CanMoveFocus 57 | { 58 | get 59 | { 60 | return m_canMove; 61 | } 62 | set 63 | { 64 | m_canMove = value; 65 | } 66 | } 67 | 68 | private FocusNavigationDirection m_navigationDirection; 69 | private bool m_reachedMaxLength; 70 | private bool m_canMove = true; //defaults to true... if nobody does nothing, then its capable of moving focus. 71 | 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /source/Lib/Controls/WatermarkComboBox.xaml: -------------------------------------------------------------------------------- 1 |  16 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 46 | 50 | 54 | 55 | 56 | 61 | 65 | 66 | 70 | 71 | 72 | 73 | 74 | 75 | 81 | 82 | 183 | 184 | 185 | 194 | 198 | 203 | 204 | 225 | 226 | 227 | 228 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 298 | 299 | 300 | 301 | 302 | 303 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 367 | 368 | 369 | 370 | 371 | 119 | 120 |