WPF NotifyIcon

--------------
CHG   Changed show/hide functionality in order to work better with showcase window (which is no longer the app's main window).

git-svn-id: https://svn.evolvesoftware.ch/repos/evolve.net/WPF/NotifyIcon@105 9f600761-6f11-4665-b6dc-0185e9171623
This commit is contained in:
Philipp Sumi
2009-05-16 12:14:02 +00:00
parent 97ef369a02
commit c8c988bb17
16 changed files with 219 additions and 207 deletions

View File

@@ -3,6 +3,8 @@ using System.ComponentModel;
using System.Windows;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using Hardcodet.Wpf.TaskbarNotification;
namespace Samples.Commands
{
@@ -73,5 +75,84 @@ namespace Samples.Commands
.Metadata.DefaultValue;
}
}
/// <summary>
/// Resolves the window that owns the TaskbarIcon class.
/// </summary>
/// <param name="commandParameter"></param>
/// <returns></returns>
protected Window GetTaskbarWindow(object commandParameter)
{
if (IsDesignMode) return null;
//get the showcase window off the taskbaricon
var tb = commandParameter as TaskbarIcon;
return tb == null ? null : TryFindParent<Window>(tb);
}
#region TryFindParent helper
/// <summary>
/// Finds a parent of a given item on the visual tree.
/// </summary>
/// <typeparam name="T">The type of the queried item.</typeparam>
/// <param name="child">A direct or indirect child of the
/// queried item.</param>
/// <returns>The first parent item that matches the submitted
/// type parameter. If not matching item can be found, a null
/// reference is being returned.</returns>
public static T TryFindParent<T>(DependencyObject child)
where T : DependencyObject
{
//get parent item
DependencyObject parentObject = GetParentObject(child);
//we've reached the end of the tree
if (parentObject == null) return null;
//check if the parent matches the type we're looking for
T parent = parentObject as T;
if (parent != null)
{
return parent;
}
else
{
//use recursion to proceed with next level
return TryFindParent<T>(parentObject);
}
}
/// <summary>
/// This method is an alternative to WPF's
/// <see cref="VisualTreeHelper.GetParent"/> method, which also
/// supports content elements. Keep in mind that for content element,
/// this method falls back to the logical tree of the element!
/// </summary>
/// <param name="child">The item to be processed.</param>
/// <returns>The submitted item's parent, if available. Otherwise
/// null.</returns>
public static DependencyObject GetParentObject(DependencyObject child)
{
if (child == null) return null;
ContentElement contentElement = child as ContentElement;
if (contentElement != null)
{
DependencyObject parent = ContentOperations.GetParent(contentElement);
if (parent != null) return parent;
FrameworkContentElement fce = contentElement as FrameworkContentElement;
return fce != null ? fce.Parent : null;
}
//if it's not a ContentElement, rely on VisualTreeHelper
return VisualTreeHelper.GetParent(child);
}
#endregion
}
}

View File

@@ -6,19 +6,20 @@ namespace Samples.Commands
/// <summary>
/// Hides the main window.
/// </summary>
public class HideMainWindowCommand : CommandBase<HideMainWindowCommand>
public class HideSampleWindowCommand : CommandBase<HideSampleWindowCommand>
{
public override void Execute(object parameter)
{
Application.Current.MainWindow.Hide();
GetTaskbarWindow(parameter).Hide();
CommandManager.InvalidateRequerySuggested();
}
public override bool CanExecute(object parameter)
{
return !IsDesignMode && Application.Current.MainWindow.IsVisible;
Window win = GetTaskbarWindow(parameter);
return win != null && win.IsVisible;
}

View File

@@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;
namespace Samples.Commands
{
/// <summary>
/// Shows the main window.
/// </summary>
public class ShowMainWindowCommand : CommandBase<ShowMainWindowCommand>
{
public override void Execute(object parameter)
{
Application.Current.MainWindow.Show();
CommandManager.InvalidateRequerySuggested();
}
public override bool CanExecute(object parameter)
{
return !IsDesignMode && Application.Current.MainWindow.IsVisible == false;
}
}
}

View File

@@ -0,0 +1,24 @@
using System.Windows;
using System.Windows.Input;
namespace Samples.Commands
{
/// <summary>
/// Shows the main window.
/// </summary>
public class ShowSampleWindowCommand : CommandBase<ShowSampleWindowCommand>
{
public override void Execute(object parameter)
{
GetTaskbarWindow(parameter).Show();
CommandManager.InvalidateRequerySuggested();
}
public override bool CanExecute(object parameter)
{
Window win = GetTaskbarWindow(parameter);
return win != null && !win.IsVisible;
}
}
}

View File

@@ -3,8 +3,8 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Main"
Height="595"
Width="596"
Height="563"
Width="703"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
@@ -31,8 +31,7 @@
FontStyle="Italic"
FontWeight="Bold"
TextWrapping="Wrap"><Run
Text="WPF NotifyIcon 1.0.1 - Samples"
/></TextBlock>
Text="WPF NotifyIcon 1.0.1 - Samples" /></TextBlock>
<Button
HorizontalAlignment="Left"
Margin="10,133,0,0"
@@ -48,8 +47,7 @@
VerticalAlignment="Top"
FontWeight="Bold"
TextWrapping="Wrap"><Run
Text="Tutorials:"
/></TextBlock>
Text="Tutorials:" /></TextBlock>
<TextBlock
HorizontalAlignment="Left"
Margin="10,75.96,0,0"
@@ -58,8 +56,7 @@
Width="224.31"
Height="47.04"
d:LayoutOverrides="HorizontalAlignment"><Run
Text="Tutorials follow the contents of the CodeProject article. Check the &quot;Tutorials&quot; folder for the source code."
/></TextBlock>
Text="Tutorials follow the contents of the CodeProject article. Check the &quot;Tutorials&quot; folder for the source code." /></TextBlock>
<Button
HorizontalAlignment="Left"
Margin="10,170,0,0"
@@ -115,59 +112,53 @@
x:Name="btnToolTipControl"
Click="btnToolTipControl_Click" />
<TextBlock
Margin="0,50,166.627,0"
Margin="0,50,328.76,0"
VerticalAlignment="Top"
FontWeight="Bold"
TextWrapping="Wrap"
HorizontalAlignment="Right"
d:LayoutOverrides="HorizontalAlignment, Width"><Run
Text="Showcase Sample:"
/></TextBlock>
Text="Showcase Sample:" /></TextBlock>
<TextBlock
Margin="0,75.96,90.247,0"
Margin="255.31,75.96,145.38,0"
VerticalAlignment="Top"
TextWrapping="Wrap"
Height="47.04"
HorizontalAlignment="Right"
Width="179.31"><Run
Text="An interactive sample that shows off most features on a single NotifyIcon."
/></TextBlock>
Height="47.04"><Run
Text="An interactive sample that shows off most features on a single NotifyIcon." /></TextBlock>
<Button
HorizontalAlignment="Right"
Margin="0,133,105.557,0"
Margin="255.31,133,0,0"
VerticalAlignment="Top"
Width="164"
Height="27"
Content="Open Sample Window"
x:Name="btnMainSample"
Click="btnMainSample_Click" />
Click="btnMainSample_Click"
Width="164"
HorizontalAlignment="Left" />
<Path
Fill="#FFFFFFFF"
Stretch="Fill"
Stroke="#FF60758A"
HorizontalAlignment="Left"
Margin="269,57,0,172"
Margin="244.31,50,0,66"
Width="1"
Data="M269,57 L269,390.18163" />
<TextBlock
Margin="10,413,20,0"
Margin="255.31,191,10,0"
TextWrapping="Wrap"
VerticalAlignment="Top"
Height="102.76"><Run
Text="You will always find the latest news related to the component on the project page:"
/><LineBreak />
<Hyperlink
NavigateUri="http://www.hardcodet.net/wpf-notifyicon">http://www.hardcodet.net/wpf-notifyicon</Hyperlink>
<LineBreak /><Run
Text=""
/><LineBreak /><Run
Text="Critical feedback is appreciated - please post bug reports, requests, questions etc. to the CodeProject forum @"
/>
<Hyperlink
NavigateUri="http://www.codeproject.com/wpf-notifyicon">http://www.codeproject.com/wpf-notifyicon</Hyperlink>
<LineBreak /><Run
Text="And if you love it or hate it, please let me know and leave your rating - thanks!"
/></TextBlock>
VerticalAlignment="Top"><Run
Text="You will always find the latest news related to the component on the project page:" /><LineBreak /><Hyperlink
NavigateUri="http://www.hardcodet.net/wpf-notifyicon"><Run
Text="http://www.hardcodet.net/wpf-notifyicon" /></Hyperlink><LineBreak /><Run
Text="" /><LineBreak /><Run
Text="Critical feedback is appreciated - please post bug reports, requests, questions etc. to the CodeProject forum" /><Run
Language="de-ch"
Text=":" /><LineBreak /><Hyperlink
NavigateUri="http://www.codeproject.com/KB/WPF/wpf_notifyicon.aspx"><Run
Text="http://www.codeproject.com/KB/WPF/wpf_notifyicon.aspx" /></Hyperlink><LineBreak /><Run
Text="" /><LineBreak /><Run
Language="de-ch"
Text="I" /><Run
Text="f you love it or hate it, please let me know and leave your rating - thanks!" /></TextBlock>
<TextBlock
Margin="10,0,10,10"
VerticalAlignment="Bottom"
@@ -186,6 +177,24 @@
VerticalAlignment="Bottom"
Height="1"
Data="M11,517 L561.07363,517" />
<Button
HorizontalAlignment="Left"
Margin="11,397,0,0"
Width="164"
Content="Events"
VerticalAlignment="Top"
Height="27"
x:Name="btnEvents"
Click="btnEvents_Click" />
<Button
HorizontalAlignment="Left"
Margin="11,434,0,0"
Width="164"
Content="Data Binding"
VerticalAlignment="Top"
Height="27"
x:Name="btnDataBinding"
Click="btnDataBinding_Click" />
</Grid>
</Window>

View File

@@ -16,6 +16,8 @@ using Samples.Tutorials;
using Samples.Tutorials.Balloons;
using Samples.Tutorials.Commands;
using Samples.Tutorials.ContextMenus;
using Samples.Tutorials.DataBinding;
using Samples.Tutorials.Events;
using Samples.Tutorials.Popups;
using Samples.Tutorials.ToolTips;
@@ -82,6 +84,16 @@ namespace Samples
ShowDialog(new CommandWindow());
}
private void btnEvents_Click(object sender, RoutedEventArgs e)
{
ShowDialog(new EventVisualizerWindow());
}
private void btnDataBinding_Click(object sender, RoutedEventArgs e)
{
ShowDialog(new DataBoundToolTipWindow());
}
private void btnMainSample_Click(object sender, RoutedEventArgs e)
{
var sampleWindow = new ShowcaseWindow();
@@ -98,8 +110,5 @@ namespace Samples
e.Handled = true;
}
}
}

View File

@@ -155,8 +155,8 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Commands\CommandBase.cs" />
<Compile Include="Commands\HideMainWindowCommand.cs" />
<Compile Include="Commands\ShowMainWindowCommand.cs" />
<Compile Include="Commands\HideSampleWindowCommand.cs" />
<Compile Include="Commands\ShowSampleWindowCommand.cs" />
<Compile Include="Showcase\FancyBalloon.xaml.cs">
<DependentUpon>FancyBalloon.xaml</DependentUpon>
</Compile>

View File

@@ -27,9 +27,14 @@
</Setter>
</Style>
<!-- The taskbar context menu - the first row is a dummy to show of simple data binding -->
<!--
The "shared" directive is needed if we reopen the sample a few times - WPF will otherwise
reuse the same context menu again (which will have its DataContext set to the old TaskbarIcon)
-->
<ContextMenu
x:Shared="false"
x:Key="tbMenu">
<MenuItem
IsEnabled="False"
@@ -43,8 +48,9 @@
</MenuItem>
<MenuItem
Header="Show Main Window"
Command="{Commands:ShowMainWindowCommand}">
Header="Show Showcase Window"
Command="{Commands:ShowSampleWindowCommand}"
CommandParameter="{Binding}">
<MenuItem.Icon>
<Image
Width="16"
@@ -56,8 +62,9 @@
<Separator />
<MenuItem
Header="Hide Main Window"
Command="{Commands:HideMainWindowCommand}">
Header="Hide Showcase Window"
Command="{Commands:HideSampleWindowCommand}"
CommandParameter="{Binding}">
<MenuItem.Icon>
<Image
Width="16"
@@ -68,88 +75,4 @@
</ContextMenu>
<ToolTip
x:Key="tbToolTip"
Background="Transparent"
BorderThickness="0"
HasDropShadow="False"
VerticalOffset="-10"
>
<Grid
>
<Border
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Width="Auto"
Height="Auto"
CornerRadius="6,6,6,6"
BorderThickness="3,3,3,3"
Margin="0,0,5,5">
<Border.Effect>
<DropShadowEffect
Color="#FF7A7A7A" />
</Border.Effect>
<Border.Background>
<LinearGradientBrush
EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop
Color="#FFFFD283"
Offset="0" />
<GradientStop
Color="#FFFFFFFF"
Offset="1" />
</LinearGradientBrush>
</Border.Background>
</Border>
<Image
HorizontalAlignment="Left"
Margin="10,10,0,26"
Width="72"
Source="Images\Info.png"
Stretch="Fill"
VerticalAlignment="Top"
RenderTransformOrigin="0.792,0.486" />
<TextBlock
Margin="82,10,20,0"
TextWrapping="Wrap"
Height="32"
VerticalAlignment="Top"
FontSize="16"
FontWeight="Bold"
Foreground="#FF575757"><Run
Text="This is a fancy ToolTip..."
Language="de-ch" /></TextBlock>
<TextBlock
FontSize="12"
FontWeight="Normal"
Foreground="#FF141414"
TextWrapping="Wrap"
Margin="82,52,20,0"
VerticalAlignment="Top"
Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type tb:TaskbarIcon}}, Path=ToolTipText}"
/>
</Grid>
</ToolTip>
<!--
As we don't declare the popup with the control, use
commands to trigger an action.
-->
<Popup
x:Key="tbPopupSimple"
PopupAnimation="Slide"
Placement="Mouse"
AllowsTransparency="True"
StaysOpen="False"
>
<Border
Width="200"
Height="200"
Background="Red">
<Button>Click me</Button>
</Border>
</Popup>
</ResourceDictionary>

View File

@@ -70,7 +70,9 @@
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}"
DoubleClickCommand="{Commands:ShowMainWindowCommand}">
DoubleClickCommand="{Commands:ShowSampleWindowCommand}"
DoubleClickCommandParameter="{Binding RelativeSource={RelativeSource Self}}"
>
<tb:TaskbarIcon.TrayPopup>
<!-- the control will be put into a popup with an explicit DataContext -->

View File

@@ -253,9 +253,7 @@
VerticalAlignment="Top"
Height="31"
TextWrapping="Wrap"
FontWeight="Bold"><Run
Language="de-ch"
Text="The green elipses are animated based on routed events of the NotifyIcon" /></TextBlock>
FontWeight="Bold"><Run Language="de-ch" Text="The green ellipses are animated based on routed events of the NotifyIcon"/></TextBlock>
</Grid>
</Window>

View File

@@ -1,15 +1,4 @@
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.Shapes;
using System.Windows;
namespace Samples.Tutorials.Events
{

View File

@@ -4,12 +4,12 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tb="http://www.hardcodet.net/taskbar"
Height="300"
Width="300">
Width="500">
<Grid>
<!-- the ToolTipText property is bound to the TextBox below -->
<tb:TaskbarIcon
x:Name="MyNotifyIcon"
x:Name="MyNotifyIcon1"
IconSource="/Icons/Error.ico"
ToolTipText="{Binding ElementName=txtToolTip, Path=Text}">
@@ -36,16 +36,19 @@
</tb:TaskbarIcon>
<!-- the ToolTipText property is bound to the TextBox below -->
<!-- This NotifyIcon has its DataContext set - implicit binding is no longer possible -->
<tb:TaskbarIcon
x:Name="MyNotifyIcon2"
DataContext="WPF IS GREAT: "
IconSource="/Icons/Inactive.ico"
ToolTipText="{Binding ElementName=txtToolTip, Path=Text}">
<!--
The TextBlock bound to the ToolTipText property of the NotifyIcon
The binding is explicit (via attached ParentTaskbarIcon property)
-->
<tb:TaskbarIcon.TrayToolTip>
<!--
Important: The attached property is assigned to the border!
The NotifyIcon does not touch the underlying controls.
-->
<Border
Background="White"
BorderBrush="Orange"
@@ -54,10 +57,16 @@
Opacity="0.8"
Width="160"
Height="40">
<!-- Implicitly access the DataContext (which is a string this time)-->
<TextBlock Text="{Binding}">
<!-- Explicitly access the NotifyIcon -->
<TextBlock
Text="{Binding (tb:TaskbarIcon.ParentTaskbarIcon), Path=ToolTipText}"
Text="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type Border}},
Path=(tb:TaskbarIcon.ParentTaskbarIcon).ToolTipText}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</TextBlock>
</Border>
</tb:TaskbarIcon.TrayToolTip>

View File

@@ -1,15 +1,4 @@
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.Shapes;
using System.Windows;
namespace Samples.Tutorials.DataBinding
{
@@ -27,9 +16,10 @@ namespace Samples.Tutorials.DataBinding
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
//clean up notifyicon (would otherwise stay open until application finishes)
MyNotifyIcon.Dispose();
MyNotifyIcon1.Dispose();
MyNotifyIcon2.Dispose();
base.OnClosing(e);
}
}
}
}