0

I develop my App UI with XAML and in Background I run a C# program.

To make it bit easier to explain: Lets say the program shall Display Paramters in a ListView/Grid.

  1. Column 1 is the Parameter Name (string)
  2. Column 2 is the Parameter Value (string or string [,])

The Parameter Value can be a single value (displayed as Label) or a vector/matrix (displayed as Grid inside this cell). I have no idea how I can also add a other grid here with unknown column number, the number will be different for each paramter.

All the Parameters are in a List and loaded with a ItemSource + DisplayMemberBinding dynamically.

So what I Need: - A Grid in a DataTemplate - A Grid with unknown number of rows

<DataTemplate x:Key="labelTemplate">
  <Label Content="{Binding Path=Value}" Width="Auto"></Label>
</DataTemplate>

<DataTemplate x:Key="table2DTemplate">
</DataTemplate>

<local:ParameterTemplateSelector 
  x:Key="parameterTemplateSelector" 
  LabelTemplate="{StaticResource labelTemplate}" 
  Table2DTemplate ="{StaticResource table2DTemplate}"/>

MY Datatempaltes + TemplateSelector:

<ListView ItemsSource="{Binding Parameters}" Margin="10,156,10.286,10.429" x:Name="listBox1" FontSize="8" Background="White" Foreground="Black" BorderBrush="#FF60EFBB">
  <ListView.View>
    <GridView>
            <GridViewColumn 
                Header="Name" 
                Width="Auto"
                DisplayMemberBinding="{Binding Name}" />
            <GridViewColumn 
                Header="Value" 
                Width="Auto"
                CellTemplateSelector="{StaticResource parameterTemplateSelector}" />
            <GridViewColumn 
                Header="Unit" 
                Width="Auto"
    </GridView>
  </ListView.View>
</ListView>

1 Answers1

0

Here's what you want to do. The value converter is necessary because you can't bind an ItemsControl (or any of its subclasses like ListBox, ListView, etc.) to a two-dimensional array. So we convert the 2D array into a List<List<String>> and display that in nested ItemsControls. The converter is included below.

This could be simplified if you're willing to use List<List<String>> throughout your code as a substitute for string[,], but that may not be practical.

<DataTemplate x:Key="table2DTemplate">
    <ItemsControl 
        ItemsSource="{Binding Value, Converter={StaticResource ListOfListsFrom2DArray}}"
        >
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <ItemsControl ItemsSource="{Binding}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Label Content="{Binding}" />
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <UniformGrid
                                Rows="1"
                                />
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                </ItemsControl>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</DataTemplate>

Converter. There's not much here but a LINQ expression I stole from another StackOverflow answer.

public class ListOfListsFrom2DArray : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var values = value as string[,];

        //  https://stackoverflow.com/a/37458182/424129
        var result = values.Cast<string>()
            // Use overloaded 'Select' and calculate row index.
            .Select((x, i) => new { x, index = i / values.GetLength(1) })
            // Group on Row index
            .GroupBy(x => x.index)
            // Create List for each group.  
            .Select(x => x.Select(s => s.x).ToList())
            .ToList();

        return result;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}