WPF ListView绑定自定义集合无数据显示问题求助
问题描述
用户的WPF ListView绑定ViewModel的ObservableCollection<Player>后无数据显示,相关代码如下:
XAML代码
<ListView x:Name="listviewPlayers" ItemsSource="{Binding Players}" Height="200"> <ListView.View> <GridView> <GridViewColumn Width="235"> <GridViewColumn.Header> <Label Grid.Column="2" Content ="Name" Foreground="Black" FontSize="10"></Label> </GridViewColumn.Header> </GridViewColumn> <GridViewColumn Width="235"> <GridViewColumn.Header> <Label Grid.Column="1" Content ="Score" Foreground="Black" FontSize="10"></Label> </GridViewColumn.Header> </GridViewColumn> <GridViewColumn Width="235"> <GridViewColumn.Header> <Label Grid.Column="0" Content ="Games" Foreground="Black" FontSize="10"></Label> </GridViewColumn.Header> </GridViewColumn> </GridView> </ListView.View> <ListView.ItemTemplate> <DataTemplate DataType="local:MainPageViewModel"> <Grid Height="25"> <Grid.ColumnDefinitions> <ColumnDefinition /> <ColumnDefinition /> <ColumnDefinition /> </Grid.ColumnDefinitions> <Label Content="{Binding Name}" FontWeight="Bold" FontSize="10" Foreground="Black"> </Label> <Label Grid.Column="1" Content="{Binding CurrentScore}" FontSize="10" HorizontalContentAlignment="Center" Foreground="Black"> </Label> <Label Grid.Column="2" Content="{Binding GamesWon}" HorizontalContentAlignment="Center" FontSize="10" Foreground="Black"> </Label> </Grid> </DataTemplate> </ListView.ItemTemplate> </ListView>
ViewModel代码
public ObservableCollection<Player> Players { get { return players; } set { players = value; foreach (Player p in players) { PlayerNames.Add(p.Name); } PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Players")); } }
Player实体类
public class Player : INotifyPropertyChanged { public event PropertyChangedEventHandler? PropertyChanged; private string name = ""; public string Name { get { return name; } set { name = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name")); } } private string currentScore = "0"; public string CurrentScore { get { return currentScore; } set { currentScore = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CurrentScore")); } } private string gamesWon = "0"; public string GamesWon { get { return gamesWon; } set { gamesWon = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("GamesWon")); } } }
用户已设置设计时DataContext:
d:DataContext="{d:DesignInstance Type=local:MainPageViewModel}"
问题分析与解决建议
1. DataTemplate的DataType错误
ListView的ItemsSource绑定的是Players(ObservableCollection<Player>),每个列表项的数据上下文是Player对象,而非MainPageViewModel。但你把DataTemplate的DataType设为了local:MainPageViewModel,导致绑定无法匹配Player的属性。
修正:将DataTemplate的DataType改为local:Player:
<DataTemplate DataType="local:Player">
2. GridView与ItemTemplate冲突
当ListView使用ListView.View指定GridView时,全局的ItemTemplate会被忽略。GridView需要通过DisplayMemberBinding或CellTemplate定义列内容,而非使用ItemTemplate。当前写法同时定义两种布局规则,导致内容无法渲染。
两种修正方案:
方案一:保留GridView,用CellTemplate定义列内容
<ListView x:Name="listviewPlayers" ItemsSource="{Binding Players}" Height="200"> <ListView.View> <GridView> <GridViewColumn Width="235"> <GridViewColumn.Header> <Label Content ="Name" Foreground="Black" FontSize="10"></Label> </GridViewColumn.Header> <GridViewColumn.CellTemplate> <DataTemplate DataType="local:Player"> <Label Content="{Binding Name}" FontWeight="Bold" FontSize="10" Foreground="Black"/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Width="235"> <GridViewColumn.Header> <Label Content ="Score" Foreground="Black" FontSize="10"></Label> </GridViewColumn.Header> <GridViewColumn.CellTemplate> <DataTemplate DataType="local:Player"> <Label Content="{Binding CurrentScore}" FontSize="10" HorizontalContentAlignment="Center" Foreground="Black"/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> <GridViewColumn Width="235"> <GridViewColumn.Header> <Label Content ="Games" Foreground="Black" FontSize="10"></Label> </GridViewColumn.Header> <GridViewColumn.CellTemplate> <DataTemplate DataType="local:Player"> <Label Content="{Binding GamesWon}" HorizontalContentAlignment="Center" FontSize="10" Foreground="Black"/> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> </GridView> </ListView.View> </ListView>
方案二:移除GridView,仅使用ItemTemplate
若不需要GridView的列布局,直接去掉ListView.View部分,保留正确的ItemTemplate即可:
<ListView x:Name="listviewPlayers" ItemsSource="{Binding Players}" Height="200"> <ListView.ItemTemplate> <DataTemplate DataType="local:Player"> <Grid Height="25"> <Grid.ColumnDefinitions> <ColumnDefinition Width="235"/> <ColumnDefinition Width="235"/> <ColumnDefinition Width="235"/> </Grid.ColumnDefinitions> <Label Content="{Binding Name}" FontWeight="Bold" FontSize="10" Foreground="Black"/> <Label Grid.Column="1" Content="{Binding CurrentScore}" FontSize="10" HorizontalContentAlignment="Center" Foreground="Black"/> <Label Grid.Column="2" Content="{Binding GamesWon}" HorizontalContentAlignment="Center" FontSize="10" Foreground="Black"/> </Grid> </DataTemplate> </ListView.ItemTemplate> </ListView>
3. 运行时DataContext检查
你仅设置了设计时的DataContext(d:DataContext),运行时需确保MainWindow的DataContext绑定到MainPageViewModel实例,可在MainWindow构造函数中添加:
public MainWindow() { InitializeComponent(); DataContext = new MainPageViewModel(); }
4. 额外优化建议
Players属性的setter中,每次赋值都会向PlayerNames添加所有Player的Name,多次赋值会导致重复数据,建议先清空再添加:set { players = value; PlayerNames.Clear(); foreach (Player p in players) { PlayerNames.Add(p.Name); } PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Players))); }- 使用
nameof()代替硬编码属性名,避免拼写错误:PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Players)));
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

