WPF 上下文菜单数据绑定图标仅在检查时出现
WPF context menu data-bound icon only appears when inspected
在 TreeView
的资源中,我有一个 HierarchicalDataTemplate
也定义了上下文菜单样式。目的是能够以编程方式定义 MenuItem
s 将图标名称指定为其 Tag
,然后让前端显示正确的图标。
<StackPanel.ContextMenu>
<ContextMenu ItemsSource="{Binding MenuItems}">
<ContextMenu.Resources>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Icon">
<Setter.Value>
<local:StringToIcon IconName="{Binding Tag, RelativeSource={RelativeSource AncestorType=MenuItem}}" />
</Setter.Value>
</Setter>
</Style>
</ContextMenu.Resources>
</ContextMenu>
</StackPanel.ContextMenu>
StringToIcon
是另一个控件,为了测试,它看起来就像这样。它由依赖 属性 IconName
.
支持
<UserControl x:Class="MyApp.Components.StringToIcon"
...
Name="StringIconControl">
<Image DataContext="{Binding ElementName=StringIconControl}">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding IconName}" Value="Refresh">
<Setter Property="Source" Value="{StaticResource IconRefresh}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</UserControl>
IconRefresh
只是一个全局可用的资源:
<BitmapImage x:Shared="False" x:Key="IconRefresh" UriSource="pack://application:,,,/Resources/Icons/refresh.png" />
启动应用程序时,none 的上下文菜单刷新图标出现。它们都是空白的。我收到绑定错误,我认为这是由于上下文菜单不在可视化树中造成的:
Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.MenuItem', AncestorLevel='1''. BindingExpression:Path=Tag; DataItem=null; target element is 'StringToIcon' (Name='StringIconControl'); target property is 'IconName' (type 'String')
但是,当使用 Snoop 检查菜单时,所有绑定和依赖性 属性 都是正确的。以这种方式检查后,检查的刷新图标奇迹般地出现了,就好像它强制绑定重新评估一样。您可以对这个图标的每个实例一个一个地执行此操作,它们就会出现。
如何修复似乎发生在此处的惰性绑定?还是有其他事情在起作用?我看到另一个 post 建议将菜单数据上下文附加到可视化树中 是 的东西,但我看不到在这种情况下会是什么。
绑定问题的最终解决方案是制作一个新的 class 来保存菜单项详细信息:
public class BindableMenuItem
{
public BindableMenuItem(string name, ICommand command)
{
this.Name = name;
this.Command = command;
}
public string Name { get; set; }
public ICommand Command { get; set; }
public string IconName { get; set; }
public ObservableCollection<BindableMenuItem> Children { get; set; }
}
然后将其绑定到菜单项的样式,如下所示:
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Name}" />
<Setter Property="Command" Value="{Binding Command}" />
<Setter Property="ItemsSource" Value="{Binding Children}" />
<Setter Property="Icon">
<Setter.Value>
<local:StringToIcon IconName="{Binding IconName}" />
</Setter.Value>
</Setter>
</Style>
大概这是可行的,因为绑定不依赖于可视化树中的相对源,而是它有一个具体的模型 class 可以使用。
但是,上述关于多个样式实例的问题仍然存在。我会 post 另一个问题。
在 TreeView
的资源中,我有一个 HierarchicalDataTemplate
也定义了上下文菜单样式。目的是能够以编程方式定义 MenuItem
s 将图标名称指定为其 Tag
,然后让前端显示正确的图标。
<StackPanel.ContextMenu>
<ContextMenu ItemsSource="{Binding MenuItems}">
<ContextMenu.Resources>
<Style TargetType="{x:Type MenuItem}">
<Setter Property="Icon">
<Setter.Value>
<local:StringToIcon IconName="{Binding Tag, RelativeSource={RelativeSource AncestorType=MenuItem}}" />
</Setter.Value>
</Setter>
</Style>
</ContextMenu.Resources>
</ContextMenu>
</StackPanel.ContextMenu>
StringToIcon
是另一个控件,为了测试,它看起来就像这样。它由依赖 属性 IconName
.
<UserControl x:Class="MyApp.Components.StringToIcon"
...
Name="StringIconControl">
<Image DataContext="{Binding ElementName=StringIconControl}">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Style.Triggers>
<DataTrigger Binding="{Binding IconName}" Value="Refresh">
<Setter Property="Source" Value="{StaticResource IconRefresh}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
</UserControl>
IconRefresh
只是一个全局可用的资源:
<BitmapImage x:Shared="False" x:Key="IconRefresh" UriSource="pack://application:,,,/Resources/Icons/refresh.png" />
启动应用程序时,none 的上下文菜单刷新图标出现。它们都是空白的。我收到绑定错误,我认为这是由于上下文菜单不在可视化树中造成的:
Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.MenuItem', AncestorLevel='1''. BindingExpression:Path=Tag; DataItem=null; target element is 'StringToIcon' (Name='StringIconControl'); target property is 'IconName' (type 'String')
但是,当使用 Snoop 检查菜单时,所有绑定和依赖性 属性 都是正确的。以这种方式检查后,检查的刷新图标奇迹般地出现了,就好像它强制绑定重新评估一样。您可以对这个图标的每个实例一个一个地执行此操作,它们就会出现。
如何修复似乎发生在此处的惰性绑定?还是有其他事情在起作用?我看到另一个 post 建议将菜单数据上下文附加到可视化树中 是 的东西,但我看不到在这种情况下会是什么。
绑定问题的最终解决方案是制作一个新的 class 来保存菜单项详细信息:
public class BindableMenuItem
{
public BindableMenuItem(string name, ICommand command)
{
this.Name = name;
this.Command = command;
}
public string Name { get; set; }
public ICommand Command { get; set; }
public string IconName { get; set; }
public ObservableCollection<BindableMenuItem> Children { get; set; }
}
然后将其绑定到菜单项的样式,如下所示:
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Name}" />
<Setter Property="Command" Value="{Binding Command}" />
<Setter Property="ItemsSource" Value="{Binding Children}" />
<Setter Property="Icon">
<Setter.Value>
<local:StringToIcon IconName="{Binding IconName}" />
</Setter.Value>
</Setter>
</Style>
大概这是可行的,因为绑定不依赖于可视化树中的相对源,而是它有一个具体的模型 class 可以使用。
但是,上述关于多个样式实例的问题仍然存在。我会 post 另一个问题。