Search code examples
c#xamlwin-universal-appcollectionviewsourceuwp

Using d:DesignInstance with CollectionViewSource


I am using d:DesignInstance to get design-time data in the designer. My model looks like this (simplified):

interface IModel {
  public ObservableCollection<IConversation> OpenConversations { get; }
}

enum ConversationType {
  Channel, IM
}

interface IConversation {
  public string Name { get; }
  public ConversationType ConversationType { get; }
}

Then I have a mock-model with a couple of entries in the OpenConversations property. This works great when used as the ItemsSource in my ListView. My simplified XAML view looks like this:

<Page d:DataContext="{d:DesignInstance Type=mocks:MockModel, IsDesignTimeCreatable=True}">
  <ListView ItemsSource="{Binding OpenConversations}"/>
</Page>

The above example works as expected and I get design time data.

However now I would like to add grouping in my ListView using CollectionViewSource so I added the following to my XAML:

<Page.Resources>
  <CollectionViewSource x:Name="OpenConversations" IsSourceGrouped="True" />
</Page.Resources>

And changed the ListView to:

<ListView ItemSource="{StaticResource OpenConversations}" />

What I cannot really figure out though is how to get the design data into the CollectionViewSource, I tried the following but it doesn't work:

<CollectionViewSource ... Source="{Binding OpenConversations}" />

According to the documentation at https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh780627.aspx I need to (in the code-behind) assign CollectionViewSource.Source = from conversation in OpenConversations group by conversation.ConversationType into group select group. But I cannot figure out how to do that using design-time data.


Solution

  • First try to define how a group shoud look I mean title of group ,and many more

    public class  Group<T> : ObservableCollection<T>, INotifyPropertyChanged
    {
      public Group(string name,IEnumerable<T> items):base(items)
       { Name=name;
       }
      //more ...
    }
    

    This class is for more than static data ,it handles changing data. Now if you use MVVM model define in your viewmodel(home) a property ListGroup (name how you desire) of type new ObservableCollection> PS not real code just mockup to give an ideea.

     var s = from val in OpenConversations 
             group val by val.Conversationb into g 
             select new Group<IConversation>(g.Key.ToString(), g);
     GroupList = new ObservableCollection<Group<IConversation>>(s);
    

    Now create a just like you did before a CollectionViewSource in resouce

        <CollectionViewSource x:Key="cvs" IsSourceGrouped="True" Source="{Binding Source={StaticResource home},Path=GroupList}"/>
    
          <ListView ItemsSource="{Binding Source={StaticResource cvs}}">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Background="Salmon" Width="100" Height="100">
                        <TextBlock  Text="{Binding Name}"/>
                    </StackPanel>
                </DataTemplate>              
            </ListView.ItemTemplate>
            <ListView.GroupStyle>
                <GroupStyle >
                    <GroupStyle.HeaderTemplate>
                        <DataTemplate>
                            <Grid Background="LightGray"  >
                                <TextBlock Text='{Binding Name}' Foreground="Black" Margin="10"
                               Style="{StaticResource SubheaderTextBlockStyle}" />
                            </Grid>
                        </DataTemplate>
                    </GroupStyle.HeaderTemplate>
                </GroupStyle>
            </ListView.GroupStyle>               
        </ListView>
    

    See how a define GroupSyle you add more properties in here It work best for complete control i'm using it in w10 app. Plus a has a partial design time helps(Shows only the list) :)) Not showing the header of group(GroupView)