Cannot bind list of items in GridView column

前端 未结 1 1484
渐次进展
渐次进展 2021-01-07 12:58

I\'m building an application that show to user the live result of a matches series. I setup the structure of data as follows: Countries->Leagues->Matches

相关标签:
1条回答
  • 2021-01-07 13:50

    If you want to use the ListView's grouping abilities, you have to provide it a flat list of the items you want to group (in your case, the leagues), not the header items. The CollectionView does the grouping for you by specifying GroupDescriptions.

    For example, assuming the League class has a Country property:

    class ViewModel
    {
        public ObservableCollection<Models.Country> Country { get; }
    
        public IEnumerable<League> AllLeagues => Country.SelectMany(c => c.Leagues);
    }
    
    public class League
    {
        public string Name { get; set; }
        public List<Event> Event { get; set; }
        // add Country here
        public Country Country { get; set; }
    }
    
    class 
    
    <CollectionViewSource Source="{Binding AllLeagues}" x:Key="GroupedItems">
       <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription PropertyName="Country" />
       </CollectionViewSource.GroupDescriptions>
    

    Then when you bind the columns, you bind directly to League properties, e.g.:

    <GridViewColumn Header="Date" DisplayMemberBinding="{Binding Path=Event.MatchDate}"/>
    

    And in the group style you can bind to Country properties, as you've done.

    Alternative solution

    If you want to display any hierarchical data in WPF you can either use a control that was built for it (such as the Xceed data grid) or hack it together with the built-in WPF data grid's row details.

    Here's a sample XAML for this (note it uses your original data structures without the modifications I suggested above). These are essentially 3 data grids nested within each other. Each grid has its own set of columns, so you can define anything you want for each level (Country, League, Event).

    <Window x:Class="WpfApp.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            mc:Ignorable="d"
            xmlns:app="clr-namespace:WpfApp"
            d:DataContext="{d:DesignData ViewModel}">
        <FrameworkElement.Resources>
            <app:VisibilityToBooleanConverter x:Key="VisibilityToBooleanConverter" />
            <DataTemplate x:Key="HeaderTemplate">
                <Expander IsExpanded="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=DataGridRow}, Path=DetailsVisibility, Converter={StaticResource VisibilityToBooleanConverter}}" />
            </DataTemplate>
            <Style x:Key="DataGridStyle"
                   TargetType="DataGrid">
                <Setter Property="RowHeaderTemplate"
                        Value="{StaticResource HeaderTemplate}" />
                <Setter Property="RowDetailsVisibilityMode"
                        Value="Collapsed" />
                <Setter Property="AutoGenerateColumns"
                        Value="False" />
                <Setter Property="IsReadOnly"
                        Value="True" />
            </Style>
        </FrameworkElement.Resources>
        <Grid>
            <DataGrid ItemsSource="{Binding Country}"
                      Style="{StaticResource DataGridStyle}">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Name"
                                        Binding="{Binding Name}" />
                </DataGrid.Columns>
                <DataGrid.RowDetailsTemplate>
                    <DataTemplate>
                        <DataGrid ItemsSource="{Binding League}"
                                  Style="{StaticResource DataGridStyle}">
                            <DataGrid.Columns>
                                <DataGridTextColumn Header="Name"
                                                    Binding="{Binding Name}" />
                            </DataGrid.Columns>
                            <DataGrid.RowDetailsTemplate>
                                <DataTemplate>
                                    <DataGrid ItemsSource="{Binding Event}"
                                              AutoGenerateColumns="False"
                                              IsReadOnly="True">
                                        <DataGrid.Columns>
                                            <DataGridTextColumn Header="Match Home"
                                                                Binding="{Binding MatchHome}" />
                                        </DataGrid.Columns>
                                    </DataGrid>
                                </DataTemplate>
                            </DataGrid.RowDetailsTemplate>
                        </DataGrid>
                    </DataTemplate>
                </DataGrid.RowDetailsTemplate>
            </DataGrid>
        </Grid>
    </Window>
    

    You'll also need the code for the converter I used:

    public class VisibilityToBooleanConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            => value as Visibility? == Visibility.Visible;
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            => value as bool? == true ? Visibility.Visible : Visibility.Collapsed;
    }
    
    0 讨论(0)
提交回复
热议问题