using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Media; namespace AIK.Behaviors { public static class PlaceholderBehavior { #region 依赖属性定义 private static readonly DependencyPropertyKey IsPlaceholderActivePropertyKey = DependencyProperty.RegisterAttachedReadOnly( "IsPlaceholderActive", typeof(bool), typeof(PlaceholderBehavior), new PropertyMetadata(false)); public static readonly DependencyProperty IsPlaceholderActiveProperty = IsPlaceholderActivePropertyKey.DependencyProperty; public static readonly DependencyProperty PlaceholderTextProperty = DependencyProperty.RegisterAttached( "PlaceholderText", typeof(string), typeof(PlaceholderBehavior), new PropertyMetadata(string.Empty, OnPlaceholderTextChanged)); // 添加一个属性来存储原始绑定 private static readonly DependencyProperty OriginalBindingProperty = DependencyProperty.RegisterAttached( "OriginalBinding", typeof(Binding), typeof(PlaceholderBehavior)); // 添加一个属性来标记是否正在设置Placeholder private static readonly DependencyProperty IsSettingPlaceholderProperty = DependencyProperty.RegisterAttached( "IsSettingPlaceholder", typeof(bool), typeof(PlaceholderBehavior), new PropertyMetadata(false)); #endregion #region 公共方法 public static bool GetIsPlaceholderActive(DependencyObject obj) { return (bool)obj.GetValue(IsPlaceholderActiveProperty); } public static string GetPlaceholderText(DependencyObject obj) { return (string)obj.GetValue(PlaceholderTextProperty); } public static void SetPlaceholderText(DependencyObject obj, string value) { obj.SetValue(PlaceholderTextProperty, value); } #endregion #region 私有方法 private static bool GetIsSettingPlaceholder(DependencyObject obj) { return (bool)obj.GetValue(IsSettingPlaceholderProperty); } private static void SetIsSettingPlaceholder(DependencyObject obj, bool value) { obj.SetValue(IsSettingPlaceholderProperty, value); } private static Binding GetOriginalBinding(DependencyObject obj) { return (Binding)obj.GetValue(OriginalBindingProperty); } private static void SetOriginalBinding(DependencyObject obj, Binding value) { obj.SetValue(OriginalBindingProperty, value); } #endregion #region 事件处理 private static void OnPlaceholderTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is TextBox textBox) { // 确保只注册一次事件 textBox.Loaded -= OnTextBoxLoaded; textBox.GotFocus -= OnTextBoxGotFocus; textBox.LostFocus -= OnTextBoxLostFocus; textBox.TextChanged -= OnTextBoxTextChanged; textBox.Loaded += OnTextBoxLoaded; textBox.GotFocus += OnTextBoxGotFocus; textBox.LostFocus += OnTextBoxLostFocus; textBox.TextChanged += OnTextBoxTextChanged; // 保存原始绑定 var binding = BindingOperations.GetBinding(textBox, TextBox.TextProperty); if (binding != null) { SetOriginalBinding(textBox, binding); } // 如果已经加载,立即初始化 if (textBox.IsLoaded) { InitializePlaceholder(textBox); } } } private static void OnTextBoxLoaded(object sender, RoutedEventArgs e) { InitializePlaceholder((TextBox)sender); } private static void OnTextBoxGotFocus(object sender, RoutedEventArgs e) { var textBox = (TextBox)sender; if (GetIsPlaceholderActive(textBox)) { // 标记开始设置Placeholder,避免触发数据源更新 SetIsSettingPlaceholder(textBox, true); // 移除placeholder textBox.Text = string.Empty; textBox.SetValue(IsPlaceholderActivePropertyKey, false); textBox.Foreground = Brushes.Black; // 恢复数据绑定 RestoreBinding(textBox); SetIsSettingPlaceholder(textBox, false); } } private static void OnTextBoxLostFocus(object sender, RoutedEventArgs e) { var textBox = (TextBox)sender; if (string.IsNullOrEmpty(textBox.Text)) { ShowPlaceholder(textBox); } } private static void OnTextBoxTextChanged(object sender, TextChangedEventArgs e) { var textBox = (TextBox)sender; // 如果正在设置Placeholder,不处理TextChanged事件 if (GetIsSettingPlaceholder(textBox)) return; // 只有在不是placeholder状态时才处理 if (!GetIsPlaceholderActive(textBox)) { // 如果文本变为空,显示placeholder if (string.IsNullOrEmpty(textBox.Text) && !textBox.IsFocused) { ShowPlaceholder(textBox); } else { // 正常文本变化,确保数据绑定是激活的 EnsureBindingActive(textBox); } } } #endregion #region 核心方法 private static void InitializePlaceholder(TextBox textBox) { // 检查当前文本是否为空或者就是Placeholder文本 var currentText = textBox.Text; var placeholderText = GetPlaceholderText(textBox); if (string.IsNullOrEmpty(currentText) || currentText == placeholderText) { ShowPlaceholder(textBox); } } private static void ShowPlaceholder(TextBox textBox) { var placeholderText = GetPlaceholderText(textBox); if (!string.IsNullOrEmpty(placeholderText)) { // 标记开始设置Placeholder SetIsSettingPlaceholder(textBox, true); // 临时解除数据绑定,避免触发数据源更新 SuspendBinding(textBox); // 设置Placeholder文本 textBox.Text = placeholderText; textBox.SetValue(IsPlaceholderActivePropertyKey, true); textBox.Foreground = new SolidColorBrush(Color.FromArgb(0xFF, 0xA0, 0xAE, 0xC0)); SetIsSettingPlaceholder(textBox, false); } } // 临时解除数据绑定 private static void SuspendBinding(TextBox textBox) { // 清除绑定,但保留绑定表达式 var bindingExpression = textBox.GetBindingExpression(TextBox.TextProperty); if (bindingExpression != null) { // 保存原始绑定(如果还没有保存的话) if (GetOriginalBinding(textBox) == null) { var binding = BindingOperations.GetBinding(textBox, TextBox.TextProperty); SetOriginalBinding(textBox, binding); } // 清除绑定,这样设置文本就不会更新数据源 BindingOperations.ClearBinding(textBox, TextBox.TextProperty); } } // 恢复数据绑定 private static void RestoreBinding(TextBox textBox) { var originalBinding = GetOriginalBinding(textBox); if (originalBinding != null) { // 恢复原始绑定 textBox.SetBinding(TextBox.TextProperty, originalBinding); // 立即更新数据源为空值 var bindingExpression = textBox.GetBindingExpression(TextBox.TextProperty); bindingExpression?.UpdateSource(); } } // 确保数据绑定是激活的 private static void EnsureBindingActive(TextBox textBox) { var currentBinding = BindingOperations.GetBinding(textBox, TextBox.TextProperty); var originalBinding = GetOriginalBinding(textBox); // 如果没有当前绑定但有原始绑定,恢复绑定 if (currentBinding == null && originalBinding != null) { textBox.SetBinding(TextBox.TextProperty, originalBinding); } } #endregion } }