WPF中如何在Expander Header绑定Cluster的Summary属性
我来帮你搞定这个问题!你现在遇到的核心问题是分组的上下文里没有关联到Cluster对象的Summary属性——因为你是按Cluster.valueName这个字符串来分组的,分组后GroupItem的DataContext是CollectionViewGroup,它的Name只是分组的字符串键(比如"Front end"),而不是完整的Cluster对象,所以绑定Summary肯定找不到这个属性。
方案一:直接按Cluster对象分组(最简单直接)
这个方法是把分组依据从Cluster.valueName改成Cluster对象本身,这样分组后的CollectionViewGroup.Name就是对应的Cluster实例,自然就能绑定到它的valueName和Summary属性了。
修改C#代码
把原来的PropertyGroupDescription创建代码:
var groupDescription = new PropertyGroupDescription("Cluster.valueName");
改成:
var groupDescription = new PropertyGroupDescription("Cluster");
另外,为了确保相同valueName的Cluster能正确分组(如果需要的话),建议给Cluster类重写Equals和GetHashCode方法(如果你的业务逻辑是valueName相同就视为同一分组):
class Cluster { public string valueName { get; set; } public string Summary { get; set; } public override bool Equals(object obj) { return obj is Cluster cluster && valueName == cluster.valueName; } public override int GetHashCode() { return HashCode.Combine(valueName); } }
修改XAML代码
调整Expander Header里的绑定,现在Name是Cluster对象,所以要绑定它的子属性:
<Expander.Header> <TextBlock TextWrapping="Wrap" Margin="0,10,0,5" > <Bold><TextBlock Text="{Binding Name.valueName}"/></Bold> (<TextBlock Text="{Binding ItemCount}"/> servers) Summary : <TextBlock Text="{Binding Name.Summary}"/> </TextBlock> </Expander.Header>
这样修改后,分组的Expander Header就能正确显示对应Cluster的Summary了。
方案二:使用转换器关联分组名称与Cluster(适合按字符串分组的场景)
如果你的业务需求必须按valueName字符串分组(比如不同Cluster实例但valueName相同要分到同一组),可以用IValueConverter来根据分组名称找到对应的Cluster,再取出Summary。
步骤1:创建转换器类
using System.Globalization; using System.Linq; public class ClusterSummaryConverter : IValueConverter { public ObservableCollection<Cluster> Clusters { get; set; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is string clusterName && Clusters != null) { var cluster = Clusters.FirstOrDefault(c => c.valueName == clusterName); return cluster?.Summary ?? string.Empty; } return string.Empty; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
步骤2:修改Window的Clusters属性
把原来的readonly ObservableCollection<object> Clusters;改成公开的ObservableCollection<Cluster>:
public ObservableCollection<Cluster> Clusters { get; } = new ObservableCollection<Cluster>();
然后在构造函数里初始化Clusters:
public Window1() { InitializeComponent(); Clusters.Add(new Cluster { valueName = "Front end" , Summary = "Front Summary"}); Clusters.Add(new Cluster { valueName = "Middle end" , Summary = "Middle Summary"}); Clusters.Add(new Cluster { valueName = "Back end" , Summary = "Back Summary"}); var collectionView = new ListCollectionView(new[] { new Server { Cluster = Clusters[0], Name = "webshop1" }, new Server { Cluster = Clusters[0], Name = "webshop2" }, new Server { Cluster = Clusters[0], Name = "webshop3" }, new Server { Cluster = Clusters[0], Name = "webshop4" }, new Server { Cluster = Clusters[0], Name = "webshop5" }, new Server { Cluster = Clusters[0], Name = "webshop6" }, new Server { Cluster = Clusters[2], Name = "sql1" }, new Server { Cluster = Clusters[2], Name = "sql2" }, }); var groupDescription = new PropertyGroupDescription("Cluster.valueName"); foreach (var cluster in Clusters) { groupDescription.GroupNames.Add(cluster.valueName); } collectionView.GroupDescriptions.Add(groupDescription); ServersList.ItemsSource = collectionView; }
步骤3:在XAML中声明转换器并绑定
在Window的Resources里添加转换器:
<Window.Resources> <local:ClusterSummaryConverter x:Key="ClusterSummaryConverter" Clusters="{Binding Clusters}"/> </Window.Resources>
然后修改Header的Summary绑定:
<TextBlock Text="{Binding Name, Converter={StaticResource ClusterSummaryConverter}}"/>
最终效果
经过上面的修改,分组的Expander Header就能正确展示对应Cluster的Summary信息,和你预期的效果一致。
内容的提问来源于stack exchange,提问作者Royal Blue Mayank

