feat: add closing feature.
This commit is contained in:
@@ -9,10 +9,7 @@
|
||||
<Setter Property="VerticalAlignment" Value="Top" />
|
||||
<Setter Property="ItemTemplate">
|
||||
<DataTemplate>
|
||||
<Label
|
||||
Classes="Solid"
|
||||
Content="{Binding}"
|
||||
Theme="{DynamicResource TagLabel}" />
|
||||
<u:ClosableTag Command="{Binding $parent[u:TagInput].Close}" Content="{Binding}" />
|
||||
</DataTemplate>
|
||||
</Setter>
|
||||
<Setter Property="Template">
|
||||
@@ -24,6 +21,7 @@
|
||||
CornerRadius="3">
|
||||
<Panel HorizontalAlignment="Stretch">
|
||||
<ItemsControl
|
||||
Name="PART_ItemsControl"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
ItemTemplate="{TemplateBinding ItemTemplate}"
|
||||
@@ -84,4 +82,34 @@
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</ControlTheme>
|
||||
|
||||
<ControlTheme x:Key="{x:Type u:ClosableTag}" TargetType="u:ClosableTag">
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate TargetType="u:ClosableTag">
|
||||
<Border
|
||||
Margin="1"
|
||||
Background="Transparent"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="1"
|
||||
CornerRadius="3">
|
||||
<DockPanel LastChildFill="True">
|
||||
<PathIcon
|
||||
Name="{x:Static u:ClosableTag.PART_CloseButton}"
|
||||
Width="8"
|
||||
Height="8"
|
||||
Background="Transparent"
|
||||
Data="M17.6568 19.7782C18.2426 20.3639 19.1924 20.3639 19.7782 19.7782C20.3639 19.1924 20.3639 18.2426 19.7782 17.6568L14.1213 12L19.7782 6.34313C20.3639 5.75734 20.3639 4.8076 19.7782 4.22181C19.1924 3.63602 18.2426 3.63602 17.6568 4.22181L12 9.87866L6.34313 4.22181C5.75734 3.63602 4.8076 3.63602 4.22181 4.22181C3.63602 4.8076 3.63602 5.75734 4.22181 6.34313L9.87866 12L4.22181 17.6568C3.63602 18.2426 3.63602 19.1924 4.22181 19.7782C4.8076 20.3639 5.75734 20.3639 6.34313 19.7782L12 14.1213L17.6568 19.7782Z"
|
||||
DockPanel.Dock="Right" />
|
||||
<TextBlock
|
||||
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
FontSize="12"
|
||||
Text="{TemplateBinding Content}"
|
||||
TextTrimming="CharacterEllipsis" />
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</ControlTheme>
|
||||
</ResourceDictionary>
|
||||
|
||||
46
src/Ursa/Controls/TagInput/ClosableTag.cs
Normal file
46
src/Ursa/Controls/TagInput/ClosableTag.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System.Windows.Input;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Metadata;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Input;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
[TemplatePart(PART_CloseButton, typeof(PathIcon))]
|
||||
public class ClosableTag: ContentControl
|
||||
{
|
||||
public const string PART_CloseButton = "PART_CloseButton";
|
||||
private PathIcon? _icon;
|
||||
public static readonly StyledProperty<ICommand?> CommandProperty = AvaloniaProperty.Register<ClosableTag, ICommand?>(
|
||||
nameof(Command));
|
||||
|
||||
public ICommand? Command
|
||||
{
|
||||
get => GetValue(CommandProperty);
|
||||
set => SetValue(CommandProperty, value);
|
||||
}
|
||||
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
if (_icon != null)
|
||||
{
|
||||
_icon.PointerPressed -= OnPointerPressed;
|
||||
}
|
||||
_icon = e.NameScope.Find<PathIcon>(PART_CloseButton);
|
||||
if (_icon != null)
|
||||
{
|
||||
_icon.PointerPressed += OnPointerPressed;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void OnPointerPressed(object? sender, PointerPressedEventArgs args)
|
||||
{
|
||||
if (Command != null && Command.CanExecute(null))
|
||||
{
|
||||
Command.Execute(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,29 @@
|
||||
using System.Collections;
|
||||
using System.Collections.ObjectModel;
|
||||
using Avalonia;
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.Metadata;
|
||||
using Avalonia.Controls.Presenters;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Styling;
|
||||
|
||||
namespace Ursa.Controls;
|
||||
|
||||
[TemplatePart (PART_ItemsControl, typeof (ItemsControl))]
|
||||
public class TagInput: TemplatedControl
|
||||
{
|
||||
public const string PART_ItemsControl = "PART_ItemsControl";
|
||||
|
||||
private readonly TextBox _textBox;
|
||||
private ItemsControl? _itemsControl;
|
||||
|
||||
|
||||
public static readonly StyledProperty<IList<string>> TagsProperty = AvaloniaProperty.Register<TagInput, IList<string>>(
|
||||
nameof(Tags));
|
||||
|
||||
private TextBox _textBox;
|
||||
|
||||
public IList<string> Tags
|
||||
{
|
||||
get => GetValue(TagsProperty);
|
||||
@@ -24,7 +32,6 @@ public class TagInput: TemplatedControl
|
||||
|
||||
public static readonly StyledProperty<IList> ItemsProperty = AvaloniaProperty.Register<TagInput, IList>(
|
||||
nameof(Items));
|
||||
|
||||
public IList Items
|
||||
{
|
||||
get => GetValue(ItemsProperty);
|
||||
@@ -34,6 +41,9 @@ public class TagInput: TemplatedControl
|
||||
public TagInput()
|
||||
{
|
||||
_textBox = new TextBox();
|
||||
_textBox.KeyDown += OnTextBoxKeyDown;
|
||||
Items = new AvaloniaList<object>();
|
||||
Tags = new ObservableCollection<string>();
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<ControlTheme> InputThemeProperty = AvaloniaProperty.Register<TagInput, ControlTheme>(
|
||||
@@ -57,20 +67,42 @@ public class TagInput: TemplatedControl
|
||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||
{
|
||||
base.OnApplyTemplate(e);
|
||||
Items = new AvaloniaList<object>();
|
||||
_itemsControl = e.NameScope.Find<ItemsControl>(PART_ItemsControl);
|
||||
if (IsSet(InputThemeProperty) && InputTheme.TargetType == typeof(TextBox))
|
||||
{
|
||||
_textBox.Theme = InputTheme;
|
||||
}
|
||||
_textBox.KeyDown += (sender, args) =>
|
||||
{
|
||||
if (args.Key == Avalonia.Input.Key.Enter)
|
||||
{
|
||||
Items.Insert(Items.Count - 1, _textBox.Text);
|
||||
// Tags.Insert(Items.Count - 1, _textBox.Text ?? string.Empty);
|
||||
_textBox.Text = "";
|
||||
}
|
||||
};
|
||||
Items.Add(_textBox);
|
||||
}
|
||||
|
||||
private void OnTextBoxKeyDown(object? sender, KeyEventArgs args)
|
||||
{
|
||||
if (args.Key == Avalonia.Input.Key.Enter)
|
||||
{
|
||||
if (_textBox.Text?.Length > 0)
|
||||
{
|
||||
Items.Insert(Items.Count - 1, _textBox.Text);
|
||||
Tags.Insert(Items.Count - 2, _textBox.Text ?? string.Empty);
|
||||
_textBox.Text = "";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public void Close(object o)
|
||||
{
|
||||
if (o is ClosableTag t)
|
||||
{
|
||||
var presenter = t.Parent as ContentPresenter;
|
||||
if (presenter != null)
|
||||
{
|
||||
int? index = _itemsControl?.IndexFromContainer(presenter);
|
||||
if (index is >= 0 && index < Items.Count - 1)
|
||||
{
|
||||
Items.RemoveAt(index.Value);
|
||||
Tags.RemoveAt(index.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,7 +82,7 @@ public class TagInputPanel: Panel
|
||||
else
|
||||
{
|
||||
totalHeight += currentLineHeight;
|
||||
child.Arrange(new Rect(0, totalHeight, finalSize.Width, child.DesiredSize.Height));
|
||||
child.Arrange(new Rect(0, totalHeight, Math.Min(child.DesiredSize.Width, finalSize.Width), child.DesiredSize.Height));
|
||||
currentLineX = child.DesiredSize.Width;
|
||||
currentLineHeight = child.DesiredSize.Height;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user