我正在构建一个应用程序,向用户显示匹配系列的实时结果。我按如下方式设置数据结构: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 -> Inter
和Serie B -> Milan
我将联盟中的两个国家加入,最后将国家添加到viewmodel中的可观察集合中。直到这里没问题。这个问题出现在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中的联盟名称的错误 并在GridView中:
<GridViewColumn Header="Casa" Width="150" DisplayMemberBinding="{Binding Path = League[0].Event[0].MatchHome}"/>
但这当然只会显示特定项目..而不是项目列表。我需要帮助来解决这个问题,我无法弄明白。感谢。
答案 0 :(得分: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;
}