WPF NotifyIcon

--------------
CHG   Remove PlacementTarget assignment for popups and others. Did not provide advantages, but hid popups if taskbar owner isn't visible.
ADD   Added double click command declaration.

git-svn-id: https://svn.evolvesoftware.ch/repos/evolve.net/WPF/NotifyIcon@83 9f600761-6f11-4665-b6dc-0185e9171623
This commit is contained in:
Philipp Sumi
2009-04-26 17:14:39 +00:00
parent dc0a2167fe
commit d792f1c5a4
5 changed files with 212 additions and 14 deletions

View File

@@ -4,6 +4,7 @@ using System.Drawing;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using Hardcodet.Wpf.TaskbarNotification.Interop;
@@ -207,7 +208,7 @@ namespace Hardcodet.Wpf.TaskbarNotification
{
ImageSource newValue = (ImageSource)e.NewValue;
//resolving the ImageSource at design time probably won't work
//resolving the ImageSource at design time is unlikely to work
if (!Util.IsDesignMode) Icon = newValue.ToIcon();
}
@@ -550,6 +551,169 @@ namespace Hardcodet.Wpf.TaskbarNotification
#endregion
#region DataContext dependency property override
/// <summary>
/// A static callback listener which is being invoked if the
/// <see cref="FrameworkElement.DataContextProperty"/> dependency property has
/// been changed. Invokes the <see cref="OnDataContextPropertyChanged"/>
/// 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 DataContextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
TaskbarIcon owner = (TaskbarIcon) d;
owner.OnDataContextPropertyChanged(e);
}
/// <summary>
/// Handles changes of the <see cref="FrameworkElement.DataContextProperty"/> dependency property. As
/// WPF internally uses the dependency property system and bypasses the
/// <see cref="FrameworkElement.DataContext"/> property wrapper, updates of the property's value
/// should be handled here.
/// </summary
/// <param name="e">Provides information about the updated property.</param>
private void OnDataContextPropertyChanged(DependencyPropertyChangedEventArgs e)
{
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;
}
}
#endregion
#region DoubleClickCommand dependency property
/// <summary>
/// Associates a command that is being executed if the tray icon is being
/// double clicked.
/// </summary>
public static readonly DependencyProperty DoubleClickCommandProperty =
DependencyProperty.Register("DoubleClickCommand",
typeof (ICommand),
typeof (TaskbarIcon),
new FrameworkPropertyMetadata(null));
/// <summary>
/// A property wrapper for the <see cref="DoubleClickCommandProperty"/>
/// dependency property:<br/>
/// Associates a command that is being executed if the tray icon is being
/// double clicked.
/// </summary>
public ICommand DoubleClickCommand
{
get { return (ICommand) GetValue(DoubleClickCommandProperty); }
set { SetValue(DoubleClickCommandProperty, value); }
}
#endregion
#region DoubleClickCommandParameter dependency property
/// <summary>
/// Command parameter for the <see cref="DoubleClickCommand"/>.
/// </summary>
public static readonly DependencyProperty DoubleClickCommandParameterProperty =
DependencyProperty.Register("DoubleClickCommandParameter",
typeof (object),
typeof (TaskbarIcon),
new FrameworkPropertyMetadata(null));
/// <summary>
/// A property wrapper for the <see cref="DoubleClickCommandParameterProperty"/>
/// dependency property:<br/>
/// Command parameter for the <see cref="DoubleClickCommand"/>.
/// </summary>
public object DoubleClickCommandParameter
{
get { return GetValue(DoubleClickCommandParameterProperty); }
set { SetValue(DoubleClickCommandParameterProperty, value); }
}
#endregion
#region LeftClickCommand dependency property
/// <summary>
/// Associates a command that is being executed if the tray icon is being
/// double clicked.
/// </summary>
public static readonly DependencyProperty LeftClickCommandProperty =
DependencyProperty.Register("LeftClickCommand",
typeof (ICommand),
typeof (TaskbarIcon),
new FrameworkPropertyMetadata(null));
/// <summary>
/// A property wrapper for the <see cref="LeftClickCommandProperty"/>
/// dependency property:<br/>
/// Associates a command that is being executed if the tray icon is being
/// double clicked.
/// </summary>
public ICommand LeftClickCommand
{
get { return (ICommand) GetValue(LeftClickCommandProperty); }
set { SetValue(LeftClickCommandProperty, value); }
}
#endregion
#region LeftClickCommandParameter dependency property
/// <summary>
/// Command parameter for the <see cref="LeftClickCommand"/>.
/// </summary>
public static readonly DependencyProperty LeftClickCommandParameterProperty =
DependencyProperty.Register("LeftClickCommandParameter",
typeof (object),
typeof (TaskbarIcon),
new FrameworkPropertyMetadata(null));
/// <summary>
/// A property wrapper for the <see cref="LeftClickCommandParameterProperty"/>
/// dependency property:<br/>
/// Command parameter for the <see cref="LeftClickCommand"/>.
/// </summary>
public object LeftClickCommandParameter
{
get { return GetValue(LeftClickCommandParameterProperty); }
set { SetValue(LeftClickCommandParameterProperty, value); }
}
#endregion
/// <summary>
/// Executes a given command.
/// </summary>
/// <param name="command">The command to be executed.</param>
/// <param name="commandParameter">An optional parameter that was associated with
/// the command.</param>
private static void RunCommand(ICommand command, object commandParameter)
{
if (command == null) return;
if (command.CanExecute(commandParameter))
{
command.Execute(commandParameter);
}
}
//EVENTS
@@ -576,7 +740,10 @@ namespace Hardcodet.Wpf.TaskbarNotification
/// </summary>
protected RoutedEventArgs RaiseTrayLeftMouseDownEvent()
{
return RaiseTrayLeftMouseDownEvent(this);
//first raise event, then command
RoutedEventArgs args = RaiseTrayLeftMouseDownEvent(this);
RunCommand(LeftClickCommand, LeftClickCommandParameter);
return args;
}
/// <summary>
@@ -824,7 +991,9 @@ namespace Hardcodet.Wpf.TaskbarNotification
/// </summary>
protected RoutedEventArgs RaiseTrayMouseDoubleClickEvent()
{
return RaiseTrayMouseDoubleClickEvent(this);
RoutedEventArgs args = RaiseTrayMouseDoubleClickEvent(this);
RunCommand(DoubleClickCommand, DoubleClickCommandParameter);
return args;
}
/// <summary>
@@ -1515,6 +1684,11 @@ namespace Hardcodet.Wpf.TaskbarNotification
//register change listener for the Visibility property
PropertyMetadata md = new PropertyMetadata(Visibility.Visible, VisibilityPropertyChanged);
VisibilityProperty.OverrideMetadata(typeof(TaskbarIcon), md);
//register change listener for the DataContext property
md = new FrameworkPropertyMetadata(new PropertyChangedCallback(DataContextPropertyChanged));
DataContextProperty.OverrideMetadata(typeof(TaskbarIcon), md);
}
}
}

View File

@@ -149,17 +149,24 @@ 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;
//don't animate by default - devs can use attached
//events or override
popup.PopupAnimation = animation;
Popup.CreateRootPopup(popup, balloon);
popup.PlacementTarget = this;
//TODO we don't really need this and it causes the popup to become hidden if the
//TaskbarIcon's parent is hidden, too...
//popup.PlacementTarget = this;
popup.Placement = PlacementMode.AbsolutePoint;
popup.StaysOpen = true;
@@ -332,10 +339,9 @@ namespace Hardcodet.Wpf.TaskbarNotification
if (visible)
{
if (ContextMenu != null && ContextMenu.IsOpen ||
TrayPopupResolved != null && TrayPopupResolved.IsOpen)
if (IsPopupOpen)
{
//ignore if we have an open context menu or popup
//ignore if we are already displaying something down there
return;
}
@@ -389,7 +395,10 @@ namespace Hardcodet.Wpf.TaskbarNotification
//create an invisible tooltip that hosts the UIElement
tt = new ToolTip();
tt.Placement = PlacementMode.Mouse;
tt.PlacementTarget = this;
//TODO we don't really need this and it causes the popup to become hidden if the
//TaskbarIcon's parent is hidden, too.
//tt.PlacementTarget = this;
//the tooltip (and implicitly its context) explicitly gets
//the DataContext of this instance. If there is no DataContext,
@@ -484,7 +493,10 @@ namespace Hardcodet.Wpf.TaskbarNotification
Popup.CreateRootPopup(popup, TrayPopup);
popup.PlacementTarget = this;
//TODO we don't really need this and it causes the popup to become hidden if the
//TaskbarIcon's parent is hidden, too.
//popup.PlacementTarget = this;
popup.Placement = PlacementMode.AbsolutePoint;
popup.StaysOpen = false;
}

View File

@@ -72,6 +72,7 @@
Language="de-ch" /></TextBlock>
<Button
Click="OnButtonClick"
ToolTip="{Binding Path=ToolTipText}"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
Width="89"

View File

@@ -10,7 +10,8 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:local="clr-namespace:Sample_Project" MinWidth="750" MinHeight="800">
xmlns:local="clr-namespace:Sample_Project"
xmlns:Commands="clr-namespace:Sample_Project.Commands" MinWidth="750" MinHeight="800">
<Window.Resources>
<BooleanToVisibilityConverter
@@ -63,7 +64,9 @@
ToolTipText="{Binding Path=Text, ElementName=txtToolTipText, Mode=Default}"
Visibility="{Binding Path=IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, ElementName=iconVisibility, Mode=Default}"
MenuActivation="{Binding Path=SelectedItem, ElementName=lstMenuTrigger, Mode=Default}"
PopupActivation="{Binding Path=SelectedItem, ElementName=lstPopupTrigger, Mode=Default}">
PopupActivation="{Binding Path=SelectedItem, ElementName=lstPopupTrigger, Mode=Default}"
DoubleClickCommand="{Binding Source={x:Static Commands:TaskbarIconCommands.ShowMain}}"
>
<tb:TaskbarIcon.TrayPopup>
<!-- the control will be put into a popup with an explicit DataContext -->
@@ -141,10 +144,11 @@
Margin="125,0,17,133"
x:Name="txtBalloonTitle"
VerticalAlignment="Bottom"
Height="23" />
Height="23">WPF NotifyIcon</TextBox>
<TextBox
Margin="125,0,17,76"
x:Name="txtBalloonText" AcceptsReturn="True" Height="47" VerticalAlignment="Bottom" d:LayoutOverrides="VerticalAlignment" />
x:Name="txtBalloonText" AcceptsReturn="True" Height="47" VerticalAlignment="Bottom" d:LayoutOverrides="VerticalAlignment"
TextWrapping="Wrap">You should see a grey LED icon in your system tray. This is your NotifyIcon</TextBox>
<RadioButton
HorizontalAlignment="Left"
Margin="14,0,0,54"
@@ -377,7 +381,7 @@
<Border HorizontalAlignment="Stretch" Width="Auto" BorderThickness="2,2,2,2" BorderBrush="#FF000000"/>
<Button Content="Display Message" x:Name="showCustomBalloon"
Click="showCustomBalloon_Click" HorizontalAlignment="Right" Margin="0,0,24.377,10.52" Width="107.623" Height="23" VerticalAlignment="Bottom" />
<TextBox VerticalAlignment="Bottom" Height="23" Text="Balloon Title" TextWrapping="Wrap" Margin="10,0,173,10" x:Name="customBalloonTitle"/>
<TextBox VerticalAlignment="Bottom" Height="23" Text="WPF Balloon" TextWrapping="Wrap" Margin="10,0,173,10" x:Name="customBalloonTitle"/>
<TextBlock Margin="10,10,24.377,0" VerticalAlignment="Top" TextWrapping="Wrap"><Run Text="Custom Balloon Tips are more flexible then standard tips when it comes to styling..." Language="de-ch"/></TextBlock>
</Grid>
</Grid>

View File

@@ -12,6 +12,13 @@ namespace Sample_Project
public Window1()
{
InitializeComponent();
Loaded += delegate
{
//show balloon at startup, pointing to the icon
showBalloonTip_Click(null, null);
};
}