找不到具有显式ElementName的WPF DataBinding

rab*_*ens 3 c# data-binding wpf xaml

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

我正在使用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>
Run Code Online (Sandbox Code Playgroud)

这是我的代码背后:

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
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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')
Run Code Online (Sandbox Code Playgroud)

奇怪的是:mainWindow IS在XAML编辑发现当我输入ElementName=IsChecked绑定,智能感知它显示给我.

什么DOES工作虽然是设置DataContext在代码隐藏右后编程InitializeComponent();:

DataContext = this;
Run Code Online (Sandbox Code Playgroud)

然后将绑定更改为:

IsChecked="{Binding Enabled, UpdateSourceTrigger=PropertyChanged}"
Run Code Online (Sandbox Code Playgroud)

这确实输出以下内容:

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')
Run Code Online (Sandbox Code Playgroud)

但它的确有效.

我在这做错了什么?或者以DataContext编程方式设置要走的路?

Jai*_*Jai 6

你正在处理ContextMenu.这是最棘手的控件之一,因为它实际上是一个Window,它有自己的可视树.你必须想象底层是做类似的事情:

Window contextMenu = new Window();
contextMenu.Show();
Run Code Online (Sandbox Code Playgroud)

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

捆绑

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

<SomeControl>
    <SomeControl.ContextMenu>
        <ContextMenu ....>
        <!-- This ContextMenu's PlacementTarget is automatically SomeControl -->
        <ContextMenu>
    </SomeControl.ContextMenu>
</SomeControl>
Run Code Online (Sandbox Code Playgroud)

要进行绑定,您需要这样做:

<ContextMenu DataContext="{Binding RelativeSource={RelativeSource Self}, Path=PlacementTarget.DataContext}" ...>
Run Code Online (Sandbox Code Playgroud)

对于您的情况,您使用的是一些外部API.显然,此自定义控件已将DataContext设置为其放置目标的DataContext.

您的问题是因为您的窗口的DataContext未设置为自己,您已经解决了.无论是xaml还是代码隐藏都同样有效.

的ElementName

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