WPF ListViewItem样式App.xaml生效但UserControl内不生效问题
问题根因
这个问题是WPF隐式样式的查找和继承规则导致的,核心逻辑如下:
- WPF给控件匹配隐式样式时,会从控件自身开始沿着资源树向上查找,找到第一个TargetType匹配的样式就直接使用,不会自动合并上层资源里同类型的其他样式。只有手动给样式设置
BasedOn属性指向其他样式时,才会继承对应样式里的属性设置和触发器。 - 你在
UserControl.Resources里写了设置HorizontalContentAlignment、VerticalContentAlignment的ListViewItem样式,但在更内层的ListView.Resources里又写了一个只带选中状态触发器的同TargetType ListViewItem样式。后者离运行时生成的ListViewItem距离更近,会被WPF优先选中作为ListViewItem的生效样式,而且这个样式没设置BasedOn,根本不会继承UserControl资源里那个样式的对齐配置。 - 对于没有显式指定
BasedOn的控件样式,WPF会默认让它继承该控件的全局默认样式:全局默认样式优先读App.xaml里定义的同类型隐式样式,找不到才会用系统主题自带的默认样式。系统主题自带的ListViewItem默认样式里,HorizontalContentAlignment和VerticalContentAlignment是通过RelativeSource FindAncestor绑定到父级ItemsControl对应属性实现的,而ListView生成项容器时会先在内存中创建ListViewItem实例,此时实例还没挂载到可视化树,找不到父级ListView,就会抛出你看到的那两个绑定错误。 - 你把对齐样式移到
App.xaml里之所以能生效,是因为App.xaml里的同类型隐式样式会直接替换系统主题的ListViewItem默认样式,你在ListView.Resources里定义的样式会自动继承这个全局默认样式的对齐设置,自然就不会报错、样式也能正常应用了。
修复方案
不用把样式放到全局App.xaml里,任选一种改法就行:
- 给
ListView.Resources里的ListViewItem样式加BasedOn属性,让它主动继承上层资源中的ListViewItem样式:
<Style TargetType="{x:Type ListViewItem}" BasedOn="{StaticResource {x:Type ListViewItem}}"> <Style.Triggers> <!-- 原有选中触发器代码保持不变 --> </Style.Triggers> </Style>
- 直接把
UserControl.Resources里ListViewItem样式的两个对齐属性Setter,移到ListView.Resources的ListViewItem样式里,合并成一个完整样式即可。
内容的提问来源于stack exchange,提问作者Nodial Tone
相关产品推荐
相关产品推荐

