1
votes

I have an enumerable datasource that I want to bind to a some control in Xamarin Forms.

I want the layout to look something like -

ColA | ColB | ColC | ColD
  3      4      1     6
 15     25     62    26

Just a standard table with a header.

I have tried the ListView but it doesn't support headers. I've tried TableLayout but it doesn't support binding to a datasource.

Have I missed something or is there some other control I should use.

3
You can also render that with a Grid and populate the rows with labels with bindings if your row count is relatively low (n<10?) otherwise performance would be an issueSten Petrov
The TableLayout can be bound, but not in this way and it won't work for this purpose. The Grid suggestion below is your best bet, or HTML and WebView.Nick Daniels

3 Answers

0
votes

Yeah theres no control out of the box for it, here's a one way to hack it:

Create a grid that has a row for your header (4 columns), the next row has a listview with a viewcell for your items, then you use a viewcell template, and in your template you have the grid with 4 columns ,and 4 labes ( 1 each column) just like the header, now the trick here is how will you bind 4 values in 1 viewcell, my sugestions is having a object like 'Something' that has Prop1, Prop2, Prop3, Prop4 , and now you bind label1 to Prop1, label2 to Prop2 and so one, So when you create your datasource it will be something like:

var list = List<Something>();
list.Add(new Something() { Prop1 = 3, Prop2 = 4, Prop3 = 1, Prop4 = 6});
list.Add(new Something() { Prop1 = 15, Prop2 = 25, Prop3 = 62, Prop4 = 26});

this should accomplish what you need..

0
votes

As Stephane Delcroix mentioned in this other StackOverflow question:-

"Horizontal ListView Xamarin.Forms"

The ListView does not natively support horizontal orientation, so you couldn't use this as your are ideally wanting to bind to an IEnumerable datasource.

There is another hack method mentioned in the following post:-

"How to adjust size of Horizontal ListView in Xamarin.Forms?"

that suggests to use Rotation to get around this, although this will more than likely be quite cumbersome and problematic in cases as rotation will apply outside a normal View bounds, unless it is a square dimension.

That would allow you to use your bindable datasource however by using the ItemTemplate property of the ListView and creating your DataTemplate with other control bindings specified in it.

It is however not ideal with the rotation hack, and personally I wouldn't even consider it.

The best method, at present, would be to do as Rui is mentioning, creating some kind of Grid of equal columns and do your formatting within.

You could also achieve this with a StackLayout specifying a specific WidthRequest for each of the child Views and then do your formatting from within each child View.

Should you need to display more than 4 columns, or more information than would fit on a typical device screen width, then you may want to put a ScrollView as the parent of this Grid or StackLayout, so you can view everything with better spacing rather than cramming everything in.

As a final alternative - you could write your own custom-renderer to support a horizontal ListView with a bindable datasource.

0
votes
<Grid x:Name="dgvEmp">
    <Grid.RowDefinitions>

    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>

    </Grid.ColumnDefinitions>
 </Grid>

 List<Employee> lstEmp;
        public Gridbasic()
        {
            InitializeComponent();
          lstEmp=  new List<Employee>()
            {
                new Employee()
                {
                    EmpId=1,EmpName="Test1",EmpSalary=12345
                },
                new Employee()
                {
                    EmpId=2,
                    EmpName="Test2",
                    EmpSalary=12345
                },
                new Employee()
                {
                    EmpId=3,
                    EmpName="Test3",
                    EmpSalary=12334
                }
            };
        dgvEmp.Children.Add(new Label() {Text="EmpName" }, 0, 0);
        dgvEmp.Children.Add(new Label() { Text = "EmpSal" }, 1, 0);
       
        for(int i=0,j = 1;  i <lstEmp.Count; i++)
            {
                Label lbl = new Label()
                {
                    Text = lstEmp[i].EmpName
                };
                Label llblEmpSal = new Label()
                {
                    Text = lstEmp[i].EmpSalary.ToString()
                };

                dgvEmp.Children.Add(lbl, 0, j);
                dgvEmp.Children.Add(llblEmpSal, 1, j);
                j++;
            }

        }