קוד עבור WPF PlaceHolder TextBox
-
מטרת הקוד הזה היא ליצור רכיב מותאם אישית של תיבת טקסט (TextBox) ב-WPF, עם תמיכה בטקסט PlaceHolder, כלומר טקסט שמופיע בתוך תיבת הטקסט כשהיא ריקה ולא ממוקדת (כלומר, המשתמש לא בחר בה עדיין). כאשר המשתמש לוחץ על תיבת הטקסט ומתחיל להקליד, PlaceHolder נעלם, וכשהתיבה ריקה והפוקוס יוצא ממנה, PlaceHolder חוזר.
בפועל, הקוד משתמש במנגנון שנקרא Adorner כדי להציג את טקסט PlaceHolder כטקסט חיצוני מעל תיבת הטקסט, מבלי להשפיע על התוכן האמיתי שבתיבת הטקסט.using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; namespace AdvancedControls { public class PlaceHolderTextBox : TextBox { private AdornerLayer _adornerLayer; private PlaceholderAdorner _placeholderAdorner; #region PlaceHolder Property public static readonly DependencyProperty PlaceholderTextProperty = DependencyProperty.Register( "PlaceholderText", typeof(string), typeof(PlaceHolderTextBox), new PropertyMetadata(string.Empty, OnPlaceholderTextChanged)); public string PlaceholderText { get => (string)GetValue(PlaceholderTextProperty); set => SetValue(PlaceholderTextProperty, value); } private static void OnPlaceholderTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var textBox = d as PlaceHolderTextBox; textBox?.UpdatePlaceholderVisibility(); } #endregion public PlaceHolderTextBox() { Loaded += (s, e) => InitializePlaceholder(); TextChanged += (s, e) => UpdatePlaceholderVisibility(); GotFocus += (s, e) => UpdatePlaceholderVisibility(); LostFocus += (s, e) => UpdatePlaceholderVisibility(); } private void InitializePlaceholder() { _adornerLayer = AdornerLayer.GetAdornerLayer(this); UpdatePlaceholderVisibility(); } private void UpdatePlaceholderVisibility() { if (_adornerLayer == null) return; // Remove existing adorner if any var adorners = _adornerLayer.GetAdorners(this); if (adorners != null) { foreach (var adorner in adorners) { if (adorner is PlaceholderAdorner) { _adornerLayer.Remove(adorner); } } } // Add the adorner only if the TextBox is empty and not focused if (string.IsNullOrEmpty(this.Text) && !this.IsFocused) { _placeholderAdorner = new PlaceholderAdorner(this, PlaceholderText, this.FontSize); _adornerLayer.Add(_placeholderAdorner); } } } public class PlaceholderAdorner : Adorner { private readonly TextBlock _placeholderTextBlock; public PlaceholderAdorner(UIElement adornedElement, string placeholderText, double fontSize) : base(adornedElement) { _placeholderTextBlock = new TextBlock { Text = placeholderText, Foreground = Brushes.Gray, IsHitTestVisible = false, // Allow clicks to pass through to the TextBox FontSize = fontSize - 1, Padding = new Thickness(2,0,2,0) }; AddVisualChild(_placeholderTextBlock); } protected override int VisualChildrenCount => 1; protected override Visual GetVisualChild(int index) => _placeholderTextBlock; protected override Size MeasureOverride(Size constraint) { _placeholderTextBlock.Measure(constraint); return AdornedElement.RenderSize; } protected override Size ArrangeOverride(Size finalSize) { _placeholderTextBlock.Arrange(new Rect(finalSize)); return finalSize; } } }