2016-07-01 9 views
3

Ich möchte eine Anwendung erstellen, die im Hintergrund Aufgaben erledigt und über ein Taskleistensymbol steuerbar ist. Dieses Taskleistensymbol verfügt über ein Kontextmenü mit einem Kontrollkästchen, das auf Aktiviert gesetzt werden kann. Anschließend wird die Hintergrundaufgabe gestartet.WPF DataBinding mit expliziten ElementName wurde nicht gefunden

Ich verwende WPF und die Hardcodet WPF NotifyIcon.

Hier ist meine 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> 

Hier ist mein Code Behind:

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

Dies funktioniert nicht. Ich erhalte die folgende in der Ausgabe, wenn es ausgeführt wird:

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

Das Merkwürdige ist: mainWindow im XAML-Editor gefunden, wenn ich ElementName= für die IsChecked Typ binden, wie IntelliSense es mir zeigt.

Was DOES Arbeit ist jedoch die DataContext programmatisch in Code-Behind Einstellung direkt nach InitializeComponent();:

DataContext = this; 

Und dann die Änderung der Bindung an:

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

Dies gilt Ausgabe der folgenden :

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

aber es funktioniert.

Was mache ich hier falsch? Oder setzt man den DataContext programmatisch auf den Weg?

+0

Vielleicht haben Sie es ändern zu „IsEnabled“ Eigenschaft. – CiccioRocca

+0

Nein, ich möchte IsChecked binden, aber ich habe es herausgefunden. Ich muss 'DataContext =" {Binding RelativeSource = {RelativeSource Self}} "im öffnenden' ' Tag setzen und die zweite, kürzere Bindung verwenden. – rabejens

+0

Sorry hat deine Frage nicht gut gelesen. Ich habe es falsch verstanden. – CiccioRocca

Antwort

6

Sie haben es mit ContextMenu. Dies ist eines der kompliziertesten Steuerelemente, da es eigentlich ein eigenes Fenster ist, das seinen eigenen visuellen Baum hat. Sie müssen sich vorstellen, dass die zugrunde liegenden etwas Ähnliches dies tut:

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

Dieses Fenster Beispiel kann natürlich nicht direkt an das Mainwindow binden, die es schafft, kann es?

ContextMenu Bindung ist eine separate Einheit für sich allein. Standardmäßig ist DataContext vom übergeordneten Objekt (Placement-Ziel) isoliert. Zum Glück hat ContextMenu PlacementTarget Eigenschaft, die automatisch das Objekt ist, das Sie in XAML einfügen.

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

Um eine Bindung zu tun, müssen Sie dies tun:

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

Für Ihren Fall Sie einige externe API verwenden. Anscheinend hat dieses benutzerdefinierte Steuerelement den DataContext bereits als den DataContext seines Placement-Ziels festgelegt.

Ihr Problem ist, weil der DataContext Ihres Fensters nicht auf sich selbst eingestellt ist, die Sie gelöst haben. Entweder funktioniert XAML oder Code-Behind gleich gut.

Element

Wenn Sie ElementName, wird die Bindungsmodul Datacontext im Allgemeinen ignorieren. Es wird nach dem Element mit dem spezifischen Namen in einen eigenen visuellen Baum suchen. Wie ich anfangs gesagt habe, hat ContextMenu seinen eigenen visuellen Baum, so dass es offensichtlich nicht in der Lage wäre, dieses Element in seinem visuellen Baum zu finden.

0

Elementnamen sind Groß- und Kleinschreibung, sollten Sie die es aktualisieren, um „Mainwindow“ von „Mainwindow“, weil die Bindung kann nicht das Element finden, wie der Fehler schlägt