跨程序集场景下如何向DataTemplateSelector传递指定属性参数
DataTemplateSelector.SelectTemplate 是WPF框架定义的虚方法,方法签名由框架固定,你无法修改入参让框架只传入单个属性值——框架调用该方法时,默认传入的就是当前列表项绑定的完整数据对象。你不需要修改传参逻辑,也不需要改动现有XAML配置,只需在不引用AssemblyY的前提下,从传入的item对象中读取IsGroup属性值即可,有三个常用实现方案:
方案1(类型安全、无性能开销,最推荐):在AssemblyX中定义轻量接口,让AssemblyY的视图模型实现该接口
因为AssemblyY本身就需要引用AssemblyX才能使用其中定义的DataTemplate、控件等资源,在AssemblyX中添加接口不会产生反向依赖,完全符合程序集依赖规则。
首先在AssemblyX中添加接口定义:// 定义于AssemblyX,无需引用AssemblyY public interface IGroupSupport { bool IsGroup { get; } }让AssemblyY中的
MyViewModel实现这个接口后,修改模板选择器代码即可:public class MyContentTemplateSelector : DataTemplateSelector { public DataTemplate ServiceTemplate { get; set; } public DataTemplate GroupTemplate { get; set; } public override DataTemplate SelectTemplate(object item, DependencyObject container) { if (item is IGroupSupport groupItem) { return groupItem.IsGroup ? GroupTemplate : ServiceTemplate; } // 兜底逻辑,匹配失败时返回默认模板 return base.SelectTemplate(item, container); } }方案2(无需修改视图模型代码):通过反射动态读取
IsGroup属性
如果你不想修改视图模型的定义,直接在运行时通过反射读取目标属性即可,不需要引用AssemblyY中的类型:public override DataTemplate SelectTemplate(object item, DependencyObject container) { if (item != null) { var prop = item.GetType().GetProperty("IsGroup"); if (prop?.PropertyType == typeof(bool)) { bool isGroup = (bool)prop.GetValue(item); return isGroup ? GroupTemplate : ServiceTemplate; } } return base.SelectTemplate(item, container); }注意这个方案没有编译时检查,如果后续视图模型修改了
IsGroup的属性名,需要同步修改这里的字符串,否则会匹配失败。方案3(代码最简洁):使用dynamic动态类型读取属性
写法比反射更精简,本质还是运行时动态绑定:public override DataTemplate SelectTemplate(object item, DependencyObject container) { try { dynamic itemObj = item; return (bool)itemObj.IsGroup ? GroupTemplate : ServiceTemplate; } catch { return base.SelectTemplate(item, container); } }这个方案的缺点是属性不存在时会通过异常捕获走兜底逻辑,高频调用场景下有额外开销,适合快速实现非性能敏感的场景。
内容的提问来源于stack exchange,提问作者user48408

