ListView renders all rows with the same data

LapsusLapsus USMember ✭✭

I created a content page, that will show data in ListView, based on the data it recieves. Since data will have different amount of columns, I created the DataTemplate in C#. However, when I bind my collection to the created list, all rows are rendered with the same data (usually from the last row) but if I select one row, the selected item will be correct and data of this selected object will differ from data that is shown on the list.

So I will provide a little bit of my code that will hopefully show where I am wrong.

I have a special row class and header class, that looks like this:

public class DynamicListRow
{
    public string Id { get; set; }
    public List<string> Columns { get; set; }

    public DynamicListRow(string id, List<string> cols)
    {
        Id = id;
        Columns = cols;
    }
}

public class DynamicListHeader
{
    public int Width { get; set; }
    public string Text { get; set; }

    public DynamicListHeader(string text, int width)
    {
        Width = width;
        Text = text;
    }
}

Then in the XAML of my content page, I define a ListView like so:

<StackLayout x:Name="ListContentWrapper">
    <ListView x:Name="InventoryListView" RowHeight="20" HeightRequest="120" ItemSelected="ListItemSelected">
        <!-- Item template is generated in code -->
    </ListView>
</StackLayout>

This is the base of ListView, that I then "create" inside the class on my page.

var rowGrid = new Grid();
rowGrid.RowDefinitions.Add(new RowDefinition
{
    Height = new GridLength(1, GridUnitType.Star)
});
int colIndex = 0;
foreach (DynamicListHeader col in Headers)
{
    //Add column defition for item row
    rowGrid.ColumnDefinitions.Add(new ColumnDefinition
    {
        Width = new GridLength(col.Width, GridUnitType.Star)
    });
    //Add binding for item row column
    var columnLabel = new Label();
    columnLabel.SetBinding(Label.TextProperty, $"Columns[{colIndex}]");
    //Add label to item row grid
    rowGrid.Children.Add(columnLabel, colIndex, 0);
    colIndex++;
}
//After the grid is created, I assign it to the ListView
var dataTemplate = new DataTemplate(() =>
{
    return new ViewCell { View = rowGrid };
});
InventoryListView.ItemTemplate = dataTemplate;
//And finally I assign data to the ListView
InventoryListView.ItemsSource = Rows;

So now we pass some data to the list, for example:

var Headers = new List<DynamicListHeader>
{
    new DynamicListHeader("ColumnA", 50),
    new DynamicListHeader("ColumnB", 50)
};

var Rows = new List<DynamicListRow>
{
    new DynamicListRow("1", "A", "AAA"),
    new DynamicListRow("2", "B", "BBB"),
    new DynamicListRow("3", "C", "CCC")
};

The resulting list is now showing 3 lines but all the lines are the same (the last row):
3 C CCC
3 C CCC
3 C CCC

But when I select for example the first row, the object inside the method ListItemSelected will be correct "1 A AAA".
So the SelectedItem and what is shown differ (selected item is correct, but rendered item is wrong).

I am guessing there is something fishy going on with my binding inside ViewCell, but I can't figure it out. There is also something interesting I noticed. If I make my list height enough only for 2 rows, buth rows will be rendered as:
2 B BBB
2 B BBB

But when I scroll to the 3rd item, all 3 items change to 3rd item.

Does anyone have any ideas how can I fix my list, so it will be rendered correctly?

BR,
Denis

Best Answer

Answers

  • LapsusLapsus USMember ✭✭

    @LandLu It works correctly now, thank you :) I was trying to do everything inside one for loop in order to optimize performance, but since I won't have a large amount of columns this shouldn't be a problem.

Sign In or Register to comment.