Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ComboBox: support different DataTemplate for selected item. #15420

Merged
merged 3 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions samples/ControlCatalog/Pages/ComboBoxPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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.SelectedItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Foreground="Red"></TextBlock>
</DataTemplate>
</ComboBox.SelectedItemTemplate>
</ComboBox>

<ComboBox WrapSelection="{Binding WrapSelection}" ItemsSource="{Binding Values}" >
<ComboBox.ItemTemplate>
Expand All @@ -114,9 +136,6 @@
</ComboBox.ItemTemplate>
</ComboBox>
</WrapPanel>

<CheckBox IsChecked="{Binding WrapSelection}">WrapSelection</CheckBox>

</StackPanel>
</StackPanel>
</UserControl>
21 changes: 20 additions & 1 deletion src/Avalonia.Controls/ComboBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
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;

Expand Down Expand Up @@ -71,6 +73,13 @@ public class ComboBox : SelectingItemsControl
/// </summary>
public static readonly StyledProperty<VerticalAlignment> VerticalContentAlignmentProperty =
ContentControl.VerticalContentAlignmentProperty.AddOwner<ComboBox>();

/// <summary>
/// Defines the <see cref="SelectedItemTemplate"/> property.
/// </summary>
public static readonly StyledProperty<IDataTemplate?> SelectedItemTemplateProperty =
AvaloniaProperty.Register<ComboBox, IDataTemplate?>(
nameof(SelectedItemTemplate), defaultBindingMode: BindingMode.TwoWay);

private Popup? _popup;
private object? _selectionBoxItem;
Expand Down Expand Up @@ -159,6 +168,16 @@ public VerticalAlignment VerticalContentAlignment
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? SelectedItemTemplate
{
get => GetValue(SelectedItemTemplateProperty);
set => SetValue(SelectedItemTemplateProperty, value);
}

protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
Expand Down Expand Up @@ -433,7 +452,7 @@ private void UpdateSelectionBoxItem(object? item)
}
else
{
if(ItemTemplate is null && DisplayMemberBinding is { } binding)
if(ItemTemplate is null && SelectedItemTemplate is null && DisplayMemberBinding is { } binding)
{
var template = new FuncDataTemplate<object?>((_, _) =>
new TextBlock
Expand Down
23 changes: 23 additions & 0 deletions src/Avalonia.Controls/Converters/MultiDataTemplatesConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using Avalonia.Controls.Templates;
using Avalonia.Data.Converters;

namespace Avalonia.Controls.Converters;

/// <summary>
/// Select a valid IDataTemplate in order.
/// </summary>
public class MultiDataTemplatesConverter: IMultiValueConverter
rabbitism marked this conversation as resolved.
Show resolved Hide resolved
{
/// <inheritdoc/>
public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
{
for (var i = 0; i < values.Count; i++)
{
if (values[i] is IDataTemplate template) return template;
}
return null;
}
}
12 changes: 10 additions & 2 deletions src/Avalonia.Themes.Fluent/Controls/ComboBox.xaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="using:System"
xmlns:converters="clr-namespace:Avalonia.Controls.Converters;assembly=Avalonia.Controls"
x:ClassModifier="internal">
<Design.PreviewWith>
<Border Padding="20">
Expand Down Expand Up @@ -36,6 +37,7 @@
<Thickness x:Key="ComboBoxPadding">12,5,0,7</Thickness>
<Thickness x:Key="ComboBoxEditableTextPadding">11,5,32,6</Thickness>
<x:Double x:Key="ComboBoxMinHeight">32</x:Double>
<converters:MultiDataTemplatesConverter x:Key="TemplatesConverter"/>

<ControlTheme x:Key="{x:Type ComboBox}" TargetType="ComboBox">
<Setter Property="Padding" Value="{DynamicResource ComboBoxPadding}" />
Expand Down Expand Up @@ -84,11 +86,17 @@
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}" />
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
<ContentControl.ContentTemplate>
<MultiBinding Converter="{StaticResource TemplatesConverter}">
<TemplateBinding Property="SelectedItemTemplate"></TemplateBinding>
<TemplateBinding Property="ItemTemplate"></TemplateBinding>
</MultiBinding>
</ContentControl.ContentTemplate>
</ContentControl>

<Border x:Name="DropDownOverlay"
Grid.Column="1"
Expand Down
12 changes: 10 additions & 2 deletions src/Avalonia.Themes.Simple/Controls/ComboBox.xaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:Avalonia.Controls.Converters;assembly=Avalonia.Controls"
x:ClassModifier="internal">
<converters:MultiDataTemplatesConverter x:Key="TemplatesConverter"/>
<ControlTheme x:Key="{x:Type ComboBox}"
TargetType="ComboBox">
<Setter Property="Background" Value="Transparent" />
Expand Down Expand Up @@ -33,8 +35,14 @@
<ContentControl Margin="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding ItemTemplate}" />
Content="{TemplateBinding SelectionBoxItem}">
<ContentControl.ContentTemplate>
<MultiBinding Converter="{StaticResource TemplatesConverter}">
<TemplateBinding Property="SelectedItemTemplate"></TemplateBinding>
<TemplateBinding Property="ItemTemplate"></TemplateBinding>
</MultiBinding>
</ContentControl.ContentTemplate>
</ContentControl>
<ToggleButton Name="toggle"
Grid.Column="1"
Background="Transparent"
Expand Down
Loading