WPF中如何将两个不同类的数据绑定至同一DataGrid
解决WPF DataGrid绑定不同类列表的AC显示与排序问题
方案一:使用值转换器直接处理跨类属性绑定
这种方式无需修改原有类结构,通过转换器判断对象类型并返回对应AC值:
- 创建AC值转换器
public class AcValueConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is Player player) { return player.Ac; } else if (value is Monster monster) { return monster.Stats?.Ac ?? 0; } return 0; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
- 在XAML中引用转换器并修改AC列绑定
先在窗口/用户控件的资源中声明转换器:
<Window.Resources> <local:AcValueConverter x:Key="AcConverter"/> </Window.Resources>
然后修改DataGrid的AC列:
<DataGridTextColumn Header="AC" Binding="{Binding Converter={StaticResource AcConverter}}"/>
同理,HP列也可以用类似转换器处理(Player无Hp属性时返回N/A):
public class HpValueConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is Monster monster) { return monster.Hp; } return "N/A"; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
方案二:创建统一ViewModel(推荐,更易维护与排序)
通过包装类统一两个实体的属性,同时直接处理排序逻辑:
- 创建统一的CreatureViewModel
public class CreatureViewModel { public string Name { get; set; } public int Id { get; set; } public int Ac { get; set; } public string HpDisplay { get; set; } public int Initiative { get; set; } // 用于排序的核心属性 // 从Player转换 public static CreatureViewModel FromPlayer(Player player) { return new CreatureViewModel { Name = player.Name, Id = player.Id, Ac = player.Ac, HpDisplay = "N/A", Initiative = player.InitiativeBonus }; } // 从Monster转换 public static CreatureViewModel FromMonster(Monster monster) { if (monster.Stats == null) return null; return new CreatureViewModel { Name = monster.Name, Id = monster.Id, Ac = monster.Stats.Ac, HpDisplay = $"{monster.Hp}/{monster.Stats.MaxHp}", Initiative = (monster.Stats.Dex - 10) / 2 // 计算敏捷 modifier 作为 initiative }; } }
- 后台转换列表并排序
// 假设已有players和monsters两个数据源列表 var creatureViewModels = new List<CreatureViewModel>(); creatureViewModels.AddRange(players.Select(CreatureViewModel.FromPlayer)); creatureViewModels.AddRange(monsters.Select(CreatureViewModel.FromMonster).Where(vm => vm != null)); // 按Initiative从高到低排序 creatureViewModels = creatureViewModels.OrderByDescending(vm => vm.Initiative).ToList(); // 绑定到DataGrid creatureDatagrid.ItemsSource = creatureViewModels;
- 简化XAML绑定
此时所有列都可以直接绑定统一属性,无需转换器:
<DataGrid x:Name="creatureDatagrid"> <DataGrid.Columns> <DataGridTextColumn Header="Name" Binding="{Binding Name}"/> <DataGridTextColumn Header="ID" Binding="{Binding Id}"/> <DataGridTextColumn Header="AC" Binding="{Binding Ac}"/> <DataGridTextColumn Header="HP" Binding="{Binding HpDisplay}"/> </DataGrid.Columns> </DataGrid>
内容的提问来源于stack exchange,提问作者NoTimeLeft
相关产品推荐
相关产品推荐

