mirror of
https://github.com/ckaczor/wpf-notifyicon.git
synced 2026-02-12 11:08:30 -05:00
WPF NotifyIcon
--------------
CHG DataContext now also set on ContextMenu property. Revamped DataContext handling, which
now not only checks whether DataContext is not null, but also leaves DataContext of
controls unchanged, if the DataContext is bound.
CHG Some documentation changes and cleanup, added class diagram.
git-svn-id: https://svn.evolvesoftware.ch/repos/evolve.net/WPF/NotifyIcon@100 9f600761-6f11-4665-b6dc-0185e9171623
This commit is contained in:
17
Source/NotifyIconWpf/Diagrams/TaskbarIcon Overview.cd
Normal file
17
Source/NotifyIconWpf/Diagrams/TaskbarIcon Overview.cd
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ClassDiagram MajorVersion="1" MinorVersion="1">
|
||||
<Class Name="Hardcodet.Wpf.TaskbarNotification.TaskbarIcon">
|
||||
<Position X="0.5" Y="0.5" Width="3.5" />
|
||||
<Compartments>
|
||||
<Compartment Name="Fields" Collapsed="true" />
|
||||
<Compartment Name="Methods" Collapsed="true" />
|
||||
<Compartment Name="Properties" Collapsed="true" />
|
||||
</Compartments>
|
||||
<TypeIdentifier>
|
||||
<HashCode>N6qdVIeUdLmQtSUbiJhEGdYRjvJYXlhbEVBBKuPRO5s=</HashCode>
|
||||
<FileName>TaskbarIcon.cs</FileName>
|
||||
</TypeIdentifier>
|
||||
<Lollipop Position="0.2" />
|
||||
</Class>
|
||||
<Font Name="Segoe UI" Size="9" />
|
||||
</ClassDiagram>
|
||||
@@ -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
|
||||
/// </summary>
|
||||
public static class TrayInfo
|
||||
{
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern Int32 GetWindowLong(IntPtr hWnd, Int32 Offset);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the position of the system tray.
|
||||
/// </summary>
|
||||
/// <returns>Tray coordinates.</returns>
|
||||
public static Point GetTrayLocation()
|
||||
{
|
||||
var info = new AppBarInfo();
|
||||
|
||||
@@ -85,6 +85,7 @@
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<None Include="Diagrams\TaskbarIcon Overview.cd" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
|
||||
@@ -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")]
|
||||
|
||||
@@ -557,7 +557,24 @@ namespace Hardcodet.Wpf.TaskbarNotification
|
||||
|
||||
#endregion
|
||||
|
||||
#region DataContext dependency property override
|
||||
#region DataContext dependency property override / target update
|
||||
|
||||
/// <summary>
|
||||
/// Updates the <see cref="FrameworkElement.DataContextProperty"/> of a given
|
||||
/// <see cref="FrameworkElement"/>. This method only updates target elements
|
||||
/// that do not already have a data context of their own, and either assigns
|
||||
/// the <see cref="FrameworkElement.DataContext"/> of the NotifyIcon, or the
|
||||
/// NotifyIcon itself, if no data context was assigned at all.
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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
|
||||
|
||||
/// <summary>
|
||||
/// A static callback listener which is being invoked if the
|
||||
/// <see cref="FrameworkElement.ContextMenuProperty"/> dependency property has
|
||||
/// been changed. Invokes the <see cref="OnContextMenuPropertyChanged"/>
|
||||
/// instance method of the changed instance.
|
||||
/// </summary>
|
||||
/// <param name="d">The currently processed owner of the property.</param>
|
||||
/// <param name="e">Provides information about the updated property.</param>
|
||||
private static void ContextMenuPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
TaskbarIcon owner = (TaskbarIcon)d;
|
||||
owner.OnContextMenuPropertyChanged(e);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Releases the old and updates the new <see cref="ContextMenu"/> property
|
||||
/// in order to reflect both the NotifyIcon's <see cref="FrameworkElement.DataContext"/>
|
||||
/// property and have the <see cref="ParentTaskbarIconProperty"/> assigned.
|
||||
/// </summary>
|
||||
/// <param name="e">Provides information about the updated property.</param>
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
/// <summary>
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
/// <see cref="NotifyIconData"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="data">Configuration settings for the NotifyIcon.</param>
|
||||
/// <param name="command">Operation on the icon (e.g. delete the icon).</param>
|
||||
/// <returns>True if the data was successfully written.</returns>
|
||||
/// <remarks>See Shell_NotifyIcon documentation on MSDN for details.</remarks>
|
||||
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
|
||||
/// <see cref="NotifyIconData"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="command"></param>
|
||||
/// <param name="flags"></param>
|
||||
/// <returns></returns>
|
||||
/// <param name="data">Configuration settings for the NotifyIcon.</param>
|
||||
/// <param name="command">Operation on the icon (e.g. delete the icon).</param>
|
||||
/// <param name="flags">Defines which members of the <paramref name="data"/>
|
||||
/// structure are set.</param>
|
||||
/// <returns>True if the data was successfully written.</returns>
|
||||
/// <remarks>See Shell_NotifyIcon documentation on MSDN for details.</remarks>
|
||||
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
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the <see cref="FrameworkElement.DataContextProperty"/>
|
||||
/// is bound or not.
|
||||
/// </summary>
|
||||
/// <param name="element">The element to be checked.</param>
|
||||
/// <returns>True if the data context property is being managed by a
|
||||
/// binding expression.</returns>
|
||||
/// <exception cref="ArgumentNullException">If <paramref name="element"/>
|
||||
/// is a null reference.</exception>
|
||||
public static bool IsDataContextDataBound(this FrameworkElement element)
|
||||
{
|
||||
if (element == null) throw new ArgumentNullException("element");
|
||||
return element.GetBindingExpression(FrameworkElement.DataContextProperty) != null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user