From 4aa20d930fc76fb0b1a9acb49bea6f8dfb153949 Mon Sep 17 00:00:00 2001 From: rabbitism Date: Sun, 23 Jun 2024 16:46:09 +0800 Subject: [PATCH] feat: add watermark support. --- demo/Ursa.Demo/Pages/TagInputDemo.axaml | 1 + src/Ursa.Themes.Semi/Controls/TagInput.axaml | 12 ++++- src/Ursa/Controls/TagInput/TagInput.cs | 54 +++++++++++++++++++- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/demo/Ursa.Demo/Pages/TagInputDemo.axaml b/demo/Ursa.Demo/Pages/TagInputDemo.axaml index dadccf2..aa17cb2 100644 --- a/demo/Ursa.Demo/Pages/TagInputDemo.axaml +++ b/demo/Ursa.Demo/Pages/TagInputDemo.axaml @@ -17,6 +17,7 @@ Margin="20" AllowDuplicates="True" Separator="-" + Watermark="Hello world" Tags="{Binding Tags}" /> + + @@ -123,10 +131,10 @@ Foreground="{TemplateBinding Foreground}" /> diff --git a/src/Ursa/Controls/TagInput/TagInput.cs b/src/Ursa/Controls/TagInput/TagInput.cs index 30773d4..c51fd8d 100644 --- a/src/Ursa/Controls/TagInput/TagInput.cs +++ b/src/Ursa/Controls/TagInput/TagInput.cs @@ -1,6 +1,7 @@ using System.Collections; using System.Collections.ObjectModel; using System.Collections.Specialized; +using System.ComponentModel; using Avalonia; using Avalonia.Collections; using Avalonia.Controls; @@ -8,32 +9,56 @@ using Avalonia.Controls.Metadata; using Avalonia.Controls.Presenters; using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; +using Avalonia.Data; +using Avalonia.Data.Converters; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Layout; using Avalonia.Styling; +using Irihi.Avalonia.Shared.Common; +using Irihi.Avalonia.Shared.Helpers; namespace Ursa.Controls; [TemplatePart(PART_ItemsControl, typeof(ItemsControl))] +[TemplatePart(PART_Watermark, typeof(Visual))] +[PseudoClasses(PseudoClassName.PC_Empty)] public class TagInput : TemplatedControl { public const string PART_ItemsControl = "PART_ItemsControl"; + public const string PART_Watermark = "PART_Watermark"; private readonly TextBox _textBox; private ItemsControl? _itemsControl; - + private Visual? _watermark; public static readonly StyledProperty> TagsProperty = AvaloniaProperty.Register>( nameof(Tags)); + public static readonly StyledProperty WatermarkProperty = TextBox.WatermarkProperty.AddOwner(); + + public string? Watermark + { + get => GetValue(WatermarkProperty); + set => SetValue(WatermarkProperty, value); + } + public IList Tags { get => GetValue(TagsProperty); set => SetValue(TagsProperty, value); } + public static readonly StyledProperty MaxCountProperty = AvaloniaProperty.Register( + nameof(MaxCount), int.MaxValue); + + public int MaxCount + { + get => GetValue(MaxCountProperty); + set => SetValue(MaxCountProperty, value); + } + public static readonly DirectProperty ItemsProperty = AvaloniaProperty.RegisterDirect( nameof(Items), o => o.Items); @@ -150,6 +175,21 @@ public class TagInput : TemplatedControl { base.OnApplyTemplate(e); _itemsControl = e.NameScope.Find(PART_ItemsControl); + _watermark = e.NameScope.Find(PART_Watermark); + } + + private TextPresenter? _presenter; + protected override void OnLoaded(RoutedEventArgs e) + { + base.OnLoaded(e); + if (_watermark is null) return; + _presenter = _textBox.GetTemplateChildren().OfType().FirstOrDefault(); + _presenter?.GetObservable(TextPresenter.PreeditTextProperty).Subscribe(a => CheckEmpty()); + _textBox.GetObservable(TextBox.TextProperty).Subscribe(a => CheckEmpty()); + if (Tags is INotifyCollectionChanged incc) + { + incc.GetWeakCollectionChangedObservable().Subscribe(a => this.CheckEmpty()); + } } private void OnInputThemePropertyChanged(AvaloniaPropertyChangedEventArgs args) @@ -160,6 +200,18 @@ public class TagInput : TemplatedControl _textBox.Theme = newTheme; } } + + private void CheckEmpty() + { + if(string.IsNullOrWhiteSpace(_presenter?.PreeditText) && string.IsNullOrEmpty(_textBox?.Text) && (Tags.Count==0)) + { + PseudoClasses.Set(PseudoClassName.PC_Empty, true); + } + else + { + PseudoClasses.Set(PseudoClassName.PC_Empty, false); + } + } private void OnTagsPropertyChanged(AvaloniaPropertyChangedEventArgs args) {