WPF中ContentTemplateSelector的item参数为null问题咨询
以下是自定义的Button ControlTemplate:
<ControlTemplate x:Name="FlatSymbolIconButton" TargetType="Button"> <Border x:Name="ButtonBorder"> <ContentControl ContentTemplateSelector="{StaticResource FlatButtonTemplateSelector}" Content="{TemplateBinding Content}"/> </Border> </ControlTemplate>
使用示例:
<Button Template="{StaticResource FlatSymbolIconButton}" Content="Edit"/>
发现SelectTemplateCore方法被调用时item参数为null,原本预期Content属性的值(字符串“Edit”)会传递给该方法用于模板选择。但测试时返回默认模板,内容却能正确传递给数据模板并显示。请问item参数为null的原因可能是什么?
原因分析
1. TemplateBinding的解析时机问题
TemplateBinding属于轻量级绑定,解析时机晚于普通绑定。当ContentControl初始化并触发ContentTemplateSelector的SelectTemplateCore时,TemplateBinding可能还未完成对Button.Content属性的解析,此时ContentControl的Content仍为null,导致传入SelectTemplateCore的item参数为null。
2. SelectTemplateCore的多次调用特性
ContentTemplateSelector的SelectTemplateCore会在ContentControl的Content属性变更时触发多次:
- 第一次调用发生在ContentControl初始化阶段,此时TemplateBinding尚未完成值传递,Content为null,item参数自然是null;
- 当TemplateBinding完成解析,Button的Content值(“Edit”)传递给ContentControl后,
SelectTemplateCore会被第二次调用,此时item参数就是正确的“Edit”。
你可以在SelectTemplateCore中添加日志输出,验证是否存在第二次调用。
3. 未完整重写SelectTemplateCore重载
如果只重写了SelectTemplateCore(object item, DependencyObject container)这一个重载,在部分WPF框架版本中,可能会触发仅接受object item的重载,导致参数传递异常。建议同时重写两个重载:
public override DataTemplate SelectTemplate(object item, DependencyObject container) { // 你的模板选择逻辑 } // 适配.NET Framework的重载 public override DataTemplate SelectTemplate(object item) { return SelectTemplate(item, null); }
4. ContentControl初始状态的影响
ContentControl在XAML中未显式设置Content初始值时,初始状态下Content为null,会触发第一次SelectTemplateCore调用。后续TemplateBinding完成值传递后,Content更新,才会触发第二次带正确item参数的调用。
你可以通过打印SelectTemplateCore的调用日志,确认是否存在第二次调用,以此验证上述推测。
内容的提问来源于stack exchange,提问作者testalino

