123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Controls.Primitives;
- using System.Windows.Documents;
- namespace MECF.Framework.UI.Client.ClientBase.AttachedProperties
- {
- /// <summary>
- /// Class that provides the Watermark attached property
- /// </summary>
- public static class WatermarkService
- {
- /// <summary>
- /// Watermark Attached Dependency Property
- /// </summary>
- public static readonly DependencyProperty WatermarkProperty = DependencyProperty.RegisterAttached(
- "Watermark",
- typeof(object),
- typeof(WatermarkService),
- new FrameworkPropertyMetadata(null, OnWatermarkChanged));
- #region Private Fields
- /// <summary>
- /// Dictionary of ItemsControls
- /// </summary>
- private static readonly Dictionary<object, ItemsControl> ItemsControls
- = new Dictionary<object, ItemsControl>();
- #endregion
- /// <summary>
- /// Gets the Watermark property. This dependency property indicates the watermark for the control.
- /// </summary>
- /// <param name="d"><see cref="DependencyObject"/> to get the property from</param>
- /// <returns>The value of the Watermark property</returns>
- public static object GetWatermark(DependencyObject d)
- {
- return d.GetValue(WatermarkProperty);
- }
- /// <summary>
- /// Sets the Watermark property. This dependency property indicates the watermark for the control.
- /// </summary>
- /// <param name="d"><see cref="DependencyObject"/> to set the property on</param>
- /// <param name="value">value of the property</param>
- public static void SetWatermark(DependencyObject d, object value)
- {
- d.SetValue(WatermarkProperty, value);
- }
- /// <summary>
- /// Handles changes to the Watermark property.
- /// </summary>
- /// <param name="d"><see cref="DependencyObject"/> that fired the event</param>
- /// <param name="e">A <see cref="DependencyPropertyChangedEventArgs"/> that contains the event data.</param>
- 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
- /// <summary>
- /// Handle the GotFocus event on the control
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">A <see cref="RoutedEventArgs"/> that contains the event data.</param>
- private static void Control_GotKeyboardFocus(object sender, RoutedEventArgs e)
- {
- var c = (Control)sender;
- if (ShouldShowWatermark(c))
- {
- ShowWatermark(c);
- }
- else
- {
- RemoveWatermark(c);
- }
- }
- /// <summary>
- /// Handle the Loaded and LostFocus event on the control
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">A <see cref="RoutedEventArgs"/> that contains the event data.</param>
- private static void Control_Loaded(object sender, RoutedEventArgs e)
- {
- var control = (Control)sender;
- if (ShouldShowWatermark(control))
- {
- ShowWatermark(control);
- }
- }
- /// <summary>
- /// Event handler for the items source changed event
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">A <see cref="EventArgs"/> that contains the event data.</param>
- 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);
- }
- }
- /// <summary>
- /// Event handler for the items changed event
- /// </summary>
- /// <param name="sender">The source of the event.</param>
- /// <param name="e">A <see cref="ItemsChangedEventArgs"/> that contains the event data.</param>
- 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
- /// <summary>
- /// Remove the watermark from the specified element
- /// </summary>
- /// <param name="control">Element to remove the watermark from</param>
- 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);
- }
- }
- }
- }
- /// <summary>
- /// Show the watermark on the specified control
- /// </summary>
- /// <param name="control">Control to show the watermark on</param>
- 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)));
- }
- /// <summary>
- /// Indicates whether or not the watermark should be shown on the specified control
- /// </summary>
- /// <param name="c"><see cref="Control"/> to test</param>
- /// <returns>true if the watermark should be shown; false otherwise</returns>
- 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
- }
- }
|