WPF ComboBox的DataTemplate内UserControl图标偶发丢失如何解决
WPF DataTemplate内UserControl偶发不显示问题解决方案
问题现象
- 首次展开ComboBox时,选中项无图标展示
- 第二次展开ComboBox时,上一次选中的项无图标展示
对应效果如下图:

核心原因
WPF中任意UI元素同一时间只能挂载到一个视觉父节点下。当前实现将UserControl实例直接存储在ViewModel的模型类中,而ComboBox的选中项会同时出现在两个视觉容器中:下拉列表的项容器、ComboBox顶部的选中内容展示框,二者争夺同一个UI控件实例,必然会导致其中一个位置的图标被移除,出现消失的现象。同时这种直接把UI元素放到ViewModel的写法也违反了MVVM的职责分离原则。
解决方案(推荐,符合MVVM规范)
步骤1:修改项模型,替换UI存储为标识枚举
// 定义图标类型枚举 public enum IconType { Rendered, Wireframe, Shaded, HiddenLines } // 修改组合框项模型 public class ComboBoxItemModel { public IconType IconType { get; set; } public string Text { get; set; } }
步骤2:修改ViewModel初始化逻辑,赋值枚举标识
public ObservableCollection<ComboBoxItemModel> RendererItems { get; set; } = new ObservableCollection<ComboBoxItemModel>(); public MainWindowViewModel() { RendererItems.Add(new ComboBoxItemModel() { IconType = IconType.Rendered, Text = "Rendered" }); RendererItems.Add(new ComboBoxItemModel() { IconType = IconType.Wireframe, Text = "Wireframe" }); RendererItems.Add(new ComboBoxItemModel() { IconType = IconType.Shaded, Text = "Shaded" }); RendererItems.Add(new ComboBoxItemModel() { IconType = IconType.HiddenLines, Text = "Hidden Lines" }); }
步骤3:修改DataTemplate,用触发器动态生成图标实例
<DataTemplate x:Key="DropDownItemTemplate"> <StackPanel Orientation="Horizontal"> <ContentControl Width="24" Height="24"> <ContentControl.Style> <Style TargetType="ContentControl"> <Style.Triggers> <DataTrigger Binding="{Binding IconType}" Value="Rendered"> <Setter Property="Content"> <Setter.Value> <local:RenderedIcon/> </Setter.Value> </Setter> </DataTrigger> <DataTrigger Binding="{Binding IconType}" Value="Wireframe"> <Setter Property="Content"> <Setter.Value> <local:WireframeIcon/> </Setter.Value> </Setter> </DataTrigger> <DataTrigger Binding="{Binding IconType}" Value="Shaded"> <Setter Property="Content"> <Setter.Value> <local:ShadedIcon/> </Setter.Value> </Setter> </DataTrigger> <DataTrigger Binding="{Binding IconType}" Value="HiddenLines"> <Setter Property="Content"> <Setter.Value> <local:HiddenLinesIcon/> </Setter.Value> </Setter> </DataTrigger> </Style.Triggers> </Style> </ContentControl.Style> </ContentControl> <TextBlock Text="{Binding Text}" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="10,0"/> </StackPanel> </DataTemplate>
如果图标用户控件是定义在资源字典里的,给每个图标资源加上x:Shared="False"属性,就可以保证每次引用都生成新的实例,避免父级冲突。
临时快速修复方案(仅做应急)
如果暂时不想调整现有模型结构,直接给ComboBox设置属性SelectionBoxItemTemplate="{StaticResource DropDownItemTemplate}",同时给每个图标用户控件的定义加上x:Shared="False",也可以解决图标消失的问题,但仍存在ViewModel耦合UI的设计缺陷。
内容的提问来源于stack exchange,提问作者Jaime
相关产品推荐
相关产品推荐

