简体   繁体   English

WPF上下文菜单数据绑定图标仅在检查时出现

[英]WPF context menu data-bound icon only appears when inspected

Within a TreeView 's resources, I have a HierarchicalDataTemplate that also defines the context menu style. TreeView的资源中,我有一个HierarchicalDataTemplate ,它也定义了上下文菜单样式。 The aim is to be able to have programmatically defined MenuItem s specify an icon name as their Tag and then have the front-end display the right icon. 目的是能够以编程方式定义的MenuItem将图标名称指定为其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 is another control that, for testing, looks just like this. StringToIcon是另一个用于测试的控件,看起来像这样。 It is backed by the dependency property IconName . 它由依赖项属性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 is simply a globally available resource: IconRefresh只是一个全局可用的资源:

<BitmapImage x:Shared="False" x:Key="IconRefresh" UriSource="pack://application:,,,/Resources/Icons/refresh.png" />

When starting the application, none of the context menu refresh icons appear. 启动应用程序时,没有任何上下文菜单刷新图标出现。 They are all blank. 它们都是空白。 I get binding errors, which I'm led to believe is due to the context menus not being in the visual tree: 我遇到绑定错误,我认为这是由于上下文菜单不在可视化树中所致:

Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.MenuItem', AncestorLevel='1''. 找不到参考'RelativeSource FindAncestor,AncestorType ='System.Windows.Controls.MenuItem',AncestorLevel ='1''的绑定源。 BindingExpression:Path=Tag; BindingExpression:Path = Tag; DataItem=null; DataItem = null; target element is 'StringToIcon' (Name='StringIconControl'); 目标元素是'StringToIcon'(Name ='StringIconControl'); target property is 'IconName' (type 'String') 目标属性为“ IconName”(类型为“字符串”)

However, when using Snoop to inspect the menu, all of the bindings and dependency property are correct. 但是,使用Snoop检查菜单时,所有绑定和依赖项属性都是正确的。 After inspecting in this way, the refresh icon inspected miraculously appears, as though it's forced the bindings to reevaluate. 以这种方式检查后,奇迹般地检查了刷新图标,好像它迫使绑定重新评估一样。 You can do this, one by one, to every instance of this icon and they'll appear. 您可以对此图标的每个实例一个一个地进行操作,它们会出现。

How do I fix this lazy binding that seems to be happening here? 如何解决似乎在这里发生的这种惰性绑定? Or is there something else at play? 还是还有其他东西在玩? I saw another post that suggested attaching the menu data context to something that is in the visual tree, but I don't see what that would be in this instance. 我看到在另一个帖子里建议安装到的东西在视觉树菜单数据上下文,但我看不出有什么,这将是在这种情况下。

The eventual solution to the binding problem was to make a new class to hold the menu item details: 绑定问题的最终解决方案是创建一个新类来保存菜单项的详细信息:

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; }
}

This was then tied up to the menu item's style as follows: 然后将其绑定到菜单项的样式,如下所示:

<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>

Presumably this works because the binding is not dependent upon there being a relative source in the visual tree, and instead it has a concrete model class to use. 大概是可行的,因为绑定不依赖于视觉树中是否存在相对源,而是要使用一个具体的模型类。

There is, however, still an issue with the above regarding multiple style instances. 但是,关于多个样式实例,上述仍然存在问题。 I'll post another question for that. 我将为此发布另一个问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM