using System.Collections.Generic; using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Documents; namespace Sicentury.Core.AttachedProperties { /// /// Class that provides the Watermark attached property /// public static class WatermarkService { /// /// Watermark Attached Dependency Property /// public static readonly DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached( "Watermark", typeof(object), typeof(WatermarkService), new FrameworkPropertyMetadata(null, OnWatermarkChanged)); #region Private Fields /// /// Dictionary of ItemsControls /// private static readonly Dictionary ItemsControls = new Dictionary(); #endregion /// /// Gets the Watermark property. This dependency property indicates the watermark for the control. /// /// to get the property from /// The value of the Watermark property public static object GetWatermark(DependencyObject d) { return d.GetValue(WatermarkProperty); } /// /// Sets the Watermark property. This dependency property indicates the watermark for the control. /// /// to set the property on /// value of the property public static void SetWatermark(DependencyObject d, object value) { d.SetValue(WatermarkProperty, value); } /// /// Handles changes to the Watermark property. /// /// that fired the event /// A that contains the event data. private static void OnWatermarkChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var control = (Control)d; control.Loaded += Control_Loaded; if (d is ComboBox) { control.GotKeyboardFocus += Control_GotKeyboardFocus; control.LostKeyboardFocus += Control_Loaded; } else if (d is TextBox) { control.GotKeyboardFocus += Control_GotKeyboardFocus; control.LostKeyboardFocus += Control_Loaded; ((TextBox)control).TextChanged += Control_GotKeyboardFocus; } if (d is ItemsControl o && !(o is ComboBox)) { // for Items property o.ItemContainerGenerator.ItemsChanged += ItemsChanged; ItemsControls.Add(o.ItemContainerGenerator, o); // for ItemsSource property var prop = DependencyPropertyDescriptor.FromProperty(ItemsControl.ItemsSourceProperty, o.GetType()); prop.AddValueChanged(o, ItemsSourceChanged); } } #region Event Handlers /// /// Handle the GotFocus event on the control /// /// The source of the event. /// A that contains the event data. private static void Control_GotKeyboardFocus(object sender, RoutedEventArgs e) { var c = (Control)sender; if (ShouldShowWatermark(c)) { ShowWatermark(c); } else { RemoveWatermark(c); } } /// /// Handle the Loaded and LostFocus event on the control /// /// The source of the event. /// A that contains the event data. private static void Control_Loaded(object sender, RoutedEventArgs e) { var control = (Control)sender; if (ShouldShowWatermark(control)) { ShowWatermark(control); } } /// /// Event handler for the items source changed event /// /// The source of the event. /// A that contains the event data. private static void ItemsSourceChanged(object sender, System.EventArgs e) { var c = (ItemsControl)sender; if (c.ItemsSource != null) { if (ShouldShowWatermark(c)) { ShowWatermark(c); } else { RemoveWatermark(c); } } else { ShowWatermark(c); } } /// /// Event handler for the items changed event /// /// The source of the event. /// A that contains the event data. private static void ItemsChanged(object sender, ItemsChangedEventArgs e) { ItemsControl control; if (ItemsControls.TryGetValue(sender, out control)) { if (ShouldShowWatermark(control)) { ShowWatermark(control); } else { RemoveWatermark(control); } } } #endregion #region Helper Methods /// /// Remove the watermark from the specified element /// /// Element to remove the watermark from private static void RemoveWatermark(UIElement control) { var layer = AdornerLayer.GetAdornerLayer(control); // layer could be null if control is no longer in the visual tree if (layer != null) { var adorners = layer.GetAdorners(control); if (adorners == null) { return; } foreach (var adorner in adorners) { if (adorner is WatermarkAdorner) { adorner.Visibility = Visibility.Hidden; layer.Remove(adorner); } } } } /// /// Show the watermark on the specified control /// /// Control to show the watermark on private static void ShowWatermark(Control control) { var layer = AdornerLayer.GetAdornerLayer(control); // layer could be null if control is no longer in the visual tree layer?.Add(new WatermarkAdorner(control, GetWatermark(control))); } /// /// Indicates whether or not the watermark should be shown on the specified control /// /// to test /// true if the watermark should be shown; false otherwise private static bool ShouldShowWatermark(Control c) { switch (c) { case ComboBox box: return box.Text == string.Empty; case TextBoxBase _: return (c as TextBox)?.Text == string.Empty; case ItemsControl control: return control.Items.Count == 0; default: return false; } } #endregion } }