Skip to content

Commit

Permalink
fix(listview): [iOS] Adjust datacontext for header/footer for ListView
Browse files Browse the repository at this point in the history
  • Loading branch information
jeromelaban committed Jul 19, 2023
1 parent 54041db commit d6de226
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2933,6 +2933,100 @@ private sealed class AlwaysEqualClass : IEquatable<AlwaysEqualClass>
[TestMethod]
public async Task When_Items_Are_Equal_But_Different_References_FlipView() => await When_Items_Are_Equal_But_Different_References_Common(new FlipView());

public record When_Header_DataContext_Model(string MyText);

[TestMethod]
[RunsOnUIThread]
public async Task When_Header_DataContext()
{
TextBlock header = new TextBlock { Text = "empty" };
TextBlock header2 = new TextBlock { Text = "empty" };

header.DataContextChanged += (s, e) => {
e.ToString();
};

var SUT = new ListView()
{
ItemContainerStyle = BasicContainerStyle,
Header = new StackPanel
{
Background = new SolidColorBrush(Colors.Red),
Children = {
header,
header2,
}
}
};

header.SetBinding(TextBlock.TextProperty, new Binding { Path = new PropertyPath("MyText") });
header2.SetBinding(TextBlock.TextProperty, new Binding { Path = new PropertyPath(".") });

WindowHelper.WindowContent = SUT;
await WindowHelper.WaitForIdle();

var source = new[] {
new ListViewItem(){ Content = "item 1" },
};

SUT.ItemsSource = source;
await WindowHelper.WaitForIdle();

Assert.IsNull(header.DataContext);

SUT.DataContext = new When_Header_DataContext_Model("test value");
await WindowHelper.WaitForIdle();

Assert.AreEqual(SUT.DataContext, header.DataContext);
Assert.AreEqual("test value", header.Text);
Assert.AreEqual(SUT.DataContext, header2.DataContext);
Assert.AreEqual(header2.DataContext.ToString(), header2.Text);
}

[RunsOnUIThread]
[TestMethod]
public async Task When_Footer_DataContext()
{
TextBlock header = new TextBlock { Text = "empty" };
TextBlock header2 = new TextBlock { Text = "empty" };

var SUT = new ListView()
{
ItemContainerStyle = BasicContainerStyle,
Footer = new StackPanel
{
Background = new SolidColorBrush(Colors.Red),
Children = {
header,
header2,
}
}
};

header.SetBinding(TextBlock.TextProperty, new Binding { Path = new PropertyPath("MyText") });
header2.SetBinding(TextBlock.TextProperty, new Binding { Path = new PropertyPath(".") });

WindowHelper.WindowContent = SUT;
await WindowHelper.WaitForIdle();

var source = new[] {
new ListViewItem(){ Content = "item 1" },
};

SUT.ItemsSource = source;
await WindowHelper.WaitForIdle();

Assert.IsNull(header.DataContext);

SUT.DataContext = new When_Header_DataContext_Model("test value");
await WindowHelper.WaitForIdle();

Assert.AreEqual(SUT.DataContext, header.DataContext);
Assert.AreEqual("test value", header.Text);
Assert.AreEqual(SUT.DataContext, header2.DataContext);
Assert.AreEqual(header2.DataContext.ToString(), header2.Text);
}

private async Task When_Items_Are_Equal_But_Different_References_Common(Selector sut)
{
var obj1 = new AlwaysEqualClass();
Expand Down
18 changes: 16 additions & 2 deletions src/Uno.UI/UI/Xaml/Controls/ListViewBase/ListViewBaseSource.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ public override void CellDisplayingEnded(UICollectionView collectionView, UIColl
{
key.IsDisplayed = false;

// Reset the parent that may have been set by
// GetBindableSupplementaryView for header and footer content
key.Content.SetParent(null);

if (_onRecycled.TryGetValue(key, out var actions))
{
foreach (var a in actions) { a(); }
Expand Down Expand Up @@ -388,8 +392,18 @@ private UICollectionReusableView GetBindableSupplementaryView(
supplementaryView.Content = content
.Binding("Content", "");
}
supplementaryView.Content.ContentTemplate = template;
supplementaryView.Content.DataContext = context;

if (elementKind == NativeListViewBase.ListViewFooterElementKindNS || elementKind == NativeListViewBase.ListViewHeaderElementKindNS)
{
supplementaryView.Content.SetParent(Owner.XamlParent);
supplementaryView.Content.Content = context;
}
else
{
supplementaryView.Content.ContentTemplate = template;
supplementaryView.Content.DataContext = context;
}

if (style != null)
{
supplementaryView.Content.Style = style;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,9 @@ public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int positi
}

var isGroupHeader = parent.GetIsGroupHeader(position);
if (isGroupHeader || parent.GetIsHeader(position) || parent.GetIsFooter(position))
var isHeader = parent.GetIsHeader(position);
var isFooter = parent.GetIsFooter(position);
if (isGroupHeader || isHeader || isFooter)
{
var item = parent.GetElementFromDisplayPosition(position);

Expand All @@ -90,11 +92,23 @@ public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int positi

var dataTemplate = GetDataTemplateFromItem(parent, item, viewType, isGroupHeader);

container.DataContext = item;
container.ContentTemplate = dataTemplate;
if (container.GetBindingExpression(ContentControl.ContentProperty) == null)

if (!isHeader && !isFooter)
{
container.DataContext = item;
container.ContentTemplate = dataTemplate;
if (container.GetBindingExpression(ContentControl.ContentProperty) == null)
{
container.SetBinding(ContentControl.ContentProperty, new Binding());
}
}
else
{
container.SetBinding(ContentControl.ContentProperty, new Binding());
// When showing the header/footer, the datacontext must be the listview's
// datacontext. We only need to se the content of the container, not its
// datacontext.

container.Content = item;
}
}
else if (viewType == IsOwnContainerType)
Expand Down

0 comments on commit d6de226

Please sign in to comment.