无法绑定GridView列中的项目列表 [英] Cannot bind list of items in GridView column
问题描述
我正在构建一个应用程序,向用户显示比赛系列的实时结果.我将数据的结构设置如下: Countries-> Leagues-> Matches
特别是在ViewModel中,我创建了一个可观察到的国家/地区集合,如下所示:
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
In particular in the ViewModel I've created an observable collection of countries as follows:
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类包含每个事件的属性,尤其是事件的名称,日期等.
the class Event contains the properties of each event, in particular the name of the event, the date and so on..
我按如下方式评估这些数据:
I valorize this data as follows:
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
(意大利)的对象,在这种情况下,该对象将包含两个联赛(意甲)和(联赛B).每个联赛实际上在玩 Serie A->中包含一场比赛.Inter
和 Serie B->米兰
How you can see I create an object called country
(Italy) that will contains in this case two leagues (Serie A) and (Serie B). Each league contains one match actually in playing Serie A -> Inter
and Serie B -> Milan
我将联盟两个国家/地区,最后一个国家/地区添加到视图模型的可观察集合中.到这里为止没有问题.问题出在xaml中.
I add the league two the country, and finally the country to the observable collection in the viewmodel. Until here no problem. The problem's come in the xaml.
因此,我已经在GroupViews中组织了所有这些内容,为此,我正在使用CollectionViewSource,尤其是:
So I've organized all of this stuff inside of GroupViews, for doing this I'm using a CollectionViewSource, in particular:
<CollectionViewSource Source="{Binding Country}" x:Key="GroupedItems">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="Name" />
<PropertyGroupDescription PropertyName="League.Name" />
</CollectionViewSource.GroupDescriptions>
上面的代码位于我的Window.Resources中,并告诉CollectionViewSource为国家名称和联赛名称组织相关的各个联赛.我有两个这样的ListView:
the code above is located in my Window.Resources, and tell to CollectionViewSource to organize for country name and leagues name the respective leagues associated. I've two ListView as this:
<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中编写以下代码:
The GroupStyle contains the leagues that will contains each match, now the problem is that I can't see any league and any match 'cause this item are inside of a list. So for display them I should write in the xaml this code:
<PropertyGroupDescription PropertyName="League[0].Name" />
此修复了将联赛名称显示在GroupStyle中的错误并在GridView中:
this fix the bug of the league name displayed into GroupStyle and in the GridView:
<GridViewColumn Header="Casa" Width="150" DisplayMemberBinding="{Binding Path = League[0].Event[0].MatchHome}"/>
但是,这当然只会显示特定的项目,而不显示项目列表.我需要帮助来解决这种情况,我无法弄清楚.谢谢.
but this of course will display only the specific item.. not the list of items. I need help to fix this situation, I cannot figure out. Thanks.
推荐答案
如果要使用 ListView
的分组功能,则必须为其提供您想要的项目的简单列表组(在您的情况下是联赛),而不是标题项. CollectionView
通过指定 GroupDescriptions
为您进行分组.
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
.
例如,假设 League
类具有 Country
属性:
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>
然后,当您绑定列时,直接绑定到 League
属性,例如:
Then when you bind the columns, you bind directly to League
properties, e.g.:
<GridViewColumn Header="Date" DisplayMemberBinding="{Binding Path=Event.MatchDate}"/>
并且按照组的样式,您可以绑定到 Country
属性,
And in the group style you can bind to Country
properties, as you've done.
如果要在WPF中显示任何分层数据,则可以使用为其构建的控件(例如Xceed数据网格),也可以将其与内置WPF数据网格的行详细信息一起修改.
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.
这是一个示例XAML(请注意,它使用了您的原始数据结构,没有我上面建议的修改).这些实际上是彼此嵌套的3个数据网格.每个网格都有自己的一组列,因此您可以为每个级别定义任何内容(国家,联赛,赛事).
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;
}
这篇关于无法绑定GridView列中的项目列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!