diff --git a/Source/NotifyIconWpf/TaskbarIcon.Declarations.cs b/Source/NotifyIconWpf/TaskbarIcon.Declarations.cs index d817b55..2870a7c 100644 --- a/Source/NotifyIconWpf/TaskbarIcon.Declarations.cs +++ b/Source/NotifyIconWpf/TaskbarIcon.Declarations.cs @@ -121,7 +121,7 @@ namespace Hardcodet.Wpf.TaskbarNotification } /// - /// Provides a secure method for setting the CustomBalloon property. + /// Provides a secure method for setting the property. /// /// The new value for the property. protected void SetCustomBalloon(Popup value) @@ -333,7 +333,21 @@ namespace Hardcodet.Wpf.TaskbarNotification //recreate tooltip control CreateCustomToolTip(); - //udpate tooltip settings - needed to make sure a string is set, even + if (e.OldValue != null) + { + //remove the taskbar icon reference from the previously used element + SetParentTaskbarIcon((DependencyObject) e.OldValue, this); + } + + + if (e.NewValue != null) + { + //set this taskbar icon as a reference to the new tooltip element + SetParentTaskbarIcon((DependencyObject) e.NewValue, this); + } + + + //update tooltip settings - needed to make sure a string is set, even //if the ToolTipText property is not set. Otherwise, the event that //triggers tooltip display is never fired. WriteToolTipSettings(); @@ -390,6 +404,19 @@ namespace Hardcodet.Wpf.TaskbarNotification /// Provides information about the updated property. private void OnTrayPopupPropertyChanged(DependencyPropertyChangedEventArgs e) { + if (e.OldValue != null) + { + //remove the taskbar icon reference from the previously used element + SetParentTaskbarIcon((DependencyObject)e.OldValue, this); + } + + + if (e.NewValue != null) + { + //set this taskbar icon as a reference to the new tooltip element + SetParentTaskbarIcon((DependencyObject)e.NewValue, this); + } + //create a pop CreatePopup(); } @@ -1670,7 +1697,38 @@ namespace Hardcodet.Wpf.TaskbarNotification #endregion - + //ATTACHED PROPERTIES + + //TODO put into use + #region ParentTaskbarIcon + + /// + /// An attached property that is assigned to + /// + public static readonly DependencyProperty ParentTaskbarIconProperty = + DependencyProperty.RegisterAttached("ParentTaskbarIcon", typeof (TaskbarIcon), typeof (TaskbarIcon)); + + /// + /// Gets the ParentTaskbarIcon property. This dependency property + /// indicates .... + /// + public static TaskbarIcon GetParentTaskbarIcon(DependencyObject d) + { + return (TaskbarIcon)d.GetValue(ParentTaskbarIconProperty); + } + + /// + /// Sets the ParentTaskbarIcon property. This dependency property + /// indicates .... + /// + public static void SetParentTaskbarIcon(DependencyObject d, TaskbarIcon value) + { + d.SetValue(ParentTaskbarIconProperty, value); + } + + #endregion + + diff --git a/Source/NotifyIconWpf/TaskbarIcon.cs b/Source/NotifyIconWpf/TaskbarIcon.cs index 97bc38e..4021df0 100644 --- a/Source/NotifyIconWpf/TaskbarIcon.cs +++ b/Source/NotifyIconWpf/TaskbarIcon.cs @@ -163,7 +163,7 @@ namespace Hardcodet.Wpf.TaskbarNotification Popup.CreateRootPopup(popup, balloon); - //TODO we don't really need this and it causes the popup to become hidden if the + //don't set the PlacementTarget as it causes the popup to become hidden if the //TaskbarIcon's parent is hidden, too... //popup.PlacementTarget = this; @@ -180,6 +180,9 @@ namespace Hardcodet.Wpf.TaskbarNotification SetCustomBalloon(popup); } + //assign this instance as an attached property + SetParentTaskbarIcon(balloon, this); + //fire attached event RaiseBalloonShowingEvent(balloon); @@ -199,7 +202,7 @@ namespace Hardcodet.Wpf.TaskbarNotification /// /// Closes the current , if it's set. /// - private void CloseBalloon() + public void CloseBalloon() { if (IsDisposed) return; @@ -214,6 +217,11 @@ namespace Hardcodet.Wpf.TaskbarNotification { //if a balloon message is already displayed, close it immediately popup.IsOpen = false; + + //reset attached property + UIElement element = popup.Child; + if (element != null) SetParentTaskbarIcon(element, null); + SetCustomBalloon(null); } } @@ -396,7 +404,7 @@ namespace Hardcodet.Wpf.TaskbarNotification tt = new ToolTip(); tt.Placement = PlacementMode.Mouse; - //TODO we don't really need this and it causes the popup to become hidden if the + //do *not* set the placement target, as it causes the popup to become hidden if the //TaskbarIcon's parent is hidden, too. //tt.PlacementTarget = this; diff --git a/Source/Sample Project/Commands/CommandBase.cs b/Source/Sample Project/Commands/CommandBase.cs new file mode 100644 index 0000000..b3411ae --- /dev/null +++ b/Source/Sample Project/Commands/CommandBase.cs @@ -0,0 +1,64 @@ +using System; +using System.Windows.Input; +using System.Windows.Markup; + +namespace Sample_Project.Commands +{ + /// + /// Basic implementation of the + /// interface, which is also accessible as a markup + /// extension. + /// + public abstract class CommandBase : MarkupExtension, ICommand + where T : class, ICommand, new() + { + /// + /// A singleton instance. + /// + private static T command; + + /// + /// Gets a shared command instance. + /// + public override object ProvideValue(IServiceProvider serviceProvider) + { + if (command == null) command = new T(); + return command; + } + + /// + /// Fires when changes occur that affect whether + /// or not the command should execute. + /// + public event EventHandler CanExecuteChanged + { + add { CommandManager.RequerySuggested += value; } + remove { CommandManager.RequerySuggested -= value; } + } + + /// + /// Defines the method to be called when the command is invoked. + /// + /// Data used by the command. + /// If the command does not require data to be passed, + /// this object can be set to null. + /// + public abstract void Execute(object parameter); + + /// + /// Defines the method that determines whether the command + /// can execute in its current state. + /// + /// + /// This default implementation always returns true. + /// + /// Data used by the command. + /// If the command does not require data to be passed, + /// this object can be set to null. + /// + public virtual bool CanExecute(object parameter) + { + return true; + } + } +} diff --git a/Source/Sample Project/Commands/HideMainWindowCommand.cs b/Source/Sample Project/Commands/HideMainWindowCommand.cs index c91b4b8..ea40b97 100644 --- a/Source/Sample Project/Commands/HideMainWindowCommand.cs +++ b/Source/Sample Project/Commands/HideMainWindowCommand.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; +using System.Windows; using System.Windows.Input; namespace Sample_Project.Commands @@ -10,30 +6,21 @@ namespace Sample_Project.Commands /// /// Hides the main window. /// - public class HideMainWindowCommand : ICommand + public class HideMainWindowCommand : CommandBase { - public event EventHandler CanExecuteChanged; - public void Execute(object parameter) + public override void Execute(object parameter) { Application.Current.MainWindow.Hide(); - TaskbarIconCommands.RefreshCommands(); + CommandManager.InvalidateRequerySuggested(); } - public bool CanExecute(object parameter) + public override bool CanExecute(object parameter) { return Application.Current.MainWindow.IsVisible; } - /// - /// Raises the event. - /// - internal void RaiseCanExcecuteChanged() - { - if (CanExecuteChanged != null) CanExecuteChanged(this, EventArgs.Empty); - } - } } diff --git a/Source/Sample Project/Commands/ShowMainWindowCommand.cs b/Source/Sample Project/Commands/ShowMainWindowCommand.cs index 8367ccf..d80e5ce 100644 --- a/Source/Sample Project/Commands/ShowMainWindowCommand.cs +++ b/Source/Sample Project/Commands/ShowMainWindowCommand.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Windows; using System.Windows.Input; @@ -10,29 +9,19 @@ namespace Sample_Project.Commands /// /// Shows the main window. /// - public class ShowMainWindowCommand : ICommand + public class ShowMainWindowCommand : CommandBase { - public event EventHandler CanExecuteChanged; - - public void Execute(object parameter) + public override void Execute(object parameter) { Application.Current.MainWindow.Show(); - TaskbarIconCommands.RefreshCommands(); + CommandManager.InvalidateRequerySuggested(); } - public bool CanExecute(object parameter) + public override bool CanExecute(object parameter) { return Application.Current.MainWindow.IsVisible == false; } - /// - /// Raises the event. - /// - internal void RaiseCanExcecuteChanged() - { - if (CanExecuteChanged != null) CanExecuteChanged(this, EventArgs.Empty); - } - } } diff --git a/Source/Sample Project/Commands/TaskbarIconCommands.cs b/Source/Sample Project/Commands/TaskbarIconCommands.cs deleted file mode 100644 index abcd757..0000000 --- a/Source/Sample Project/Commands/TaskbarIconCommands.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows.Input; - -namespace Sample_Project.Commands -{ - public static class TaskbarIconCommands - { - public static HideMainWindowCommand HideMain { get; set; } - public static ShowMainWindowCommand ShowMain { get; set; } - - - static TaskbarIconCommands() - { - HideMain = new HideMainWindowCommand(); - ShowMain =new ShowMainWindowCommand(); - } - - public static void RefreshCommands() - { - HideMain.RaiseCanExcecuteChanged(); - ShowMain.RaiseCanExcecuteChanged(); - } - } -} diff --git a/Source/Sample Project/FancyBalloon.xaml b/Source/Sample Project/FancyBalloon.xaml new file mode 100644 index 0000000..da723bb --- /dev/null +++ b/Source/Sample Project/FancyBalloon.xaml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/Sample Project/FancyBalloon.xaml.cs b/Source/Sample Project/FancyBalloon.xaml.cs new file mode 100644 index 0000000..ccda58e --- /dev/null +++ b/Source/Sample Project/FancyBalloon.xaml.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Hardcodet.Wpf.TaskbarNotification; + +namespace Sample_Project +{ + /// + /// Interaction logic for FancyBalloon.xaml + /// + public partial class FancyBalloon : UserControl + { + #region BalloonText dependency property + + /// + /// Description + /// + public static readonly DependencyProperty BalloonTextProperty = + DependencyProperty.Register("BalloonText", + typeof (string), + typeof (FancyBalloon), + new FrameworkPropertyMetadata("")); + + /// + /// A property wrapper for the + /// dependency property:
+ /// Description + ///
+ public string BalloonText + { + get { return (string) GetValue(BalloonTextProperty); } + set { SetValue(BalloonTextProperty, value); } + } + + #endregion + + + public FancyBalloon() + { + InitializeComponent(); + } + + + /// + /// Resolves the that displayed + /// the balloon and requests a close action. + /// + private void imgClose_MouseDown(object sender, MouseButtonEventArgs e) + { + //the tray icon assigned this attached property to simplify access + TaskbarIcon taskbarIcon = TaskbarIcon.GetParentTaskbarIcon(this); + taskbarIcon.CloseBalloon(); + } + } +} diff --git a/Source/Sample Project/Sample Project.csproj b/Source/Sample Project/Sample Project.csproj index 9f930c4..7d102c5 100644 --- a/Source/Sample Project/Sample Project.csproj +++ b/Source/Sample Project/Sample Project.csproj @@ -102,7 +102,7 @@ - + @@ -153,6 +153,9 @@ + + + diff --git a/Source/Sample Project/TaskbarIconResources.xaml b/Source/Sample Project/TaskbarIconResources.xaml index bb31716..7e6866d 100644 --- a/Source/Sample Project/TaskbarIconResources.xaml +++ b/Source/Sample Project/TaskbarIconResources.xaml @@ -31,7 +31,7 @@ x:Key="tbMenu"> + Command="{Commands:ShowMainWindowCommand}"> + Command="{Commands:HideMainWindowCommand}"> + SourceName="tb" /> @@ -52,8 +52,9 @@ @@ -148,7 +149,7 @@ You should see a grey LED icon in your system tray. This is your NotifyIcon + TextWrapping="Wrap" Text="You should see a LED icon in your system tray. This is your NotifyIcon."/> -