├── .gitignore ├── AnimatedTextBoxBehavior.Example ├── AnimatedTextBoxBehavior.Example.csproj ├── App.config ├── App.xaml ├── App.xaml.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings ├── blink.gif ├── packages.config └── typing.gif ├── AnimatedTextBoxBehavior.sln ├── AnimatedTextBoxBehavior ├── AnimatedTextBoxBehavior.cs ├── AnimatedTextBoxBehavior.csproj ├── CaretAdorner.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings └── packages.config ├── License.md └── Readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | *.suo 4 | *.ide 5 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior.Example/AnimatedTextBoxBehavior.Example.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {95B7E44F-F81C-4C96-B48E-7590B54F5334} 8 | WinExe 9 | Properties 10 | AnimatedTextBoxBehavior.Example 11 | AnimatedTextBoxBehavior.Example 12 | v4.5 13 | 512 14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 4 16 | 17 | 18 | AnyCPU 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | ..\packages\System.Windows.Interactivity.WPF.2.0.20525\lib\net40\Microsoft.Expression.Interactions.dll 39 | 40 | 41 | 42 | 43 | ..\packages\System.Windows.Interactivity.WPF.2.0.20525\lib\net40\System.Windows.Interactivity.dll 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 4.0 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | MSBuild:Compile 60 | Designer 61 | 62 | 63 | MSBuild:Compile 64 | Designer 65 | 66 | 67 | App.xaml 68 | Code 69 | 70 | 71 | MainWindow.xaml 72 | Code 73 | 74 | 75 | 76 | 77 | Code 78 | 79 | 80 | True 81 | True 82 | Resources.resx 83 | 84 | 85 | True 86 | Settings.settings 87 | True 88 | 89 | 90 | ResXFileCodeGenerator 91 | Resources.Designer.cs 92 | 93 | 94 | 95 | SettingsSingleFileGenerator 96 | Settings.Designer.cs 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | {d0fa27e1-335b-431f-b8f6-55674a700592} 106 | AnimatedTextBoxBehavior 107 | 108 | 109 | 110 | 117 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior.Example/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior.Example/App.xaml: -------------------------------------------------------------------------------- 1 |  6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior.Example/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | 9 | namespace AnimatedTextBoxBehavior.Example 10 | { 11 | /// 12 | /// Interaction logic for App.xaml 13 | /// 14 | public partial class App : Application 15 | { 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior.Example/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior.Example/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.Windows; 7 | using System.Windows.Controls; 8 | using System.Windows.Data; 9 | using System.Windows.Documents; 10 | using System.Windows.Input; 11 | using System.Windows.Interactivity; 12 | using System.Windows.Media; 13 | using System.Windows.Media.Imaging; 14 | using System.Windows.Navigation; 15 | using System.Windows.Shapes; 16 | 17 | namespace AnimatedTextBoxBehavior.Example 18 | { 19 | /// 20 | /// Interaction logic for MainWindow.xaml 21 | /// 22 | public partial class MainWindow : Window 23 | { 24 | public MainWindow () 25 | { 26 | InitializeComponent (); 27 | } 28 | 29 | private void OnToggleAnimations (object sender, RoutedEventArgs e) 30 | { 31 | BehaviorCollection behaviors = Interaction.GetBehaviors (this.text); 32 | if (behaviors.Count > 0) 33 | behaviors.RemoveAt (0); 34 | else 35 | behaviors.Add (new ermau.AnimatedTextBoxBehavior()); 36 | } 37 | 38 | private void OnToggleColor (object sender, RoutedEventArgs e) 39 | { 40 | this.text.CaretBrush = (this.text.CaretBrush == Brushes.Red) ? Brushes.Blue : Brushes.Red; 41 | } 42 | 43 | private void OnToggleVisibility (object sender, RoutedEventArgs e) 44 | { 45 | this.text.Focus(); 46 | this.text.Visibility = (this.text.Visibility == Visibility.Visible) ? Visibility.Collapsed : Visibility.Visible; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior.Example/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("AnimatedTextBoxBehavior.Example")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("AnimatedTextBoxBehavior.Example")] 15 | [assembly: AssemblyCopyright("Copyright © Xamarin Inc. 2014-2015")] 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 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior.Example/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.0 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 AnimatedTextBoxBehavior.Example.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 ("AnimatedTextBoxBehavior.Example.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 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior.Example/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 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior.Example/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.0 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 AnimatedTextBoxBehavior.Example.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 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior.Example/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior.Example/blink.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ermau/AnimatedTextBoxBehavior/feb94666a73ff0ee345348095842b89db507a6b6/AnimatedTextBoxBehavior.Example/blink.gif -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior.Example/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior.Example/typing.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ermau/AnimatedTextBoxBehavior/feb94666a73ff0ee345348095842b89db507a6b6/AnimatedTextBoxBehavior.Example/typing.gif -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.22310.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E2349EDD-41BB-4308-9AED-1A5A0CFA1575}" 7 | ProjectSection(SolutionItems) = preProject 8 | License.md = License.md 9 | Readme.md = Readme.md 10 | EndProjectSection 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnimatedTextBoxBehavior", "AnimatedTextBoxBehavior\AnimatedTextBoxBehavior.csproj", "{D0FA27E1-335B-431F-B8F6-55674A700592}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AnimatedTextBoxBehavior.Example", "AnimatedTextBoxBehavior.Example\AnimatedTextBoxBehavior.Example.csproj", "{95B7E44F-F81C-4C96-B48E-7590B54F5334}" 15 | EndProject 16 | Global 17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 18 | Debug|Any CPU = Debug|Any CPU 19 | Release|Any CPU = Release|Any CPU 20 | EndGlobalSection 21 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 22 | {D0FA27E1-335B-431F-B8F6-55674A700592}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {D0FA27E1-335B-431F-B8F6-55674A700592}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {D0FA27E1-335B-431F-B8F6-55674A700592}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {D0FA27E1-335B-431F-B8F6-55674A700592}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {95B7E44F-F81C-4C96-B48E-7590B54F5334}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {95B7E44F-F81C-4C96-B48E-7590B54F5334}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {95B7E44F-F81C-4C96-B48E-7590B54F5334}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {95B7E44F-F81C-4C96-B48E-7590B54F5334}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | EndGlobal 35 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior/AnimatedTextBoxBehavior.cs: -------------------------------------------------------------------------------- 1 | // 2 | // AnimatedTextBoxBehavior.cs 3 | // 4 | // Author: 5 | // Eric Maupin 6 | // 7 | // Copyright (c) 2014-2015 Xamarin Inc. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.ComponentModel; 29 | using System.Windows; 30 | using System.Windows.Controls; 31 | using System.Windows.Controls.Primitives; 32 | using System.Windows.Data; 33 | using System.Windows.Documents; 34 | using System.Windows.Interactivity; 35 | using System.Windows.Media; 36 | 37 | namespace ermau 38 | { 39 | public sealed class AnimatedTextBoxBehavior 40 | : Behavior 41 | { 42 | protected override void OnAttached() 43 | { 44 | if (!AssociatedObject.IsLoaded) { 45 | AssociatedObject.Loaded += OnAssociatedObjectLoaded; 46 | } else 47 | SetupAdorner(); 48 | } 49 | 50 | protected override void OnDetaching() 51 | { 52 | var descriptor = DependencyPropertyDescriptor.FromProperty (TextBoxBase.CaretBrushProperty, typeof (TextBox)); 53 | descriptor.RemoveValueChanged (AssociatedObject, OnCaretBrushChanged); 54 | 55 | AssociatedObject.CaretBrush = this.originalCaretBrush; 56 | this.layer.Remove (this.caretAdorner); 57 | this.caretAdorner.Dispose(); 58 | this.caretAdorner = null; 59 | } 60 | 61 | private Brush originalCaretBrush; 62 | private AdornerLayer layer; 63 | private CaretAdorner caretAdorner; 64 | 65 | private void OnCaretBrushChanged (object sender, EventArgs eventArgs) 66 | { 67 | Brush brush = AssociatedObject.CaretBrush; 68 | this.caretAdorner.CaretBrush = brush; 69 | this.originalCaretBrush = brush; 70 | } 71 | 72 | private void OnAssociatedObjectLoaded (object sender, RoutedEventArgs e) 73 | { 74 | SetupAdorner(); 75 | AssociatedObject.Loaded -= OnAssociatedObjectLoaded; 76 | } 77 | 78 | private void SetupAdorner() 79 | { 80 | this.originalCaretBrush = AssociatedObject.CaretBrush; 81 | AssociatedObject.CaretBrush = Brushes.Transparent; 82 | 83 | var descriptor = DependencyPropertyDescriptor.FromProperty (TextBoxBase.CaretBrushProperty, typeof (TextBox)); 84 | descriptor.AddValueChanged (AssociatedObject, OnCaretBrushChanged); 85 | 86 | this.layer = AdornerLayer.GetAdornerLayer (AssociatedObject); 87 | 88 | this.caretAdorner = new CaretAdorner (AssociatedObject) { 89 | CaretBrush = this.originalCaretBrush, 90 | DataContext = AssociatedObject 91 | }; 92 | this.caretAdorner.SetBinding (UIElement.VisibilityProperty, new Binding (nameof (TextBox.Visibility))); 93 | this.layer.Add (this.caretAdorner); 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior/AnimatedTextBoxBehavior.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {D0FA27E1-335B-431F-B8F6-55674A700592} 8 | library 9 | Properties 10 | AnimatedTextBoxBehavior 11 | AnimatedTextBoxBehavior 12 | v4.5 13 | 512 14 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 15 | 4 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\System.Windows.Interactivity.WPF.2.0.20525\lib\net40\Microsoft.Expression.Interactions.dll 37 | 38 | 39 | 40 | 41 | 42 | ..\packages\System.Windows.Interactivity.WPF.2.0.20525\lib\net40\System.Windows.Interactivity.dll 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 4.0 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | Code 61 | 62 | 63 | True 64 | True 65 | Resources.resx 66 | 67 | 68 | True 69 | Settings.settings 70 | True 71 | 72 | 73 | ResXFileCodeGenerator 74 | Resources.Designer.cs 75 | 76 | 77 | 78 | SettingsSingleFileGenerator 79 | Settings.Designer.cs 80 | 81 | 82 | 83 | 84 | 91 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior/CaretAdorner.cs: -------------------------------------------------------------------------------- 1 | // 2 | // CaretAdorner.cs 3 | // 4 | // Author: 5 | // Eric Maupin 6 | // 7 | // Copyright (c) 2014-2015 Xamarin Inc. 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | 27 | using System; 28 | using System.Threading; 29 | using System.Threading.Tasks; 30 | using System.Windows; 31 | using System.Windows.Documents; 32 | using System.Windows.Forms; 33 | using System.Windows.Input; 34 | using System.Windows.Media; 35 | using System.Windows.Media.Animation; 36 | using System.Windows.Shapes; 37 | using TextBox = System.Windows.Controls.TextBox; 38 | 39 | namespace ermau 40 | { 41 | internal sealed class CaretAdorner 42 | : Adorner, IDisposable 43 | { 44 | public CaretAdorner (TextBox adornedElement) 45 | : base (adornedElement) 46 | { 47 | var fontRect = adornedElement.GetRectFromCharacterIndex (0); 48 | this.caret = new Rectangle { 49 | Width = 1, 50 | Height = fontRect.Height, 51 | Fill = Brushes.Black, 52 | RenderTransform = new TranslateTransform (fontRect.Left, fontRect.Top), 53 | Opacity = 0, 54 | SnapsToDevicePixels = true 55 | }; 56 | 57 | adornedElement.SizeChanged += OnSizeChanged; 58 | adornedElement.SelectionChanged += OnSelectionChanged; 59 | adornedElement.PreviewMouseDown += OnPreviewMouseDown; 60 | adornedElement.GotKeyboardFocus += OnGotFocus; 61 | adornedElement.LostKeyboardFocus += OnLostFocus; 62 | 63 | this.children = new VisualCollection (this); 64 | this.children.Add (this.caret); 65 | 66 | double transitionTime = SystemInformation.CaretBlinkTime; 67 | TimeSpan fadeTime = TimeSpan.FromMilliseconds (transitionTime * (1d / 3d)); 68 | TimeSpan holdTime = TimeSpan.FromMilliseconds (transitionTime * (2d / 3d)); 69 | 70 | var storyboard = new Storyboard { RepeatBehavior = RepeatBehavior.Forever }; 71 | 72 | var fade = new DoubleAnimationUsingKeyFrames { 73 | KeyFrames = { 74 | new EasingDoubleKeyFrame (0, KeyTime.FromTimeSpan (fadeTime)), 75 | new DiscreteDoubleKeyFrame (0, KeyTime.FromTimeSpan (fadeTime + holdTime)), 76 | new EasingDoubleKeyFrame (1, KeyTime.FromTimeSpan (fadeTime + holdTime + fadeTime)), 77 | new DiscreteDoubleKeyFrame (1, KeyTime.FromTimeSpan (fadeTime + holdTime + fadeTime + holdTime)) 78 | }, 79 | 80 | Duration = new Duration (TimeSpan.FromMilliseconds (transitionTime * 2)) 81 | }; 82 | Storyboard.SetTargetProperty (fade, new PropertyPath ("Opacity")); 83 | fade.Freeze(); 84 | 85 | storyboard.Children.Add (fade); 86 | this.blinkStoryboard = storyboard; 87 | } 88 | 89 | public Brush CaretBrush 90 | { 91 | get { return this.caret.Fill; } 92 | set 93 | { 94 | if (value == null) 95 | value = Brushes.Black; 96 | 97 | this.caret.Fill = value; 98 | } 99 | } 100 | 101 | public void Dispose() 102 | { 103 | if (TextBox == null) 104 | return; 105 | 106 | TextBox.SelectionChanged -= OnSelectionChanged; 107 | TextBox.PreviewMouseDown -= OnPreviewMouseDown; 108 | TextBox.GotKeyboardFocus -= OnGotFocus; 109 | TextBox.LostKeyboardFocus -= OnLostFocus; 110 | TextBox.SizeChanged -= OnSizeChanged; 111 | } 112 | 113 | protected override int VisualChildrenCount 114 | { 115 | get { return this.children.Count; } 116 | } 117 | 118 | protected override Visual GetVisualChild (int index) 119 | { 120 | return this.children[index]; 121 | } 122 | 123 | protected override Size ArrangeOverride (Size finalSize) 124 | { 125 | this.caret.Arrange (new Rect (0, 0, finalSize.Width, finalSize.Height)); 126 | return this.caret.RenderSize; 127 | } 128 | 129 | protected override Size MeasureOverride (Size constraint) 130 | { 131 | this.caret.Measure (constraint); 132 | return this.caret.DesiredSize; 133 | } 134 | 135 | private Storyboard blinkStoryboard; 136 | private bool mouseInput; 137 | private CancellationTokenSource cancelSource; 138 | private readonly Rectangle caret; 139 | private readonly VisualCollection children; 140 | private readonly Duration shiftDuration = new Duration (TimeSpan.FromMilliseconds (50)); 141 | 142 | private TextBox TextBox 143 | { 144 | get { return (TextBox) AdornedElement; } 145 | } 146 | 147 | private async void UpdateCaretPosition (Size? oldSize = null) 148 | { 149 | if (this.cancelSource != null) 150 | this.cancelSource.Cancel(); 151 | 152 | this.cancelSource = new CancellationTokenSource(); 153 | 154 | bool fromMouse = this.mouseInput; 155 | this.mouseInput = false; 156 | 157 | bool visible = (TextBox.SelectedText == String.Empty); 158 | this.caret.Visibility = (visible) ? Visibility.Visible : Visibility.Collapsed; 159 | 160 | Rect position = TextBox.GetRectFromCharacterIndex (TextBox.CaretIndex); 161 | double left = Math.Round (position.Left); 162 | double top = Math.Round (position.Top); 163 | 164 | if (oldSize != null) { 165 | if (oldSize.Value.Height > TextBox.ActualHeight) 166 | left -= (oldSize.Value.Height - TextBox.ActualHeight); 167 | if (oldSize.Value.Width > TextBox.ActualWidth) 168 | top -= (oldSize.Value.Width - TextBox.ActualWidth); 169 | } 170 | 171 | this.blinkStoryboard.Stop (this.caret); 172 | this.caret.Opacity = 1; 173 | 174 | if (fromMouse || !visible) 175 | this.caret.RenderTransform = new TranslateTransform (left, top); 176 | else { 177 | if (left != ((TranslateTransform) this.caret.RenderTransform).X) 178 | this.caret.RenderTransform.BeginAnimation (TranslateTransform.XProperty, new DoubleAnimation (left, this.shiftDuration), HandoffBehavior.Compose); 179 | if (top != ((TranslateTransform) this.caret.RenderTransform).Y) 180 | this.caret.RenderTransform.BeginAnimation (TranslateTransform.YProperty, new DoubleAnimation (top, this.shiftDuration), HandoffBehavior.Compose); 181 | } 182 | 183 | if (visible) { 184 | try { 185 | await Task.Delay (SystemInformation.CaretBlinkTime, this.cancelSource.Token); 186 | this.blinkStoryboard.Begin (this.caret, isControllable: true); 187 | this.cancelSource = null; 188 | } catch (OperationCanceledException) { 189 | } 190 | } 191 | } 192 | 193 | private void OnLostFocus (object sender, RoutedEventArgs routedEventArgs) 194 | { 195 | this.blinkStoryboard.Stop (this.caret); 196 | this.caret.Opacity = 0; 197 | } 198 | 199 | private void OnGotFocus (object sender, RoutedEventArgs routedEventArgs) 200 | { 201 | this.caret.Opacity = 1; 202 | this.blinkStoryboard.Begin (this.caret, isControllable: true); 203 | } 204 | 205 | private void OnPreviewMouseDown (object sender, MouseButtonEventArgs e) 206 | { 207 | if (e.ChangedButton != MouseButton.Left && e.ChangedButton != MouseButton.Right) 208 | return; 209 | 210 | this.mouseInput = true; 211 | } 212 | 213 | private void OnSelectionChanged (object sender, RoutedEventArgs e) 214 | { 215 | UpdateCaretPosition(); 216 | } 217 | 218 | private void OnSizeChanged (object sender, SizeChangedEventArgs e) 219 | { 220 | UpdateCaretPosition (e.PreviousSize); 221 | } 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior/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("AnimatedTextBoxBehavior")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("")] 14 | [assembly: AssemblyProduct("AnimatedTextBoxBehavior")] 15 | [assembly: AssemblyCopyright("Copyright © Xamarin Inc. 2014-2015")] 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 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.0 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 AnimatedTextBoxBehavior.Properties { 12 | 13 | 14 | /// 15 | /// A strongly-typed resource class, for looking up localized strings, etc. 16 | /// 17 | // This class was auto-generated by the StronglyTypedResourceBuilder 18 | // class via a tool like ResGen or Visual Studio. 19 | // To add or remove a member, edit your .ResX file then rerun ResGen 20 | // with the /str option, or rebuild your VS project. 21 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 22 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 23 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 24 | internal class Resources { 25 | 26 | private static global::System.Resources.ResourceManager resourceMan; 27 | 28 | private static global::System.Globalization.CultureInfo resourceCulture; 29 | 30 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 31 | internal Resources() { 32 | } 33 | 34 | /// 35 | /// Returns the cached ResourceManager instance used by this class. 36 | /// 37 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 38 | internal static global::System.Resources.ResourceManager ResourceManager { 39 | get { 40 | if ((resourceMan == null)) { 41 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("AnimatedTextBoxBehavior.Properties.Resources", typeof(Resources).Assembly); 42 | resourceMan = temp; 43 | } 44 | return resourceMan; 45 | } 46 | } 47 | 48 | /// 49 | /// Overrides the current thread's CurrentUICulture property for all 50 | /// resource lookups using this strongly typed resource class. 51 | /// 52 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 53 | internal static global::System.Globalization.CultureInfo Culture { 54 | get { 55 | return resourceCulture; 56 | } 57 | set { 58 | resourceCulture = value; 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior/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 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.0 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 AnimatedTextBoxBehavior.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 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /AnimatedTextBoxBehavior/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /License.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014-2015 Xamarin, Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | Overview 2 | ======== 3 | 4 | `AnimatedTextBoxBehavior` is a WPF behavior for `TextBox` that animates caret-based operations. 5 | These animations are meant to simply provide a nicer experience, without getting in the way or slowing you down. 6 | 7 | Features 8 | ======== 9 | 10 | - Caret blink is a fade 11 | 12 | ![Blink](AnimatedTextBoxBehavior.Example/blink.gif) 13 | 14 | - Animated keyboard-based caret movement (typing, arrow keys, home/end). 15 | 16 | ![Typing](AnimatedTextBoxBehavior.Example/typing.gif) 17 | 18 | Usage 19 | ======== 20 | 21 | As `AnimatedTextBoxBehavior` exists purely as a behavior, the usage is quite straightforward: 22 | 23 | ```xaml 24 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ``` --------------------------------------------------------------------------------