WPF中DisplayMemberPath对ComboBox生效但ContextMenu不生效问题
问题现象
实现了从SQLite读取数据的泛型方法:
public static List<T> LoadTable<T>(string dBTable) { using (IDbConnection cnn = new SQLiteConnection(LoadConnectionString())) { var output = cnn.Query<T>("select * from " + dBTable, new DynamicParameters()); return output.ToList(); } }
调用该方法为ComboBox和ContextMenu绑定同一份Rank类型列表数据源,同时设置两者的DisplayMemberPath为Title属性:
List<Rank> ranks = LoadTable<Rank>("tblRanks"); cmb.ItemsSource = mnuDg.ItemsSource = ranks; cmb.DisplayMemberPath = mnuDg.DisplayMemberPath = "Title";
运行后ComboBox可以正常显示Rank实例的Title属性值,但ContextMenu所有项都显示为Rank类的全限定类型名,即使将ContextMenu的Style设置为{x:Null}排除HandyControl控件库的样式影响,问题依然存在。
问题原因
该问题和第三方控件库无关,是WPF原生属性传递逻辑导致的:
- ContextMenu属于弹出层控件,创建时会脱离常规可视化树,不会像ComboBox这类内嵌在页面可视化树中的控件一样,自动将自身的
DisplayMemberPath属性传递给内部生成的项容器(MenuItem) - ComboBox原生内置了
DisplayMemberPath到子项显示内容的映射逻辑,而MenuItem没有对应实现,因此直接给ContextMenu设置DisplayMemberPath不会对菜单项生效,最终菜单项会直接调用数据对象的ToString()方法输出类名作为显示内容。
解决方案
不要依赖ContextMenu的DisplayMemberPath属性,选择以下任意一种方式实现即可:
- 方式1:显式定义ContextMenu的项模板
直接在XAML中为ContextMenu指定ItemTemplate,绑定要显示的Title属性,后台无需再设置mnuDg的DisplayMemberPath:<ContextMenu x:Name="mnuDg"> <ContextMenu.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Title}"/> </DataTemplate> </ContextMenu.ItemTemplate> </ContextMenu> - 方式2:通过项容器样式指定菜单项显示内容
给ContextMenu设置ItemContainerStyle,强制为生成的MenuItem设置Header绑定:<ContextMenu x:Name="mnuDg"> <ContextMenu.ItemContainerStyle> <Style TargetType="MenuItem"> <Setter Property="Header" Value="{Binding Title}"/> </Style> </ContextMenu.ItemContainerStyle> </ContextMenu>
内容的提问来源于stack exchange,提问作者ParSa
相关产品推荐
相关产品推荐

