feat: add watermark support.
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
Margin="20"
|
Margin="20"
|
||||||
AllowDuplicates="True"
|
AllowDuplicates="True"
|
||||||
Separator="-"
|
Separator="-"
|
||||||
|
Watermark="Hello world"
|
||||||
Tags="{Binding Tags}" />
|
Tags="{Binding Tags}" />
|
||||||
<u:TagInput
|
<u:TagInput
|
||||||
Margin="20"
|
Margin="20"
|
||||||
|
|||||||
@@ -25,6 +25,11 @@
|
|||||||
BorderThickness="1"
|
BorderThickness="1"
|
||||||
CornerRadius="3">
|
CornerRadius="3">
|
||||||
<Panel HorizontalAlignment="Stretch">
|
<Panel HorizontalAlignment="Stretch">
|
||||||
|
<TextBlock
|
||||||
|
Name="{x:Static u:TagInput.PART_Watermark}"
|
||||||
|
Opacity="0.5"
|
||||||
|
IsVisible="False"
|
||||||
|
Text="{TemplateBinding Watermark}" />
|
||||||
<ItemsControl
|
<ItemsControl
|
||||||
Name="PART_ItemsControl"
|
Name="PART_ItemsControl"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
@@ -42,6 +47,9 @@
|
|||||||
</Border>
|
</Border>
|
||||||
</ControlTemplate>
|
</ControlTemplate>
|
||||||
</Setter>
|
</Setter>
|
||||||
|
<Style Selector="^:empty /template/ TextBlock#PART_Watermark">
|
||||||
|
<Setter Property="IsVisible" Value="True"></Setter>
|
||||||
|
</Style>
|
||||||
<Style Selector="^:pointerover /template/ Border#PART_BackgroundBorder">
|
<Style Selector="^:pointerover /template/ Border#PART_BackgroundBorder">
|
||||||
<Setter Property="Border.Background" Value="{DynamicResource TextBoxPointeroverBackground}" />
|
<Setter Property="Border.Background" Value="{DynamicResource TextBoxPointeroverBackground}" />
|
||||||
</Style>
|
</Style>
|
||||||
@@ -123,10 +131,10 @@
|
|||||||
Foreground="{TemplateBinding Foreground}" />
|
Foreground="{TemplateBinding Foreground}" />
|
||||||
<ContentPresenter
|
<ContentPresenter
|
||||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||||
FontSize="12"
|
|
||||||
Foreground="{TemplateBinding Foreground}"
|
|
||||||
Content="{TemplateBinding Content}"
|
Content="{TemplateBinding Content}"
|
||||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||||
|
FontSize="12"
|
||||||
|
Foreground="{TemplateBinding Foreground}"
|
||||||
TextTrimming="CharacterEllipsis" />
|
TextTrimming="CharacterEllipsis" />
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
|
using System.ComponentModel;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Collections;
|
using Avalonia.Collections;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
@@ -8,32 +9,56 @@ using Avalonia.Controls.Metadata;
|
|||||||
using Avalonia.Controls.Presenters;
|
using Avalonia.Controls.Presenters;
|
||||||
using Avalonia.Controls.Primitives;
|
using Avalonia.Controls.Primitives;
|
||||||
using Avalonia.Controls.Templates;
|
using Avalonia.Controls.Templates;
|
||||||
|
using Avalonia.Data;
|
||||||
|
using Avalonia.Data.Converters;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Layout;
|
using Avalonia.Layout;
|
||||||
using Avalonia.Styling;
|
using Avalonia.Styling;
|
||||||
|
using Irihi.Avalonia.Shared.Common;
|
||||||
|
using Irihi.Avalonia.Shared.Helpers;
|
||||||
|
|
||||||
namespace Ursa.Controls;
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
[TemplatePart(PART_ItemsControl, typeof(ItemsControl))]
|
[TemplatePart(PART_ItemsControl, typeof(ItemsControl))]
|
||||||
|
[TemplatePart(PART_Watermark, typeof(Visual))]
|
||||||
|
[PseudoClasses(PseudoClassName.PC_Empty)]
|
||||||
public class TagInput : TemplatedControl
|
public class TagInput : TemplatedControl
|
||||||
{
|
{
|
||||||
public const string PART_ItemsControl = "PART_ItemsControl";
|
public const string PART_ItemsControl = "PART_ItemsControl";
|
||||||
|
public const string PART_Watermark = "PART_Watermark";
|
||||||
|
|
||||||
private readonly TextBox _textBox;
|
private readonly TextBox _textBox;
|
||||||
private ItemsControl? _itemsControl;
|
private ItemsControl? _itemsControl;
|
||||||
|
private Visual? _watermark;
|
||||||
|
|
||||||
public static readonly StyledProperty<IList<string>> TagsProperty =
|
public static readonly StyledProperty<IList<string>> TagsProperty =
|
||||||
AvaloniaProperty.Register<TagInput, IList<string>>(
|
AvaloniaProperty.Register<TagInput, IList<string>>(
|
||||||
nameof(Tags));
|
nameof(Tags));
|
||||||
|
|
||||||
|
public static readonly StyledProperty<string?> WatermarkProperty = TextBox.WatermarkProperty.AddOwner<TagInput>();
|
||||||
|
|
||||||
|
public string? Watermark
|
||||||
|
{
|
||||||
|
get => GetValue(WatermarkProperty);
|
||||||
|
set => SetValue(WatermarkProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
public IList<string> Tags
|
public IList<string> Tags
|
||||||
{
|
{
|
||||||
get => GetValue(TagsProperty);
|
get => GetValue(TagsProperty);
|
||||||
set => SetValue(TagsProperty, value);
|
set => SetValue(TagsProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<int> MaxCountProperty = AvaloniaProperty.Register<TagInput, int>(
|
||||||
|
nameof(MaxCount), int.MaxValue);
|
||||||
|
|
||||||
|
public int MaxCount
|
||||||
|
{
|
||||||
|
get => GetValue(MaxCountProperty);
|
||||||
|
set => SetValue(MaxCountProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
public static readonly DirectProperty<TagInput, IList> ItemsProperty =
|
public static readonly DirectProperty<TagInput, IList> ItemsProperty =
|
||||||
AvaloniaProperty.RegisterDirect<TagInput, IList>(
|
AvaloniaProperty.RegisterDirect<TagInput, IList>(
|
||||||
nameof(Items), o => o.Items);
|
nameof(Items), o => o.Items);
|
||||||
@@ -150,6 +175,21 @@ public class TagInput : TemplatedControl
|
|||||||
{
|
{
|
||||||
base.OnApplyTemplate(e);
|
base.OnApplyTemplate(e);
|
||||||
_itemsControl = e.NameScope.Find<ItemsControl>(PART_ItemsControl);
|
_itemsControl = e.NameScope.Find<ItemsControl>(PART_ItemsControl);
|
||||||
|
_watermark = e.NameScope.Find<Visual>(PART_Watermark);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TextPresenter? _presenter;
|
||||||
|
protected override void OnLoaded(RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnLoaded(e);
|
||||||
|
if (_watermark is null) return;
|
||||||
|
_presenter = _textBox.GetTemplateChildren().OfType<TextPresenter>().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)
|
private void OnInputThemePropertyChanged(AvaloniaPropertyChangedEventArgs args)
|
||||||
@@ -160,6 +200,18 @@ public class TagInput : TemplatedControl
|
|||||||
_textBox.Theme = newTheme;
|
_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)
|
private void OnTagsPropertyChanged(AvaloniaPropertyChangedEventArgs args)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user