diff --git a/Source/NotifyIconWpf/Diagrams/TaskbarIcon Overview.cd b/Source/NotifyIconWpf/Diagrams/TaskbarIcon Overview.cd new file mode 100644 index 0000000..dc1f29e --- /dev/null +++ b/Source/NotifyIconWpf/Diagrams/TaskbarIcon Overview.cd @@ -0,0 +1,17 @@ + + + + + + + + + + + N6qdVIeUdLmQtSUbiJhEGdYRjvJYXlhbEVBBKuPRO5s= + TaskbarIcon.cs + + + + + \ No newline at end of file diff --git a/Source/NotifyIconWpf/Interop/TrayInfo.cs b/Source/NotifyIconWpf/Interop/TrayInfo.cs index ded285b..34ea681 100644 --- a/Source/NotifyIconWpf/Interop/TrayInfo.cs +++ b/Source/NotifyIconWpf/Interop/TrayInfo.cs @@ -1,4 +1,4 @@ -// Interop code taken from Mike Marshall's AnyForm +// Some interop code taken from Mike Marshall's AnyForm using System; using System.Drawing; @@ -12,11 +12,10 @@ namespace Hardcodet.Wpf.TaskbarNotification.Interop /// public static class TrayInfo { - - [DllImport("user32.dll")] - private static extern Int32 GetWindowLong(IntPtr hWnd, Int32 Offset); - - + /// + /// Gets the position of the system tray. + /// + /// Tray coordinates. public static Point GetTrayLocation() { var info = new AppBarInfo(); diff --git a/Source/NotifyIconWpf/NotifyIconWpf.csproj b/Source/NotifyIconWpf/NotifyIconWpf.csproj index 914b6b0..e7b3757 100644 --- a/Source/NotifyIconWpf/NotifyIconWpf.csproj +++ b/Source/NotifyIconWpf/NotifyIconWpf.csproj @@ -85,6 +85,7 @@ ResXFileCodeGenerator Resources.Designer.cs + SettingsSingleFileGenerator Settings.Designer.cs diff --git a/Source/NotifyIconWpf/Properties/AssemblyInfo.cs b/Source/NotifyIconWpf/Properties/AssemblyInfo.cs index df1277c..e49731a 100644 --- a/Source/NotifyIconWpf/Properties/AssemblyInfo.cs +++ b/Source/NotifyIconWpf/Properties/AssemblyInfo.cs @@ -53,5 +53,5 @@ using System.Windows.Markup; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyVersion("1.0.1.0")] +[assembly: AssemblyFileVersion("1.0.1.0")] diff --git a/Source/NotifyIconWpf/TaskbarIcon.Declarations.cs b/Source/NotifyIconWpf/TaskbarIcon.Declarations.cs index 22fe1d5..0166c6a 100644 --- a/Source/NotifyIconWpf/TaskbarIcon.Declarations.cs +++ b/Source/NotifyIconWpf/TaskbarIcon.Declarations.cs @@ -557,7 +557,24 @@ namespace Hardcodet.Wpf.TaskbarNotification #endregion - #region DataContext dependency property override + #region DataContext dependency property override / target update + + /// + /// Updates the of a given + /// . This method only updates target elements + /// that do not already have a data context of their own, and either assigns + /// the of the NotifyIcon, or the + /// NotifyIcon itself, if no data context was assigned at all. + /// + private void UpdateDataContext(FrameworkElement target, object oldDataContextValue, object newDataContextValue) + { + if (target != null && !target.IsDataContextDataBound() && Equals(oldDataContextValue, target.DataContext)) + { + //assign own data context, if available. If there is no data + //context at all, assign NotifyIcon itself. + target.DataContext = newDataContextValue ?? this; + } + } /// /// A static callback listener which is being invoked if the @@ -586,24 +603,58 @@ namespace Hardcodet.Wpf.TaskbarNotification object newValue = e.NewValue; object oldValue = e.OldValue; - //replace custom data context for popup and tooltip, if - //they are reflecting the data context's data context - var popup = TrayPopupResolved; - var toolTip = TrayToolTipResolved; - - if (popup != null && Equals(popup.DataContext, oldValue)) - { - popup.DataContext = newValue; - } - - if (toolTip != null && Equals(toolTip.DataContext, oldValue)) - { - toolTip.DataContext = newValue; - } + //replace custom data context for ToolTips, Popup, and + //ContextMenu + UpdateDataContext(TrayPopupResolved, oldValue, newValue); + UpdateDataContext(TrayToolTipResolved, oldValue, newValue); + UpdateDataContext(ContextMenu, oldValue, newValue); } #endregion + #region ContextMenu dependency property override + + /// + /// A static callback listener which is being invoked if the + /// dependency property has + /// been changed. Invokes the + /// instance method of the changed instance. + /// + /// The currently processed owner of the property. + /// Provides information about the updated property. + private static void ContextMenuPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + TaskbarIcon owner = (TaskbarIcon)d; + owner.OnContextMenuPropertyChanged(e); + } + + + /// + /// Releases the old and updates the new property + /// in order to reflect both the NotifyIcon's + /// property and have the assigned. + /// + /// Provides information about the updated property. + private void OnContextMenuPropertyChanged(DependencyPropertyChangedEventArgs e) + { + if (e.OldValue != null) + { + //remove the taskbar icon reference from the previously used element + SetParentTaskbarIcon((DependencyObject)e.OldValue, null); + } + + if (e.NewValue != null) + { + //set this taskbar icon as a reference to the new tooltip element + SetParentTaskbarIcon((DependencyObject)e.NewValue, this); + } + + UpdateDataContext((ContextMenu) e.NewValue, null, DataContext); + } + + #endregion + + #region DoubleClickCommand dependency property @@ -1752,7 +1803,12 @@ namespace Hardcodet.Wpf.TaskbarNotification //register change listener for the DataContext property md = new FrameworkPropertyMetadata(new PropertyChangedCallback(DataContextPropertyChanged)); DataContextProperty.OverrideMetadata(typeof(TaskbarIcon), md); + + //register change listener for the ContextMenu property + md = new FrameworkPropertyMetadata(new PropertyChangedCallback(ContextMenuPropertyChanged)); + ContextMenuProperty.OverrideMetadata(typeof(TaskbarIcon), md); } + } } \ No newline at end of file diff --git a/Source/NotifyIconWpf/TaskbarIcon.cs b/Source/NotifyIconWpf/TaskbarIcon.cs index dd8405a..cd3afa4 100644 --- a/Source/NotifyIconWpf/TaskbarIcon.cs +++ b/Source/NotifyIconWpf/TaskbarIcon.cs @@ -30,6 +30,7 @@ using System.Threading; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; +using System.Windows.Data; using System.Windows.Threading; using Hardcodet.Wpf.TaskbarNotification.Interop; using Point=Hardcodet.Wpf.TaskbarNotification.Interop.Point; @@ -182,14 +183,13 @@ namespace Hardcodet.Wpf.TaskbarNotification { CloseBalloon(); } - //create an invisible popup that hosts the UIElement Popup popup = new Popup(); popup.AllowsTransparency = true; //provide the popup with the taskbar icon's data context - popup.DataContext = DataContext; + UpdateDataContext(popup, null, DataContext); //don't animate by default - devs can use attached //events or override @@ -314,8 +314,6 @@ namespace Hardcodet.Wpf.TaskbarNotification #endregion - - #region Process Incoming Mouse Events /// @@ -483,11 +481,6 @@ namespace Hardcodet.Wpf.TaskbarNotification //the ParentTaskbarIcon attached dependency property: //tt.PlacementTarget = this; - //the tooltip (and implicitly its context) explicitly gets - //the DataContext of this instance. If there is no DataContext, - //the TaskbarIcon sets itself - tt.DataContext = DataContext ?? this; - //make sure the tooltip is invisible tt.HasDropShadow = false; tt.BorderThickness = new Thickness(0); @@ -504,6 +497,13 @@ namespace Hardcodet.Wpf.TaskbarNotification tt.Content = ToolTipText; } + //the tooltip explicitly gets the DataContext of this instance. + //If there is no DataContext, the TaskbarIcon assigns itself + if (tt != null) + { + UpdateDataContext(tt, null, DataContext); + } + //store a reference to the used tooltip SetTrayToolTipResolved(tt); } @@ -566,11 +566,9 @@ namespace Hardcodet.Wpf.TaskbarNotification //events or override popup.PopupAnimation = PopupAnimation.None; - //the tooltip (and implicitly its context) explicitly gets - //the DataContext of this instance. If there is no DataContext, - //the TaskbarIcon assigns itself - popup.DataContext = DataContext ?? this; - + //the CreateRootPopup method outputs binding errors in the debug window because + //it tries to bind to "Popup-specific" properties in case they are provided by the child + //not a problem. Popup.CreateRootPopup(popup, TrayPopup); //do *not* set the placement target, as it causes the popup to become hidden if the @@ -582,6 +580,13 @@ namespace Hardcodet.Wpf.TaskbarNotification popup.StaysOpen = false; } + //the popup explicitly gets the DataContext of this instance. + //If there is no DataContext, the TaskbarIcon assigns itself + if (popup != null) + { + UpdateDataContext(popup, null, DataContext); + } + //store a reference to the used tooltip SetTrayPopupResolved(popup); } diff --git a/Source/NotifyIconWpf/Util.cs b/Source/NotifyIconWpf/Util.cs index 8691996..c7ef9f6 100644 --- a/Source/NotifyIconWpf/Util.cs +++ b/Source/NotifyIconWpf/Util.cs @@ -27,6 +27,7 @@ using System; using System.ComponentModel; using System.Drawing; using System.Windows; +using System.Windows.Data; using System.Windows.Input; using System.Windows.Media; using System.Windows.Resources; @@ -99,9 +100,10 @@ namespace Hardcodet.Wpf.TaskbarNotification /// Updates the taskbar icons with data provided by a given /// instance. /// - /// - /// - /// + /// Configuration settings for the NotifyIcon. + /// Operation on the icon (e.g. delete the icon). + /// True if the data was successfully written. + /// See Shell_NotifyIcon documentation on MSDN for details. public static bool WriteIconData(ref NotifyIconData data, NotifyCommand command) { return WriteIconData(ref data, command, data.ValidMembers); @@ -112,10 +114,12 @@ namespace Hardcodet.Wpf.TaskbarNotification /// Updates the taskbar icons with data provided by a given /// instance. /// - /// - /// - /// - /// + /// Configuration settings for the NotifyIcon. + /// Operation on the icon (e.g. delete the icon). + /// Defines which members of the + /// structure are set. + /// True if the data was successfully written. + /// See Shell_NotifyIcon documentation on MSDN for details. public static bool WriteIconData(ref NotifyIconData data, NotifyCommand command, IconDataMembers flags) { //do nothing if in design mode @@ -270,5 +274,21 @@ namespace Hardcodet.Wpf.TaskbarNotification #endregion + + /// + /// Checks whether the + /// is bound or not. + /// + /// The element to be checked. + /// True if the data context property is being managed by a + /// binding expression. + /// If + /// is a null reference. + public static bool IsDataContextDataBound(this FrameworkElement element) + { + if (element == null) throw new ArgumentNullException("element"); + return element.GetBindingExpression(FrameworkElement.DataContextProperty) != null; + } + } }