【问题标题】:Cannot bind list of items in GridView column无法绑定 GridView 列中的项目列表
【发布时间】:2016-07-24 07:43:38
【问题描述】:

我正在构建一个应用程序,向用户显示比赛系列的实时结果。我设置数据结构如下:Countries->Leagues->Matches 特别是在 ViewModel 中,我创建了一个可观察的国家集合,如下所示:

private ObservableCollection<Models.Country> _countries = new ObservableCollection<Models.Country>();

public ObservableCollection<Models.Country> Country
{
    get { return _countries; }
}

和模型:

public class Country
{
    public string Name { get; set; }
    public List<League> League { get; set; }
}

public class League
{
    public string Name { get; set; }
    public List<Event> Event { get; set; }
}

Event 类包含每个事件的属性,特别是事件的名称、日期等。

我按如下方式评估这些数据:

Country country = new Country();
country.Name = "Italy";

League league = new League();
league.Name = "Serie A";
League league2 = new League();
league2.Name = "Serie B";

Event @event = new Event();
@event.MatchHome = "Inter";

Event event2 = new Event();
@event.MatchHome = "Milan";

league.Event = new List<Event>(); 
league2.Event = new List<Event>();

league.Event.Add(@event);
league2.Event.Add(event2);

country.League = new List<League>();

country.League.Add(league);
country.League.Add(league2);

lsVm.Country.Add(country); //lsVm contains the ViewModel

您如何看到我创建了一个名为country(意大利)的对象,在本例中将包含两个联赛(意甲)和(意乙)。每个联赛实际上包含一场比赛在玩Serie A -&gt; InterSerie B -&gt; Milan

我将联赛两个国家添加到视图模型中的可观察集合中。直到这里没有问题。问题出在 xaml 中。

所以我在 GroupViews 中组织了所有这些东西,为此我使用 CollectionViewSource,特别是:

<CollectionViewSource Source="{Binding Country}" x:Key="GroupedItems">
       <CollectionViewSource.GroupDescriptions>
            <PropertyGroupDescription PropertyName="Name" />
            <PropertyGroupDescription PropertyName="League.Name" />
       </CollectionViewSource.GroupDescriptions>

上面的代码位于我的 Window.Resources 中,并告诉 CollectionViewSource 组织国家名称和联赛名称相关联的相应联赛。 我有两个这样的 ListView:

<ListView ItemsSource="{Binding Source={StaticResource GroupedItems}}" Name="Playing">
                    <ListView.View>
                        <GridView>
                            <GridViewColumn Header="Date" Width="150" DisplayMemberBinding="{Binding Path = League.Event.MatchDate}"/>
                            <GridViewColumn Header="Minutes" Width="70" DisplayMemberBinding="{Binding Path = League.Event.MatchMinute}"/>
                            <GridViewColumn Header="Home" Width="150" DisplayMemberBinding="{Binding Path = League.Event.MatchHome}"/>
                            <GridViewColumn Header="Score" Width="100" DisplayMemberBinding="{Binding Path = League.Event.MatchScore}"/>
                            <GridViewColumn Header="Away" Width="150" DisplayMemberBinding="{Binding Path = League.Event.MatchAway}"/>
                        </GridView>
                    </ListView.View>
<GroupStyle>
                            <GroupStyle.ContainerStyle>
                                <Style TargetType="{x:Type GroupItem}">
                                    <Setter Property="Template">
                                        <Setter.Value>
                                            <ControlTemplate>
                                                <Expander IsExpanded="True" Background="#4F4F4F" >
                                                    <Expander.Header>
                                                        <StackPanel Orientation="Horizontal" Height="22">
                                                            <TextBlock Text="{Binding Name}" FontWeight="Bold" Foreground="White" FontSize="22" VerticalAlignment="Bottom" />
                                                            <TextBlock Text="{Binding ItemCount}" FontSize="22" Foreground="Orange" FontWeight="Bold" FontStyle="Italic" Margin="10,0,0,0" VerticalAlignment="Bottom" />
                                                            <TextBlock Text=" Leagues" FontSize="22" Foreground="White" FontStyle="Italic" VerticalAlignment="Bottom" />
                                                        </StackPanel>
                                                    </Expander.Header>
                                                    <ItemsPresenter />
                                                </Expander>
                                            </ControlTemplate>
                                        </Setter.Value>
                                    </Setter>
                                </Style>
                            </GroupStyle.ContainerStyle>
                        </GroupStyle>

GroupStyle 包含将包含每场比赛的联赛,现在的问题是我看不到任何联赛和任何比赛,因为该项目在列表中。所以为了显示它们,我应该在 xaml 中写下这段代码:

<PropertyGroupDescription PropertyName="League[0].Name" /> 

修复了GroupStyle中显示联赛名称的BUG 并在 GridView 中:

<GridViewColumn Header="Casa" Width="150" DisplayMemberBinding="{Binding Path = League[0].Event[0].MatchHome}"/>

但这当然只会显示特定项目..而不是项目列表。我需要帮助来解决这种情况,我无法弄清楚。谢谢。

【问题讨论】:

  • 我能理解您的数据源国家>联赛>赛事。现在您要显示什么?你能用一些符号来解释吗?还是有粗略想法的图像?
  • @AnjumSKhan 请在此处查看练习示例:stackoverflow.com/questions/38551511/… 是相关问题,在此问题中还有其他与其他主题相关的详细信息,谢谢

标签: c# wpf xaml


【解决方案1】:

如果您想使用ListView 的分组功能,您必须向它提供您要分组的项目(在您的情况下是联赛)的平面列表,而不是标题项目。 CollectionView 通过指定 GroupDescriptions 为您进行分组。

例如,假设League 类有一个Country 属性:

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>

然后当你绑定列时,你直接绑定到League属性,例如:

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

在组样式中,您可以绑定到Country 属性,就像您所做的那样。

替代解决方案

如果您想在 WPF 中显示任何分层数据,您可以使用为其构建的控件(例如 Xceed 数据网格)或将其与内置 WPF 数据网格的行详细信息一起破解。

这是一个示例 XAML(请注意,它使用您的原始数据结构,没有我上面建议的修改)。这些本质上是相互嵌套的 3 个数据网格。每个网格都有自己的一组列,因此您可以为每个级别(国家、联赛、赛事)定义任何您想要的内容。

<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>

您还需要我使用的转换器的代码:

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;
}

【讨论】:

  • 嗯,您或多或少已经集中了重点,但我有一个可观察的国家/地区集合,其中包含包含比赛的联赛。真正的问题是我无法在 GridViewColumn 标题和 GroupStyle(扩展器)中显示联赛名称和每场比赛的详细信息,因为它们在列表中。
  • 如果您想使用CollectionView 的本机分组支持,您将必须对数据进行稍微不同的建模。您可以创建一个中间层模型,按照我描述的方式排列数据。
  • 我明白你的意思,但是我需要设置哪个结构?因为我需要有国家->联赛->比赛的组织结构
  • 您需要一份所有国家联赛的平面列表,其中每个联赛都有您可以分组的属性(例如Country)。
  • 我已经用一些代码更新了答案。您应该阅读有关 WPF 数据分组的信息 - 您在这里遗漏了一个关键点。
猜你喜欢
  • 2019-08-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-02
  • 2017-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多