feat: selected item is now two-way binding by default.

This commit is contained in:
rabbitism
2024-04-17 20:35:35 +08:00
parent 2c471aa3f6
commit 50be089b4e
5 changed files with 73 additions and 27 deletions

View File

@@ -31,17 +31,22 @@
<u:TreeComboBox
Width="300"
HorizontalAlignment="Left"
SelectedItem="{Binding SelectedItem}"
ItemsSource="{Binding Items}">
<u:TreeComboBox.ItemTemplate>
<TreeDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding ItemName}" />
</TreeDataTemplate>
</u:TreeComboBox.ItemTemplate>
<u:TreeComboBox.SelectedItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ItemName}" />
</DataTemplate>
</u:TreeComboBox.SelectedItemTemplate>
</u:TreeComboBox>
<ContentControl Content="{Binding SelectedItem}">
<ContentControl.ContentTemplate>
<DataTemplate DataType="vm:TreeComboBoxItemViewModel">
<TextBlock Text="{Binding ItemName}"></TextBlock>
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
</StackPanel>
</UserControl>

View File

@@ -3,8 +3,9 @@ using CommunityToolkit.Mvvm.ComponentModel;
namespace Ursa.Demo.ViewModels;
public class TreeComboBoxDemoViewModel: ObservableObject
public partial class TreeComboBoxDemoViewModel: ObservableObject
{
[ObservableProperty] private TreeComboBoxItemViewModel? _selectedItem;
public List<TreeComboBoxItemViewModel> Items { get; set; }
public TreeComboBoxDemoViewModel()

View File

@@ -2,10 +2,12 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:u="https://irihi.tech/ursa"
xmlns:iri="https://irihi.tech/shared"
xmlns:converters="clr-namespace:Avalonia.Controls.Converters;assembly=Avalonia.Controls">
xmlns:converters="clr-namespace:Avalonia.Controls.Converters;assembly=Avalonia.Controls"
xmlns:converters1="clr-namespace:Ursa.Themes.Semi.Converters">
<!-- Add Resources Here -->
<converters:MarginMultiplierConverter x:Key="LeftMarginConverter" Indent="20" Left="True"/>
<converters1:SelectedItemTemplateConverter x:Key="SelectedItemTemplateConverter"/>
<ControlTheme x:Key="{x:Type u:TreeComboBox}" TargetType="u:TreeComboBox">
<Setter Property="Padding" Value="{DynamicResource ComboBoxSelectorDefaultPadding}"/>
@@ -17,7 +19,7 @@
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Template">
<ControlTemplate TargetType="u:TreeComboBox">
<Grid ColumnDefinitions="*, Auto, 32">
<Grid ColumnDefinitions="*, Auto, Auto">
<Border Grid.Column="0"
Name="Background"
Grid.ColumnSpan="3"
@@ -44,8 +46,14 @@
Margin="{TemplateBinding Padding}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
VerticalAlignment="Center"
ContentTemplate="{TemplateBinding SelectedItemTemplate}"
Content="{TemplateBinding SelectionBoxItem}"/>
Content="{TemplateBinding SelectionBoxItem}">
<ContentPresenter.ContentTemplate>
<MultiBinding Converter="{x:Static converters1:SelectedItemTemplateConverter.Instance}">
<TemplateBinding Property="SelectedItemTemplate"/>
<TemplateBinding Property="ItemTemplate"/>
</MultiBinding>
</ContentPresenter.ContentTemplate>
</ContentPresenter>
<Border
x:Name="DropDownOverlay"
Grid.Column="2"
@@ -54,19 +62,18 @@
HorizontalAlignment="Right"
Background="Transparent"
IsVisible="False" />
<PathIcon
x:Name="DropDownGlyph"
Grid.Column="2"
Width="12"
Height="12"
Margin="0,0,10,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Data="{DynamicResource ComboBoxIcon}"
Foreground="{DynamicResource ComboBoxIconDefaultForeground}"
IsHitTestVisible="False"
UseLayoutRounding="False" />
<Panel Grid.Column="2" Width="32" IsHitTestVisible="False">
<PathIcon
x:Name="DropDownGlyph"
Width="12"
Height="12"
Margin="0,0,10,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Data="{DynamicResource ComboBoxIcon}"
Foreground="{DynamicResource ComboBoxIconDefaultForeground}"
UseLayoutRounding="False" />
</Panel>
<Popup
Name="{x:Static iri:PartNames.PART_Popup}"
Grid.Column="0"
@@ -77,7 +84,7 @@
PlacementTarget="Background"
WindowManagerAddShadowHint="False"
IsLightDismissEnabled="True"
IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}">
IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}">
<Border
Name="PopupBorder"
Margin="0 4"

View File

@@ -0,0 +1,24 @@
using System.Globalization;
using Avalonia;
using Avalonia.Controls.Templates;
using Avalonia.Data.Converters;
namespace Ursa.Themes.Semi.Converters;
public class SelectedItemTemplateConverter: IMultiValueConverter
{
public static SelectedItemTemplateConverter Instance { get; } = new SelectedItemTemplateConverter();
public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
{
if(values.Count>0 && values[0] is IDataTemplate template1)
{
return template1;
}
if(values.Count>1 && values[1] is IDataTemplate template2)
{
return template2;
}
return AvaloniaProperty.UnsetValue;
}
}

View File

@@ -4,19 +4,21 @@ using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Metadata;
using Avalonia.VisualTree;
using Irihi.Avalonia.Shared.Common;
using Irihi.Avalonia.Shared.Contracts;
using Size = Avalonia.Size;
namespace Ursa.Controls;
[TemplatePart(PartNames.PART_Popup, typeof(Popup))]
public class TreeComboBox: ItemsControl
public class TreeComboBox: ItemsControl, IClearControl
{
private Popup? _popup;
@@ -89,8 +91,10 @@ public class TreeComboBox: ItemsControl
private object? _selectedItem;
public static readonly DirectProperty<TreeComboBox, object?> SelectedItemProperty = AvaloniaProperty.RegisterDirect<TreeComboBox, object?>(
nameof(SelectedItem), o => o.SelectedItem, (o, v) => o.SelectedItem = v);
public static readonly DirectProperty<TreeComboBox, object?> SelectedItemProperty =
AvaloniaProperty.RegisterDirect<TreeComboBox, object?>(
nameof(SelectedItem), o => o.SelectedItem, (o, v) => o.SelectedItem = v,
defaultBindingMode: BindingMode.TwoWay);
public object? SelectedItem
{
@@ -284,4 +288,9 @@ public class TreeComboBox: ItemsControl
treeComboBoxItem.IsSelected = selected;
}
}
public void Clear()
{
SelectedItem = null;
}
}