5

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.

SamTh3D3v
  • 9,854
  • 3
  • 31
  • 47
A. Wolf
  • 1,309
  • 17
  • 39
  • 3
    Use a DataTemplate to show your nested list in the cells of the first column (Read documentation for [GridViewColumn.CellTemplate](https://msdn.microsoft.com/en-us/library/system.windows.controls.gridviewcolumn.celltemplate(v=vs.110).aspx), and for an example using CellTemplate property, see here: https://stackoverflow.com/questions/4725352/wpf-listview-with-gridviewcolumn-and-datatemplate) –  Mar 20 '18 at 18:11
  • 1
    Oh, and the coloring you can realize with a DataTrigger changing color depending on the value of the property the DataTrigger is bound to (http://www.wpf-tutorial.com/styles/trigger-datatrigger-event-trigger/) –  Mar 20 '18 at 18:19
  • 3
    Lastly, +1 for the excellent presentation of your question, including a doodle to make it so easy to understand what your goal is. Wish people would more upvote well-formed questions than just only downvote badly written low-effort questions. –  Mar 20 '18 at 18:30
  • 3
    I just remember that i forgot to add one thing: "_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._". Oh, you already know. See, you already know how to show a List: with a ListBox/ListView. So, then, how would you show your List in the column cell? Yup, you guessed it; again, with a ListBox/ListView... ;-) –  Mar 20 '18 at 18:57
  • how many items can contains the `events`? – FoggyFinder Mar 20 '18 at 20:49
  • Thank you @elgonzo! I'm trying to implement what you suggest, but with many issues.. I think I understood the main idea, but the implementation seems hard to do to me.. – A. Wolf Mar 21 '18 at 00:53

1 Answers1

3

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
SamTh3D3v
  • 9,854
  • 3
  • 31
  • 47
  • Wow! Thank you for your answer! I tried to implement it, but I had some problems.. First of all, it gives me an error on the definition of the SequenceCollection property, saying that "the type of property 'ObservableCollection is less accessible than property "Results.SequenceCollection" (Where Results is the class of the window containing the SequenceCollection). – A. Wolf Mar 21 '18 at 00:46
  • Another thing, implementing the INotifyPropertyChanged interface in the OnPropertyChanged() method what I have to do? (I did it in the Results class) – A. Wolf Mar 21 '18 at 00:51
  • 1
    Regarding the first problem, just make sure that the property is public. And for the notification change, whenever you want that changes on the property reflects on the ui, call onepropertychanged() in the property. – SamTh3D3v Mar 21 '18 at 07:22
  • Thank you @Usama, for the property the problem was that classes Event and Sequence were not public. For the INotifyPropertyChanged instead I can figure out how to do that, I think that's why results don't appear. I followed this tutorial http://www.wpf-tutorial.com/data-binding/responding-to-changes/, implemententing that interface for Sequence and Event class. – A. Wolf Mar 21 '18 at 08:21
  • Good :)), pls accept the answer if you found it useful. – SamTh3D3v Mar 21 '18 at 08:31
  • It was useful, but I wasn't able to make it run :( it was exactly what I want but the sequence does not appear! Can you post the .cs code of the whole window which contains the SequenceCollection property? Because for sure I'm doing some stupid mistakes. Thanks!! – A. Wolf Mar 21 '18 at 08:40
  • Will do, once I am out of the train – SamTh3D3v Mar 21 '18 at 08:45
  • Thank you so much! When you have time to do it of course :) – A. Wolf Mar 21 '18 at 08:46
  • 1
    Thank you so much for your help! With the whole code I solved the problem!! Thank you for your pacience :) – A. Wolf Mar 21 '18 at 10:09
  • 1
    This is the most helpful answer with full functioning source code. Very nice. +1 – Hao Nguyen Aug 21 '19 at 18:38