зеркало из https://github.com/AvaloniaUI/Avalonia.git
ComboBox: support different DataTemplate for selected item. (#15420)
* feat: ComboBox: support different DataTemplate for selected item. * feat: use coerce instead of multi binding. * test: add multiple unit tests.
This commit is contained in:
Родитель
7a7ab8e5f8
Коммит
edb66a7720
|
@ -12,8 +12,8 @@
|
|||
<StackPanel
|
||||
Margin="0,16,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
Orientation="Horizontal"
|
||||
Spacing="8">
|
||||
<CheckBox IsChecked="{Binding WrapSelection}">WrapSelection</CheckBox>
|
||||
<WrapPanel
|
||||
MaxWidth="660"
|
||||
Margin="0,16,0,0"
|
||||
|
@ -99,9 +99,31 @@
|
|||
<ComboBoxItem>Inline Item 4</ComboBoxItem>
|
||||
</ComboBox>
|
||||
|
||||
<ComboBox WrapSelection="{Binding WrapSelection}" ItemsSource="{Binding Values}" DisplayMemberBinding="{Binding Name}">
|
||||
<ComboBox
|
||||
WrapSelection="{Binding WrapSelection}"
|
||||
ItemsSource="{Binding Values}"
|
||||
DisplayMemberBinding="{Binding Name}">
|
||||
|
||||
</ComboBox>
|
||||
|
||||
<ComboBox
|
||||
WrapSelection="{Binding WrapSelection}"
|
||||
PlaceholderText="Different Template"
|
||||
ItemsSource="{Binding Values}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding Name}"></TextBlock>
|
||||
<TextBlock Text="{Binding Id}"></TextBlock>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
<ComboBox.SelectionBoxItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock Text="{Binding Name}" Foreground="Red"></TextBlock>
|
||||
</DataTemplate>
|
||||
</ComboBox.SelectionBoxItemTemplate>
|
||||
</ComboBox>
|
||||
|
||||
<ComboBox WrapSelection="{Binding WrapSelection}" ItemsSource="{Binding Values}" >
|
||||
<ComboBox.ItemTemplate>
|
||||
|
@ -114,9 +136,6 @@
|
|||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
</WrapPanel>
|
||||
|
||||
<CheckBox IsChecked="{Binding WrapSelection}">WrapSelection</CheckBox>
|
||||
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
|
|
|
@ -5,10 +5,12 @@ using Avalonia.Controls.Metadata;
|
|||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Shapes;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Metadata;
|
||||
using Avalonia.Reactive;
|
||||
using Avalonia.VisualTree;
|
||||
|
||||
|
@ -71,6 +73,23 @@ namespace Avalonia.Controls
|
|||
/// </summary>
|
||||
public static readonly StyledProperty<VerticalAlignment> VerticalContentAlignmentProperty =
|
||||
ContentControl.VerticalContentAlignmentProperty.AddOwner<ComboBox>();
|
||||
|
||||
/// <summary>
|
||||
/// Defines the <see cref="SelectionBoxItemTemplate"/> property.
|
||||
/// </summary>
|
||||
public static readonly StyledProperty<IDataTemplate?> SelectionBoxItemTemplateProperty =
|
||||
AvaloniaProperty.Register<ComboBox, IDataTemplate?>(
|
||||
nameof(SelectionBoxItemTemplate), defaultBindingMode: BindingMode.TwoWay, coerce: CoerceSelectionBoxItemTemplate);
|
||||
|
||||
private static IDataTemplate? CoerceSelectionBoxItemTemplate(AvaloniaObject obj, IDataTemplate? template)
|
||||
{
|
||||
if (template is not null) return template;
|
||||
if(obj is ComboBox comboBox && template is null)
|
||||
{
|
||||
return comboBox.ItemTemplate;
|
||||
}
|
||||
return template;
|
||||
}
|
||||
|
||||
private Popup? _popup;
|
||||
private object? _selectionBoxItem;
|
||||
|
@ -159,6 +178,16 @@ namespace Avalonia.Controls
|
|||
set => SetValue(VerticalContentAlignmentProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the DataTemplate used to display the selected item. This has a higher priority than <see cref="ItemsControl.ItemTemplate"/> if set.
|
||||
/// </summary>
|
||||
[InheritDataTypeFromItems(nameof(ItemsSource))]
|
||||
public IDataTemplate? SelectionBoxItemTemplate
|
||||
{
|
||||
get => GetValue(SelectionBoxItemTemplateProperty);
|
||||
set => SetValue(SelectionBoxItemTemplateProperty, value);
|
||||
}
|
||||
|
||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
{
|
||||
base.OnAttachedToVisualTree(e);
|
||||
|
@ -322,7 +351,10 @@ namespace Avalonia.Controls
|
|||
{
|
||||
PseudoClasses.Set(pcDropdownOpen, change.GetNewValue<bool>());
|
||||
}
|
||||
|
||||
else if (change.Property == ItemTemplateProperty)
|
||||
{
|
||||
CoerceValue(SelectionBoxItemTemplateProperty);
|
||||
}
|
||||
base.OnPropertyChanged(change);
|
||||
}
|
||||
|
||||
|
@ -433,7 +465,7 @@ namespace Avalonia.Controls
|
|||
}
|
||||
else
|
||||
{
|
||||
if(ItemTemplate is null && DisplayMemberBinding is { } binding)
|
||||
if(ItemTemplate is null && SelectionBoxItemTemplate is null && DisplayMemberBinding is { } binding)
|
||||
{
|
||||
var template = new FuncDataTemplate<object?>((_, _) =>
|
||||
new TextBlock
|
||||
|
|
|
@ -84,11 +84,12 @@
|
|||
IsVisible="{TemplateBinding SelectionBoxItem, Converter={x:Static ObjectConverters.IsNull}}" />
|
||||
<ContentControl x:Name="ContentPresenter"
|
||||
Content="{TemplateBinding SelectionBoxItem}"
|
||||
ContentTemplate="{TemplateBinding ItemTemplate}"
|
||||
Grid.Column="0"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
|
||||
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
|
||||
</ContentControl>
|
||||
|
||||
<Border x:Name="DropDownOverlay"
|
||||
Grid.Column="1"
|
||||
|
|
|
@ -34,7 +34,8 @@
|
|||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{TemplateBinding SelectionBoxItem}"
|
||||
ContentTemplate="{TemplateBinding ItemTemplate}" />
|
||||
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}">
|
||||
</ContentControl>
|
||||
<ToggleButton Name="toggle"
|
||||
Grid.Column="1"
|
||||
Background="Transparent"
|
||||
|
|
|
@ -453,5 +453,69 @@ namespace Avalonia.Controls.UnitTests
|
|||
Assert.Equal(FlowDirection.RightToLeft, rectangle.FlowDirection);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelectionBoxItemTemplate_Overrides_ItemTemplate()
|
||||
{
|
||||
IDataTemplate itemTemplate = new FuncDataTemplate<string>((x, _) => new TextBlock { Text = x + "!" });
|
||||
IDataTemplate selectionBoxItemTemplate = new FuncDataTemplate<string>((x, _) => new TextBlock { Text = x });
|
||||
var target = new ComboBox
|
||||
{
|
||||
ItemsSource = new []{ "Foo" },
|
||||
SelectionBoxItemTemplate = selectionBoxItemTemplate,
|
||||
ItemTemplate = itemTemplate,
|
||||
};
|
||||
|
||||
Assert.Equal(selectionBoxItemTemplate, target.SelectionBoxItemTemplate);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelectionBoxItemTemplate_Inherits_From_ItemTemplate_When_NotSet()
|
||||
{
|
||||
IDataTemplate itemTemplate = new FuncDataTemplate<string>((x, _) => new TextBlock { Text = x + "!" });
|
||||
var target = new ComboBox
|
||||
{
|
||||
ItemsSource = new []{ "Foo" },
|
||||
ItemTemplate = itemTemplate,
|
||||
};
|
||||
|
||||
Assert.Equal(itemTemplate, target.SelectionBoxItemTemplate);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelectionBoxItemTemplate_Overrides_ItemTemplate_After_ItemTemplate_Changed()
|
||||
{
|
||||
IDataTemplate itemTemplate = new FuncDataTemplate<string>((x, _) => new TextBlock { Text = x + "!" });
|
||||
IDataTemplate selectionBoxItemTemplate = new FuncDataTemplate<string>((x, _) => new TextBlock { Text = x });
|
||||
IDataTemplate itemTemplate2 = new FuncDataTemplate<string>((x, _) => new TextBlock { Text = x + "?" });
|
||||
var target = new ComboBox
|
||||
{
|
||||
ItemsSource = new[] { "Foo" },
|
||||
SelectionBoxItemTemplate = selectionBoxItemTemplate,
|
||||
ItemTemplate = itemTemplate,
|
||||
};
|
||||
|
||||
Assert.Equal(selectionBoxItemTemplate, target.SelectionBoxItemTemplate);
|
||||
|
||||
target.ItemTemplate = itemTemplate2;
|
||||
|
||||
Assert.Equal(selectionBoxItemTemplate, target.SelectionBoxItemTemplate);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelectionBoxItemTemplate_Inherits_From_ItemTemplate_When_ItemTemplate_Changed()
|
||||
{
|
||||
IDataTemplate itemTemplate = new FuncDataTemplate<string>((x, _) => new TextBlock { Text = x + "!" });
|
||||
IDataTemplate selectionBoxItemTemplate = new FuncDataTemplate<string>((x, _) => new TextBlock { Text = x });
|
||||
IDataTemplate itemTemplate2 = new FuncDataTemplate<string>((x, _) => new TextBlock { Text = x + "?" });
|
||||
var target = new ComboBox { ItemsSource = new[] { "Foo" }, ItemTemplate = itemTemplate, };
|
||||
|
||||
Assert.Equal(itemTemplate, target.SelectionBoxItemTemplate);
|
||||
|
||||
target.ItemTemplate = itemTemplate2;
|
||||
target.SelectionBoxItemTemplate = null;
|
||||
|
||||
Assert.Equal(itemTemplate2, target.SelectionBoxItemTemplate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче