Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding ListView field to a nested list WPF

I've the following classes:

class Event {
int eserc {get;set;}
int type {get;set;}
}

class Sequence {
List<Event> events;
int freq {get;set;}
}

As you can see, I have a list of events inside a Sequence. I have a list of Sequence.
I want to show a ListView with a GridView with the list of sequences. For each sequence I want to have 2 columns, one with the value of the property freq and the other one should have the list of events associated with that sequence. For example: enter image description here
where the first line is related to the first sequence. The color of the rectangle represents the event's type. In the first sequence there are the following events:

  • eserc 1 of type "red"
  • eserc 2 of type "red"
  • eserc 3 of type "green"
  • eserc 4 of type "red"

I know that I have to do the binding to display values, but I don't know how to do it for the sequences, because I should bind the value of the column to the values of the Event objects within each single Sequence.
That's the code that I wrote for the ListView:

<ListView Name="resultsList" Grid.Row="5" Grid.Column="1"
                  Grid.ColumnSpan="3">
    <ListView.View>
                <GridView>

            <GridViewColumn Header="Sequence" Width="450"
                                    DisplayMemberBinding="{Binding events}"/>
            <GridViewColumn Header="Frequence" 
                                    DisplayMemberBinding="{Binding freq}"/>
        </GridView>
    </ListView.View>
</ListView>

Of course, Binding events is wrong because that would work only if it was a string, but that's the idea.
I searched on internet and I think that I should use something like DataTemplate, but I'm not sure about that and I didn't understand well how that works. I understood that it works when the source is an object, but in this case it's a List of objects and I don't know how to get the information.

like image 261
A. Wolf Avatar asked Oct 17 '22 21:10

A. Wolf


1 Answers

To achieve that you need to define another list inside the first GridViewColumn, the list should be horizontal (Edit the ItemsPanelTemplate). You could either a ListView, ListBox or an ItemsControl (looks like the most appropriate).

To draw a Border with the different colors based on the Event's type, you should first, define a custom DataTemplate for the ItemsControl items, and use a DataTrigger to set the color, here the full xaml to do that:

<ListView Name="ResultsList" 
             ItemsSource="{Binding SequenceCollection}">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Sequence" Width="450" >
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <ItemsControl ItemsSource="{Binding Events}">
                                <ItemsControl.ItemsPanel>
                                   <ItemsPanelTemplate>
                                       <StackPanel Orientation="Horizontal"></StackPanel>
                                   </ItemsPanelTemplate>
                               </ItemsControl.ItemsPanel>
                                <ItemsControl.ItemTemplate>
                                    <DataTemplate>
                                        <Border>
                                            <Border.Style>
                                                <Style TargetType="Border">
                                                    <Style.Triggers>
                                                        <DataTrigger Binding="{Binding Type}" Value="red">
                                                            <Setter Property="Background" Value="red"/>
                                                        </DataTrigger>
                                                        <DataTrigger Binding="{Binding Type}" Value="green">
                                                            <Setter Property="Background" Value="Green"/>
                                                        </DataTrigger>
                                                    </Style.Triggers>
                                                </Style>
                                            </Border.Style>
                                            <TextBlock Text="{Binding Eserc, StringFormat='{}{0} '}"></TextBlock>
                                        </Border>
                                    </DataTemplate>
                                </ItemsControl.ItemTemplate>
                            </ItemsControl>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="Frequence" 
                                DisplayMemberBinding="{Binding Freq}"/>
            </GridView>
        </ListView.View>
    </ListView>

The SequenceCollection:

    private ObservableCollection<Sequence> _sequenceCollection =new ObservableCollection<Sequence>()
    {
        new Sequence(){Events = new ObservableCollection<Event>()
        {
            new Event(){Eserc=1, Type = "red"},
            new Event(){Eserc=2, Type = "red"},
            new Event(){Eserc=3, Type = "green"},
            new Event(){Eserc=4, Type = "red"},
        },Freq = 3}
    };
    public ObservableCollection<Sequence> SequenceCollection
    {
        get { return _sequenceCollection; }
        set
        {
            if (Equals(value, _sequenceCollection)) return;
            _sequenceCollection = value;
            OnPropertyChanged();
        }
    }

And here are you classes with the needed adjacements:

public class Event
{
    public int Eserc { get; set; }
    public string Type { get; set; }
}

public class Sequence
{
    public ObservableCollection<Event> Events { get; set; }
    public int Freq { get; set; }
}

Output:

shot

On the side:

  1. make sure to define public properties to be able to bind them correctly
  2. use the naming convention
  3. use ObservableCollection instead of List (they implement ICollectionChanged which is handy for change notifications)
  4. don't forget to implement the INotifyPropertyChanged Interface
like image 183
SamTh3D3v Avatar answered Oct 30 '22 00:10

SamTh3D3v