diff --git a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ListViewBase.cs b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ListViewBase.cs index 1ad906a631e0..630372ee9993 100644 --- a/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ListViewBase.cs +++ b/src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml_Controls/Given_ListViewBase.cs @@ -1350,6 +1350,35 @@ public async Task When_Selection_Events() list.SelectedIndex = 1; } + [TestMethod] + public async Task When_DisplayMemberPath_Property_Changed() + { + var itemsSource = (new[] { "aaa", "bbb", "ccc", "ddd" }).Select(s => new When_DisplayMemberPath_Property_Changed_DataContext { Display = s }).ToArray(); + + var SUT = new ListView() + { + ItemContainerStyle = BasicContainerStyle, + DisplayMemberPath = "Display", + ItemsSource = itemsSource + }; + + WindowHelper.WindowContent = SUT; + await WindowHelper.WaitForLoaded(SUT); + + var secondContainer = await WindowHelper.WaitForNonNull(() => SUT.ContainerFromIndex(1) as ListViewItem); + await WindowHelper.WaitForLoaded(secondContainer); + + var tb = secondContainer.FindFirstChild(); + Assert.AreEqual("bbb", tb.Text); + + foreach (var item in itemsSource) + { + item.Display = item.Display.ToUpperInvariant(); + } + + await WindowHelper.WaitForResultEqual("BBB", () => tb.Text); + } + private bool ApproxEquals(double value1, double value2) => Math.Abs(value1 - value2) <= 2; private class When_Removed_From_Tree_And_Selection_TwoWay_Bound_DataContext : global::System.ComponentModel.INotifyPropertyChanged @@ -1413,6 +1442,26 @@ protected void RaiseAndSetIfChanged(ref T backingField, T value, [CallerMembe } } } + + private class When_DisplayMemberPath_Property_Changed_DataContext : INotifyPropertyChanged + { + private string _display; + + public event PropertyChangedEventHandler PropertyChanged; + + public string Display + { + get => _display; + set + { + if (value != _display) + { + _display = value; + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Display))); + } + } + } + } } public partial class OnItemsChangedListView : ListView diff --git a/src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsControl.cs b/src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsControl.cs index 4739a88bec53..ff1714af521e 100644 --- a/src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsControl.cs +++ b/src/Uno.UI/UI/Xaml/Controls/ItemsControl/ItemsControl.cs @@ -1046,18 +1046,20 @@ protected virtual void PrepareContainerForItemOverride(DependencyObject element, var styleFromItemsControl = ItemContainerStyle ?? ItemContainerStyleSelector?.SelectStyle(item, element); - object GetContent() + void SetContent(UIElement container, DependencyProperty contentProperty) { var displayMemberPath = DisplayMemberPath; if (string.IsNullOrEmpty(displayMemberPath)) { - return item; + container.SetValue(contentProperty, item); } else { - // TODO: Cache the BindingPath - var b = new BindingPath(displayMemberPath, item) { DataContext = item }; - return b.Value; + container.SetBinding(contentProperty, new Binding + { + Path = displayMemberPath, + Source = item + }); } } @@ -1078,7 +1080,7 @@ object GetContent() if (!isOwnContainer) { - containerAsContentPresenter.Content = GetContent(); + SetContent(containerAsContentPresenter, ContentPresenter.ContentProperty); } } else if (element is ContentControl containerAsContentControl) @@ -1101,7 +1103,7 @@ object GetContent() // Set the datacontext first, then the binding. // This avoids the inner content to go through a partial content being // the result of the fallback value of the binding set below. - containerAsContentControl.DataContext = GetContent(); + SetContent(containerAsContentControl, ContentControl.DataContextProperty); if (!containerAsContentControl.IsContainerFromTemplateRoot && containerAsContentControl.GetBindingExpression(ContentControl.ContentProperty) == null) {