diff --git a/samples/ControlCatalog/Pages/ListBoxPage.xaml b/samples/ControlCatalog/Pages/ListBoxPage.xaml
index 04129cb82d..dc0eaf0a51 100644
--- a/samples/ControlCatalog/Pages/ListBoxPage.xaml
+++ b/samples/ControlCatalog/Pages/ListBoxPage.xaml
@@ -32,6 +32,7 @@
diff --git a/samples/ControlCatalog/Pages/TabControlPage.xaml b/samples/ControlCatalog/Pages/TabControlPage.xaml
index a830ce69ac..e289de90f9 100644
--- a/samples/ControlCatalog/Pages/TabControlPage.xaml
+++ b/samples/ControlCatalog/Pages/TabControlPage.xaml
@@ -53,14 +53,8 @@
-
-
-
-
-
-
diff --git a/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs b/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
index 59489ebcc0..f89d9d1e20 100644
--- a/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
+++ b/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Reactive;
using Avalonia.Controls;
using Avalonia.Controls.Selection;
+using ControlCatalog.Pages;
using MiniMvvm;
namespace ControlCatalog.ViewModels
@@ -20,9 +21,9 @@ namespace ControlCatalog.ViewModels
public ListBoxPageViewModel()
{
- Items = new ObservableCollection(Enumerable.Range(1, 10000).Select(i => GenerateItem()));
+ Items = new ObservableCollection(Enumerable.Range(1, 10000).Select(i => GenerateItem()));
- Selection = new SelectionModel();
+ Selection = new SelectionModel();
Selection.Select(1);
_selectionMode = this.WhenAnyValue(
@@ -58,8 +59,8 @@ namespace ControlCatalog.ViewModels
});
}
- public ObservableCollection Items { get; }
- public SelectionModel Selection { get; }
+ public ObservableCollection Items { get; }
+ public SelectionModel Selection { get; }
public IObservable SelectionMode => _selectionMode;
public bool Multiple
@@ -96,6 +97,31 @@ namespace ControlCatalog.ViewModels
public MiniCommand RemoveItemCommand { get; }
public MiniCommand SelectRandomItemCommand { get; }
- private string GenerateItem() => $"Item {_counter++.ToString()}";
+ private ItemModel GenerateItem() => new ItemModel(_counter ++);
+ }
+
+ ///
+ /// An Item model for the
+ ///
+ public class ItemModel
+ {
+ ///
+ /// Creates a new ItemModel with the given ID
+ ///
+ /// The ID to display
+ public ItemModel(int id)
+ {
+ ID = id;
+ }
+
+ ///
+ /// The ID of this Item
+ ///
+ public int ID { get; }
+
+ public override string ToString()
+ {
+ return $"Item {ID}";
+ }
}
}
diff --git a/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs
index f9772cb399..79c77f2519 100644
--- a/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/IItemContainerGenerator.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Avalonia.Controls.Templates;
+using Avalonia.Data;
using Avalonia.Styling;
namespace Avalonia.Controls.Generators
@@ -24,6 +25,11 @@ namespace Avalonia.Controls.Generators
/// Gets or sets the data template used to display the items in the control.
///
IDataTemplate? ItemTemplate { get; set; }
+
+ ///
+ /// Gets or sets the binding to use to bind to the member of an item used for displaying
+ ///
+ IBinding? DisplayMemberBinding { get; set; }
///
/// Gets the ContainerType, or null if its an untyped ContainerGenerator.
diff --git a/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
index 7fed6cb82c..4ce48d2a06 100644
--- a/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
@@ -45,6 +45,9 @@ namespace Avalonia.Controls.Generators
/// Gets or sets the data template used to display the items in the control.
///
public IDataTemplate? ItemTemplate { get; set; }
+
+ ///
+ public IBinding? DisplayMemberBinding { get; set; }
///
/// Gets the owner control.
@@ -189,7 +192,15 @@ namespace Avalonia.Controls.Generators
if (result == null)
{
result = new ContentPresenter();
- result.SetValue(ContentPresenter.ContentProperty, item, BindingPriority.Style);
+ if (DisplayMemberBinding is not null)
+ {
+ result.SetValue(StyledElement.DataContextProperty, item, BindingPriority.Style);
+ result.Bind(ContentPresenter.ContentProperty, DisplayMemberBinding, BindingPriority.Style);
+ }
+ else
+ {
+ result.SetValue(ContentPresenter.ContentProperty, item, BindingPriority.Style);
+ }
if (ItemTemplate != null)
{
diff --git a/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs b/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
index 3ff1b0702d..5e965a9d04 100644
--- a/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
+++ b/src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
@@ -53,8 +53,16 @@ namespace Avalonia.Controls.Generators
container.SetValue(ContentTemplateProperty, ItemTemplate, BindingPriority.Style);
}
- container.SetValue(ContentProperty, item, BindingPriority.Style);
-
+ if (DisplayMemberBinding is not null)
+ {
+ container.SetValue(StyledElement.DataContextProperty, item, BindingPriority.Style);
+ container.Bind(ContentProperty, DisplayMemberBinding, BindingPriority.Style);
+ }
+ else
+ {
+ container.SetValue(ContentProperty, item, BindingPriority.Style);
+ }
+
if (!(item is IControl))
{
container.DataContext = item;
diff --git a/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs
index c6b0bda9af..4021b8436a 100644
--- a/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
+using Avalonia.Data;
using Avalonia.LogicalTree;
using Avalonia.Reactive;
using Avalonia.VisualTree;
@@ -33,6 +34,12 @@ namespace Avalonia.Controls.Generators
TabControl.ItemTemplateProperty));
}
+ if (Owner.HeaderDisplayMemberBinding is not null)
+ {
+ tabItem.Bind(HeaderedContentControl.HeaderProperty, Owner.HeaderDisplayMemberBinding,
+ BindingPriority.Style);
+ }
+
if (tabItem.Header == null)
{
if (item is IHeadered headered)
diff --git a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
index 4e3deb5552..2d8cb05e03 100644
--- a/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
@@ -76,7 +76,15 @@ namespace Avalonia.Controls.Generators
result.SetValue(Control.ThemeProperty, ItemContainerTheme, BindingPriority.Style);
}
- result.SetValue(ContentProperty, template.Build(item), BindingPriority.Style);
+ if (DisplayMemberBinding is not null)
+ {
+ result.SetValue(StyledElement.DataContextProperty, item, BindingPriority.Style);
+ result.Bind(ContentProperty, DisplayMemberBinding, BindingPriority.Style);
+ }
+ else
+ {
+ result.SetValue(ContentProperty, template.Build(item), BindingPriority.Style);
+ }
var itemsSelector = template.ItemsSelector(item);
diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs
index 345e7fcac8..e9ce7912a7 100644
--- a/src/Avalonia.Controls/ItemsControl.cs
+++ b/src/Avalonia.Controls/ItemsControl.cs
@@ -11,6 +11,7 @@ using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Controls.Utils;
+using Avalonia.Data;
using Avalonia.Input;
using Avalonia.LogicalTree;
using Avalonia.Metadata;
@@ -61,6 +62,23 @@ namespace Avalonia.Controls
public static readonly StyledProperty ItemTemplateProperty =
AvaloniaProperty.Register(nameof(ItemTemplate));
+
+ ///
+ /// Defines the property
+ ///
+ public static readonly StyledProperty DisplayMemberBindingProperty =
+ AvaloniaProperty.Register(nameof(DisplayMemberBinding));
+
+ ///
+ /// Gets or sets the to use for binding to the display member of each item.
+ ///
+ [AssignBinding]
+ public IBinding? DisplayMemberBinding
+ {
+ get { return GetValue(DisplayMemberBindingProperty); }
+ set { SetValue(DisplayMemberBindingProperty, value); }
+ }
+
private IEnumerable? _items = new AvaloniaList