【问题标题】:WPF DataBinding with explicit ElementName is not found未找到具有显式 ElementName 的 WPF 数据绑定
【发布时间】:2016-11-03 12:41:43
【问题描述】:

我想创建一个在后台执行操作并可以通过托盘图标控制的应用程序。这个托盘图标有一个带有复选框的上下文菜单,可以将其设置为启用,然后后台任务启动。

我正在使用 WPF 和 Hardcodet WPF NotifyIcon。

这是我的 MainWindow.xaml:

<Window x:Name="mainWindow" x:Class="MyTrayApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:MyTrayApplication"
        xmlns:tb="http://www.hardcodet.net/taskbar"
        mc:Ignorable="d"
        Title="MainWindow" Height="10" Width="10" Visibility="Hidden">

    <tb:TaskbarIcon x:Name="taskbarIcon" IconSource="MyTrayApplication.ico" ToolTipText="My tray application" >
        <tb:TaskbarIcon.ContextMenu>
            <ContextMenu>
                <MenuItem x:Name="enabledItem" Header="Enabled" IsCheckable="True" IsChecked="{Binding Path=Enabled, ElementName=mainWindow, UpdateSourceTrigger=PropertyChanged}"/>
                <MenuItem x:Name="configureItem" Header="Configure..." Click="configureItem_Click"/>
                <MenuItem x:Name="exitItem" Header="Exit" Click="exitItem_Click"/>
            </ContextMenu>
        </tb:TaskbarIcon.ContextMenu>
    </tb:TaskbarIcon>

</Window>

这是我的代码:

using System;
using System.Windows;

namespace MyTrayApplication {
    /// <summary>
    /// Interaktionslogik für MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window {
        private bool _enabled;

        public MainWindow() {
            InitializeComponent();
        }

        private void exitItem_Click(object sender, RoutedEventArgs e) {
            Close();
        }

        private void configureItem_Click(object sender, RoutedEventArgs e) {
            // Code to fire up configuration
        }

        public bool Enabled {
            get {
                return _enabled;
            }
            set {
                _enabled = value;
                Console.WriteLine(value);
                // Code to enable the background task
            }
        }
    }
}

这不起作用。运行时我在输出中得到以下内容:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=mainWindow'. BindingExpression:Path=Enabled; DataItem=null; target element is 'MenuItem' (Name='enabledItem'); target property is 'IsChecked' (type 'Boolean')

奇怪的是:当我为 IsChecked 绑定键入 ElementName= 时,在 XAML 编辑器中找到了 mainWindow IS,正如 IntelliSense 向我显示的那样。

的工作是在InitializeComponent(); 之后以编程方式在代码隐藏中设置DataContext

DataContext = this;

然后将绑定更改为:

IsChecked="{Binding Enabled, UpdateSourceTrigger=PropertyChanged}"

这会输出以下内容:

System.Windows.Data Error: 40 : BindingExpression path error: 'Enabled' property not found on 'object' ''TaskbarIcon' (Name='taskbarIcon')'. BindingExpression:Path=Enabled; DataItem='TaskbarIcon' (Name='taskbarIcon'); target element is 'MenuItem' (Name='enabledItem'); target property is 'IsChecked' (type 'Boolean')

但它有效。

我在这里做错了什么?还是以编程方式设置DataContext

【问题讨论】:

  • 也许您必须将其更改为“IsEnabled”属性。
  • 不,我想绑定 IsChecked,但我想通了。我必须在开头的&lt;Window&gt; 标记中设置DataContext="{Binding RelativeSource={RelativeSource Self}}" 并使用第二个更短的绑定。
  • 抱歉没有很好地阅读您的问题。我误会了。
  • 看起来,在第二次尝试中,“enabledItem”的 DataContext 在第一时间设置为 TaskbarIcon 而不是主窗口
  • 是的,就是这样。奇怪的是,FindAncestor 方法也不起作用,但我在其他评论中提到的方法有效。

标签: c# wpf xaml data-binding


【解决方案1】:

您正在处理ContextMenu。这是处理起来最棘手的控件之一,因为它实际上是一个独立的窗口,它有自己的可视化树。你必须想象底层正在做类似的事情:

Window contextMenu = new Window();
contextMenu.Show();

这个窗口实例显然不能直接绑定到创建它的MainWindow,可以吗?

绑定

ContextMenu 是一个独立的实体。默认情况下,其DataContext 与父级(放置目标)隔离。幸运的是,ContextMenu 有 PlacementTarget 属性,它会自动成为您在 XAML 中放入的对象。

<SomeControl>
    <SomeControl.ContextMenu>
        <ContextMenu ....>
        <!-- This ContextMenu's PlacementTarget is automatically SomeControl -->
        <ContextMenu>
    </SomeControl.ContextMenu>
</SomeControl>

为了进行绑定,你需要这样做:

<ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.DataContext}" ...>

对于您的情况,您正在使用一些外部 API。显然,这个自定义控件已经将 DataContext 设置为其放置目标的 DataContext。

您的问题是因为您的窗口的 DataContext 未设置为自身,您已经解决了。 xaml 或代码隐藏同样有效。

元素名称

当你使用ElementName时,绑定引擎一般会忽略DataContext。它将开始在它自己的可视化树中寻找具有特定名称的元素。就像我最初所说的那样,ContextMenu 有自己的可视化树,因此显然它无法在其可视化树中找到该元素。

【讨论】:

    【解决方案2】:

    这有点棘手。问题是 ContextMenu 不是可视树的一部分。请参阅此帖子以获取解决方案:WPF: Binding a ContextMenu to an MVVM Command

    【讨论】:

      【解决方案3】:

      元素名称区分大小写,您应该将其从“mainWindow”更新为“MainWindow”,因为绑定无法找到错误提示的元素

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多