Squashed 'NotifyIconWpf/' content from commit f64d48e

git-subtree-dir: NotifyIconWpf
git-subtree-split: f64d48ec604eef26e5dc1e7c2d5e1e91b329ffac
This commit is contained in:
maier_S
2022-03-23 10:25:49 +01:00
commit fd19b09320
31 changed files with 5633 additions and 0 deletions

400
.gitignore vendored Normal file
View File

@@ -0,0 +1,400 @@
# ---> VisualStudio
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
##
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
# User-specific files
*.rsuser
*.suo
*.user
*.userosscache
*.sln.docstates
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
# Mono auto generated files
mono_crash.*
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
x64/
x86/
[Ww][Ii][Nn]32/
[Aa][Rr][Mm]/
[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
[Ll]ogs/
# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
# Visual Studio 2017 auto generated files
Generated\ Files/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
# NUnit
*.VisualState.xml
TestResult.xml
nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
# Benchmark Results
BenchmarkDotNet.Artifacts/
# .NET Core
project.lock.json
project.fragment.lock.json
artifacts/
# ASP.NET Scaffolding
ScaffoldingReadMe.txt
# StyleCop
StyleCopReport.xml
# Files built by Visual Studio
*_i.c
*_p.c
*_h.h
*.ilk
*.meta
*.obj
*.iobj
*.pch
*.pdb
*.ipdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*_wpftmp.csproj
*.log
*.tlog
*.vspscc
*.vssscc
.builds
*.pidb
*.svclog
*.scc
# Chutzpah Test files
_Chutzpah*
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opendb
*.opensdf
*.sdf
*.cachefile
*.VC.db
*.VC.VC.opendb
# Visual Studio profiler
*.psess
*.vsp
*.vspx
*.sap
# Visual Studio Trace Files
*.e2e
# TFS 2012 Local Workspace
$tf/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# AxoCover is a Code Coverage Tool
.axoCover/*
!.axoCover/settings.json
# Coverlet is a free, cross platform Code Coverage Tool
coverage*.json
coverage*.xml
coverage*.info
# Visual Studio code coverage results
*.coverage
*.coveragexml
# NCrunch
_NCrunch_*
.*crunch*.local.xml
nCrunchTemp_*
# MightyMoose
*.mm.*
AutoTest.Net/
# Web workbench (sass)
.sass-cache/
# Installshield output folder
[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
# Note: Comment the next line if you want to checkin your web deploy settings,
# but database connection strings (with potential passwords) will be unencrypted
*.pubxml
*.publishproj
# Microsoft Azure Web App publish settings. Comment the next line if you want to
# checkin your Azure Web App publish settings, but sensitive information contained
# in these scripts will be unencrypted
PublishScripts/
# NuGet Packages
*.nupkg
# NuGet Symbol Packages
*.snupkg
# The packages folder can be ignored because of Package Restore
**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/[Pp]ackages/repositories.config
# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
# Microsoft Azure Build Output
csx/
*.build.csdef
# Microsoft Azure Emulator
ecf/
rcf/
# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
Package.StoreAssociation.xml
_pkginfo.txt
*.appx
*.appxbundle
*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
!?*.[Cc]ache/
# Others
ClientBin/
~$*
*~
*.dbmdl
*.dbproj.schemaview
*.jfm
*.pfx
*.publishsettings
orleans.codegen.cs
# Including strong name files can present a security risk
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
#*.snk
# Since there are multiple workflows, uncomment next line to ignore bower_components
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
#bower_components/
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file
# to a newer Visual Studio version. Backup files are not needed,
# because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
ServiceFabricBackup/
*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
*.rptproj.rsuser
*- [Bb]ackup.rdl
*- [Bb]ackup ([0-9]).rdl
*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
# GhostDoc plugin setting file
*.GhostDoc.xml
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
node_modules/
# Visual Studio 6 build log
*.plg
# Visual Studio 6 workspace options file
*.opt
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
*.vbw
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
*.vbp
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
*.dsw
*.dsp
# Visual Studio 6 technical files
*.ncb
*.aps
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
**/*.DesktopClient/ModelManifest.xml
**/*.Server/GeneratedArtifacts
**/*.Server/ModelManifest.xml
_Pvt_Extensions
# Paket dependency manager
.paket/paket.exe
paket-files/
# FAKE - F# Make
.fake/
# CodeRush personal settings
.cr/personal
# Python Tools for Visual Studio (PTVS)
__pycache__/
*.pyc
# Cake - Uncomment if you are using it
# tools/**
# !tools/packages.config
# Tabs Studio
*.tss
# Telerik's JustMock configuration file
*.jmconfig
# BizTalk build output
*.btp.cs
*.btm.cs
*.odx.cs
*.xsd.cs
# OpenCover UI analysis results
OpenCover/
# Azure Stream Analytics local run output
ASALocalRun/
# MSBuild Binary and Structured Log
*.binlog
# NVidia Nsight GPU debugger configuration file
*.nvuser
# MFractors (Xamarin productivity tool) working folder
.mfractor/
# Local History for Visual Studio
.localhistory/
# Visual Studio History (VSHistory) files
.vshistory/
# BeatPulse healthcheck temp database
healthchecksdb
# Backup folder for Package Reference Convert tool in Visual Studio 2017
MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder
.ionide/
# Fody - auto-generated XML schema
FodyWeavers.xsd
# VS Code files for those working on multiple tools
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
*.code-workspace
# Local History for Visual Studio Code
.history/
# Windows Installer files from build outputs
*.cab
*.msi
*.msix
*.msm
*.msp
# JetBrains Rider
*.sln.iml

81
Directory.Build.props Normal file
View File

@@ -0,0 +1,81 @@
<Project>
<PropertyGroup>
<TargetFrameworks>net45;net462;net472;netcoreapp3.1;net5.0-windows</TargetFrameworks>
<LangVersion>latest</LangVersion>
<UseWindowsForms>true</UseWindowsForms>
<UseWPF>true</UseWPF>
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
<IsSampleProject>$(MSBuildProjectName.Contains('Sample'))</IsSampleProject>
<DebugSymbols>True</DebugSymbols>
<DebugType>embedded</DebugType>
<Copyright>Copyright (c) 2009-2021 Philipp Sumi</Copyright>
<Company>hardcodet.net</Company>
<Authors>Philipp Sumi, Robin Krom, Jan Karger</Authors>
<PackageIcon>icon.png</PackageIcon>
<RepositoryUrl>https://github.com/hardcodet/wpf-notifyicon</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageProjectUrl>https://github.com/hardcodet/wpf-notifyicon</PackageProjectUrl>
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<Description>This is an implementation of a NotifyIcon (aka system tray icon or taskbar icon) for the WPF platform. It does not just rely on the Windows Forms NotifyIcon component, but is a purely independent control which leverages several features of the WPF framework in order to display rich tooltips, popups, context menus, and balloon messages. It can be used directly in code or embedded in any XAML file.
Source code and extensive sample application available at http://www.hardcodet.net/projects/wpf-notifyicon</Description>
<Summary>NotifyIcon (aka system tray icon or taskbar icon) for the WPF platform.</Summary>
<tags>NotifyIcon WPF Tray Notify ToolTip Popup Balloon Toast</tags>
</PropertyGroup>
<PropertyGroup Condition="$(TargetFramework.StartsWith('net4'))">
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
<Choose>
<When Condition=" '$(IsSampleProject)' != 'true' ">
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<IsPackable>true</IsPackable>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
</PropertyGroup>
<PropertyGroup>
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>..\NotifyIconWpf.snk</AssemblyOriginatorKeyFile>
<DelaySign>false</DelaySign>
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
<None Include="$(SolutionDir)\icon.png" Pack="true" PackagePath="\"/>
</ItemGroup>
<!-- SourceLink -->
<PropertyGroup>
<!-- Optional: Declare that the Repository URL can be published to NuSpec -->
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<!-- Optional: Embed source files that are not tracked by the source control manager to the PDB -->
<EmbedUntrackedSources>true</EmbedUntrackedSources>
<!-- https://github.com/dotnet/sourcelink/blob/master/docs/README.md#embedallsources -->
<EmbedAllSources>true</EmbedAllSources>
</PropertyGroup>
</When>
</Choose>
<ItemGroup>
<None Remove="**\*.png;**\*.jpg;**\*.ico" />
<Resource Include="**\*.png;**\*.jpg;**\*.ico" />
<None Include="..\..\LICENSE" Pack="true" PackagePath="" />
</ItemGroup>
</Project>

25
NotifyIconWpf.sln Normal file
View File

@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.32112.339
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotifyIconWpf", "NotifyIconWpf\NotifyIconWpf.csproj", "{78E6F5E5-11F1-4840-BA37-87522806DEDF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{78E6F5E5-11F1-4840-BA37-87522806DEDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{78E6F5E5-11F1-4840-BA37-87522806DEDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{78E6F5E5-11F1-4840-BA37-87522806DEDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{78E6F5E5-11F1-4840-BA37-87522806DEDF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DE07A147-0D17-4667-A1F7-7076FDFF4AEA}
EndGlobalSection
EndGlobal

BIN
NotifyIconWpf.snk Normal file

Binary file not shown.

View File

@@ -0,0 +1,52 @@
// hardcodet.net NotifyIcon for WPF
// Copyright (c) 2009 - 2020 Philipp Sumi
// Contact and Information: http://www.hardcodet.net
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Code Project Open License (CPOL);
// either version 1.0 of the License, or (at your option) any later
// version.
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE
namespace Hardcodet.Wpf.TaskbarNotification
{
///<summary>
/// Supported icons for the tray's balloon messages.
///</summary>
public enum BalloonIcon
{
/// <summary>
/// The balloon message is displayed without an icon.
/// </summary>
None,
/// <summary>
/// An information is displayed.
/// </summary>
Info,
/// <summary>
/// A warning is displayed.
/// </summary>
Warning,
/// <summary>
/// An error is displayed.
/// </summary>
Error
}
}

View File

@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<ClassDiagram MajorVersion="1" MinorVersion="1">
<Class Name="Hardcodet.Wpf.TaskbarNotification.TaskbarIcon">
<Position X="1.75" Y="0.5" Width="3.5" />
<Compartments>
<Compartment Name="Fields" Collapsed="true" />
<Compartment Name="Methods" Collapsed="true" />
</Compartments>
<TypeIdentifier>
<HashCode>N6qdVIeUdLmQtSUbiJhEGdYRjvJYXlhbEVBDKuPRO5s=</HashCode>
<FileName>TaskbarIcon.cs</FileName>
</TypeIdentifier>
<Lollipop Position="0.2" />
</Class>
<Enum Name="Hardcodet.Wpf.TaskbarNotification.PopupActivationMode">
<Position X="6.75" Y="0.5" Width="2" />
<TypeIdentifier>
<HashCode>ABAEAAAAAAAAAAABAAAAAAAAAAAAAAAAAIAKAIAAAAA=</HashCode>
<FileName>PopupActivationMode.cs</FileName>
</TypeIdentifier>
</Enum>
<Enum Name="Hardcodet.Wpf.TaskbarNotification.BalloonIcon">
<Position X="9.25" Y="0.5" Width="1.5" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAQAAAAAAABAAAAAAAAAAAAAAAEEAAAA=</HashCode>
<FileName>BalloonIcon.cs</FileName>
</TypeIdentifier>
</Enum>
<Font Name="Segoe UI" Size="9" />
</ClassDiagram>

View File

@@ -0,0 +1,133 @@
// Some interop code taken from Mike Marshall's AnyForm
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// This contains the logic to access the location of the app bar and communicate with it.
/// </summary>
public class AppBarInfo
{
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("shell32.dll")]
private static extern uint SHAppBarMessage(uint dwMessage, ref APPBARDATA data);
[DllImport("user32.dll")]
private static extern int SystemParametersInfo(uint uiAction, uint uiParam,
IntPtr pvParam, uint fWinIni);
private const int ABM_GETTASKBARPOS = 0x00000005;
private APPBARDATA m_data;
/// <summary>
/// Get on which edge the app bar is located
/// </summary>
public ScreenEdge Edge
{
get { return (ScreenEdge) m_data.uEdge; }
}
/// <summary>
/// Get the working area
/// </summary>
public Rectangle WorkArea
{
get { return GetRectangle(m_data.rc); }
}
private Rectangle GetRectangle(RECT rc)
{
return new Rectangle(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
}
/// <summary>
/// Update the location of the appbar with the specified classname and window name.
/// </summary>
/// <param name="strClassName">string</param>
/// <param name="strWindowName">string</param>
private void GetPosition(string strClassName, string strWindowName)
{
m_data = new APPBARDATA();
m_data.cbSize = (uint) Marshal.SizeOf(m_data.GetType());
IntPtr hWnd = FindWindow(strClassName, strWindowName);
if (hWnd != IntPtr.Zero)
{
uint uResult = SHAppBarMessage(ABM_GETTASKBARPOS, ref m_data);
if (uResult != 1)
{
throw new Exception("Failed to communicate with the given AppBar");
}
}
else
{
throw new Exception("Failed to find an AppBar that matched the given criteria");
}
}
/// <summary>
/// Updates the system taskbar position
/// </summary>
public void GetSystemTaskBarPosition()
{
GetPosition("Shell_TrayWnd", null);
}
/// <summary>
/// A value that specifies an edge of the screen.
/// </summary>
public enum ScreenEdge
{
/// <summary>
/// Undefined
/// </summary>
Undefined = -1,
/// <summary>
/// Left edge.
/// </summary>
Left = 0,
/// <summary>
/// Top edge.
/// </summary>
Top = 1,
/// <summary>
/// Right edge.
/// </summary>
Right = 2,
/// <summary>
/// Bottom edge.
/// </summary>
Bottom = 3
}
[StructLayout(LayoutKind.Sequential)]
private struct APPBARDATA
{
public uint cbSize;
public IntPtr hWnd;
public uint uCallbackMessage;
public uint uEdge;
public RECT rc;
public int lParam;
}
[StructLayout(LayoutKind.Sequential)]
private struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
}
}

View File

@@ -0,0 +1,63 @@
using System;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Flags that define the icon that is shown on a balloon
/// tooltip.
/// </summary>
public enum BalloonFlags
{
/// <summary>
/// No icon is displayed.
/// </summary>
None = 0x00,
/// <summary>
/// An information icon is displayed.
/// </summary>
Info = 0x01,
/// <summary>
/// A warning icon is displayed.
/// </summary>
Warning = 0x02,
/// <summary>
/// An error icon is displayed.
/// </summary>
Error = 0x03,
/// <summary>
/// Windows XP Service Pack 2 (SP2) and later.
/// Use a custom icon as the title icon.
/// </summary>
User = 0x04,
/// <summary>
/// Windows XP (Shell32.dll version 6.0) and later.
/// Do not play the associated sound. Applies only to balloon ToolTips.
/// </summary>
NoSound = 0x10,
/// <summary>
/// Windows Vista (Shell32.dll version 6.0.6) and later. The large version
/// of the icon should be used as the balloon icon. This corresponds to the
/// icon with dimensions SM_CXICON x SM_CYICON. If this flag is not set,
/// the icon with dimensions XM_CXSMICON x SM_CYSMICON is used.<br/>
/// - This flag can be used with all stock icons.<br/>
/// - Applications that use older customized icons (NIIF_USER with hIcon) must
/// provide a new SM_CXICON x SM_CYICON version in the tray icon (hIcon). These
/// icons are scaled down when they are displayed in the System Tray or
/// System Control Area (SCA).<br/>
/// - New customized icons (NIIF_USER with hBalloonIcon) must supply an
/// SM_CXICON x SM_CYICON version in the supplied icon (hBalloonIcon).
/// </summary>
LargeIcon = 0x20,
/// <summary>
/// Windows 7 and later.
/// </summary>
RespectQuietTime = 0x80
}
}

View File

@@ -0,0 +1,70 @@
using System;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Indicates which members of a <see cref="NotifyIconData"/> structure
/// were set, and thus contain valid data or provide additional information
/// to the ToolTip as to how it should display.
/// </summary>
[Flags]
public enum IconDataMembers
{
/// <summary>
/// The message ID is set.
/// </summary>
Message = 0x01,
/// <summary>
/// The notification icon is set.
/// </summary>
Icon = 0x02,
/// <summary>
/// The tooltip is set.
/// </summary>
Tip = 0x04,
/// <summary>
/// State information (<see cref="IconState"/>) is set. This
/// applies to both <see cref="NotifyIconData.IconState"/> and
/// <see cref="NotifyIconData.StateMask"/>.
/// </summary>
State = 0x08,
/// <summary>
/// The balloon ToolTip is set. Accordingly, the following
/// members are set: <see cref="NotifyIconData.BalloonText"/>,
/// <see cref="NotifyIconData.BalloonTitle"/>, <see cref="NotifyIconData.BalloonFlags"/>,
/// and <see cref="NotifyIconData.VersionOrTimeout"/>.
/// </summary>
Info = 0x10,
// Internal identifier is set. Reserved, thus commented out.
//Guid = 0x20,
/// <summary>
/// Windows Vista (Shell32.dll version 6.0.6) and later. If the ToolTip
/// cannot be displayed immediately, discard it.<br/>
/// Use this flag for ToolTips that represent real-time information which
/// would be meaningless or misleading if displayed at a later time.
/// For example, a message that states "Your telephone is ringing."<br/>
/// This modifies and must be combined with the <see cref="Info"/> flag.
/// </summary>
Realtime = 0x40,
/// <summary>
/// Windows Vista (Shell32.dll version 6.0.6) and later.
/// Use the standard ToolTip. Normally, when uVersion is set
/// to NOTIFYICON_VERSION_4, the standard ToolTip is replaced
/// by the application-drawn pop-up user interface (UI).
/// If the application wants to show the standard tooltip
/// in that case, regardless of whether the on-hover UI is showing,
/// it can specify NIF_SHOWTIP to indicate the standard tooltip
/// should still be shown.<br/>
/// Note that the NIF_SHOWTIP flag is effective until the next call
/// to Shell_NotifyIcon.
/// </summary>
UseLegacyToolTips = 0x80
}
}

View File

@@ -0,0 +1,22 @@
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// The state of the icon - can be set to
/// hide the icon.
/// </summary>
public enum IconState
{
/// <summary>
/// The icon is visible.
/// </summary>
Visible = 0x00,
/// <summary>
/// Hide the icon.
/// </summary>
Hidden = 0x01,
// The icon is shared - currently not supported, thus commented out.
//Shared = 0x02
}
}

View File

@@ -0,0 +1,54 @@
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Event flags for clicked events.
/// </summary>
public enum MouseEvent
{
/// <summary>
/// The mouse was moved withing the
/// taskbar icon's area.
/// </summary>
MouseMove,
/// <summary>
/// The right mouse button was clicked.
/// </summary>
IconRightMouseDown,
/// <summary>
/// The left mouse button was clicked.
/// </summary>
IconLeftMouseDown,
/// <summary>
/// The right mouse button was released.
/// </summary>
IconRightMouseUp,
/// <summary>
/// The left mouse button was released.
/// </summary>
IconLeftMouseUp,
/// <summary>
/// The middle mouse button was clicked.
/// </summary>
IconMiddleMouseDown,
/// <summary>
/// The middle mouse button was released.
/// </summary>
IconMiddleMouseUp,
/// <summary>
/// The taskbar icon was double clicked.
/// </summary>
IconDoubleClick,
/// <summary>
/// The balloon tip was clicked.
/// </summary>
BalloonToolTipClicked
}
}

View File

@@ -0,0 +1,41 @@
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Main operations performed on the
/// <see cref="WinApi.Shell_NotifyIcon"/> function.
/// </summary>
public enum NotifyCommand
{
/// <summary>
/// The taskbar icon is being created.
/// </summary>
Add = 0x00,
/// <summary>
/// The settings of the taskbar icon are being updated.
/// </summary>
Modify = 0x01,
/// <summary>
/// The taskbar icon is deleted.
/// </summary>
Delete = 0x02,
/// <summary>
/// Focus is returned to the taskbar icon. Currently not in use.
/// </summary>
SetFocus = 0x03,
/// <summary>
/// Shell32.dll version 5.0 and later only. Instructs the taskbar
/// to behave according to the version number specified in the
/// uVersion member of the structure pointed to by lpdata.
/// This message allows you to specify whether you want the version
/// 5.0 behavior found on Microsoft Windows 2000 systems, or the
/// behavior found on earlier Shell versions. The default value for
/// uVersion is zero, indicating that the original Windows 95 notify
/// icon behavior should be used.
/// </summary>
SetVersion = 0x04
}
}

View File

@@ -0,0 +1,168 @@
using System;
using System.Runtime.InteropServices;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// A struct that is submitted in order to configure
/// the taskbar icon. Provides various members that
/// can be configured partially, according to the
/// values of the <see cref="IconDataMembers"/>
/// that were defined.
/// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct NotifyIconData
{
/// <summary>
/// Size of this structure, in bytes.
/// </summary>
public uint cbSize;
/// <summary>
/// Handle to the window that receives notification messages associated with an icon in the
/// taskbar status area. The Shell uses hWnd and uID to identify which icon to operate on
/// when Shell_NotifyIcon is invoked.
/// </summary>
public IntPtr WindowHandle;
/// <summary>
/// Application-defined identifier of the taskbar icon. The Shell uses hWnd and uID to identify
/// which icon to operate on when Shell_NotifyIcon is invoked. You can have multiple icons
/// associated with a single hWnd by assigning each a different uID. This feature, however
/// is currently not used.
/// </summary>
public uint TaskbarIconId;
/// <summary>
/// Flags that indicate which of the other members contain valid data. This member can be
/// a combination of the NIF_XXX constants.
/// </summary>
public IconDataMembers ValidMembers;
/// <summary>
/// Application-defined message identifier. The system uses this identifier to send
/// notifications to the window identified in hWnd.
/// </summary>
public uint CallbackMessageId;
/// <summary>
/// A handle to the icon that should be displayed. Just
/// <c>Icon.Handle</c>.
/// </summary>
public IntPtr IconHandle;
/// <summary>
/// String with the text for a standard ToolTip. It can have a maximum of 64 characters including
/// the terminating NULL. For Version 5.0 and later, szTip can have a maximum of
/// 128 characters, including the terminating NULL.
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string ToolTipText;
/// <summary>
/// State of the icon. Remember to also set the <see cref="StateMask"/>.
/// </summary>
public IconState IconState;
/// <summary>
/// A value that specifies which bits of the state member are retrieved or modified.
/// For example, setting this member to <see cref="TaskbarNotification.Interop.IconState.Hidden"/>
/// causes only the item's hidden
/// state to be retrieved.
/// </summary>
public IconState StateMask;
/// <summary>
/// String with the text for a balloon ToolTip. It can have a maximum of 255 characters.
/// To remove the ToolTip, set the NIF_INFO flag in uFlags and set szInfo to an empty string.
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string BalloonText;
/// <summary>
/// Mainly used to set the version when <see cref="WinApi.Shell_NotifyIcon"/> is invoked
/// with <see cref="NotifyCommand.SetVersion"/>. However, for legacy operations,
/// the same member is also used to set timeouts for balloon ToolTips.
/// </summary>
public uint VersionOrTimeout;
/// <summary>
/// String containing a title for a balloon ToolTip. This title appears in boldface
/// above the text. It can have a maximum of 63 characters.
/// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public string BalloonTitle;
/// <summary>
/// Adds an icon to a balloon ToolTip, which is placed to the left of the title. If the
/// <see cref="BalloonTitle"/> member is zero-length, the icon is not shown.
/// </summary>
public BalloonFlags BalloonFlags;
/// <summary>
/// Windows XP (Shell32.dll version 6.0) and later.<br/>
/// - Windows 7 and later: A registered GUID that identifies the icon.
/// This value overrides uID and is the recommended method of identifying the icon.<br/>
/// - Windows XP through Windows Vista: Reserved.
/// </summary>
public Guid TaskbarIconGuid;
/// <summary>
/// Windows Vista (Shell32.dll version 6.0.6) and later. The handle of a customized
/// balloon icon provided by the application that should be used independently
/// of the tray icon. If this member is non-NULL and the <see cref="TaskbarNotification.Interop.BalloonFlags.User"/>
/// flag is set, this icon is used as the balloon icon.<br/>
/// If this member is NULL, the legacy behavior is carried out.
/// </summary>
public IntPtr CustomBalloonIconHandle;
/// <summary>
/// Creates a default data structure that provides
/// a hidden taskbar icon without the icon being set.
/// </summary>
/// <param name="handle"></param>
/// <returns>NotifyIconData</returns>
public static NotifyIconData CreateDefault(IntPtr handle)
{
var data = new NotifyIconData();
if (Environment.OSVersion.Version.Major >= 6)
{
//use the current size
data.cbSize = (uint) Marshal.SizeOf(data);
}
else
{
//we need to set another size on xp/2003- otherwise certain
//features (e.g. balloon tooltips) don't work.
data.cbSize = 952; // NOTIFYICONDATAW_V3_SIZE
//set to fixed timeout
data.VersionOrTimeout = 10;
}
data.WindowHandle = handle;
data.TaskbarIconId = 0x0;
data.CallbackMessageId = WindowMessageSink.CallbackMessageId;
data.VersionOrTimeout = (uint) NotifyIconVersion.Win95;
data.IconHandle = IntPtr.Zero;
//hide initially
data.IconState = IconState.Hidden;
data.StateMask = IconState.Hidden;
//set flags
data.ValidMembers = IconDataMembers.Message
| IconDataMembers.Icon
| IconDataMembers.Tip;
//reset strings
data.ToolTipText = data.BalloonText = data.BalloonTitle = string.Empty;
return data;
}
}
}

View File

@@ -0,0 +1,27 @@
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// The notify icon version that is used. The higher
/// the version, the more capabilities are available.
/// </summary>
public enum NotifyIconVersion
{
/// <summary>
/// Default behavior (legacy Win95). Expects
/// a <see cref="NotifyIconData"/> size of 488.
/// </summary>
Win95 = 0x0,
/// <summary>
/// Behavior representing Win2000 an higher. Expects
/// a <see cref="NotifyIconData"/> size of 504.
/// </summary>
Win2000 = 0x3,
/// <summary>
/// Extended tooltip support, which is available for Vista and later.
/// Detailed information about what the different versions do, can be found <a href="https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyicona">here</a>
/// </summary>
Vista = 0x4
}
}

View File

@@ -0,0 +1,20 @@
using System.Runtime.InteropServices;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Win API struct providing coordinates for a single point.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct Point
{
/// <summary>
/// X coordinate.
/// </summary>
public int X;
/// <summary>
/// Y coordinate.
/// </summary>
public int Y;
}
}

View File

@@ -0,0 +1,85 @@
// hardcodet.net NotifyIcon for WPF
// Copyright (c) 2009 - 2020 Philipp Sumi
// Contact and Information: http://www.hardcodet.net
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Code Project Open License (CPOL);
// either version 1.0 of the License, or (at your option) any later
// version.
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE
using System.Diagnostics.Contracts;
using System.Windows.Interop;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// This class is a helper for system information, currently to get the DPI factors
/// </summary>
public static class SystemInfo
{
/// <summary>
/// Make sure the initial value is calculated at the first access
/// </summary>
static SystemInfo()
{
UpdateDpiFactors();
}
/// <summary>
/// This calculates the current DPI values and sets this into the DpiFactorX/DpiFactorY values
/// </summary>
internal static void UpdateDpiFactors()
{
using (var source = new HwndSource(new HwndSourceParameters()))
{
if (source.CompositionTarget?.TransformToDevice != null)
{
DpiFactorX = source.CompositionTarget.TransformToDevice.M11;
DpiFactorY = source.CompositionTarget.TransformToDevice.M22;
return;
}
}
DpiFactorX = DpiFactorY = 1;
}
/// <summary>
/// Returns the DPI X Factor
/// </summary>
public static double DpiFactorX { get; private set; } = 1;
/// <summary>
/// Returns the DPI Y Factor
/// </summary>
public static double DpiFactorY { get; private set; } = 1;
/// <summary>
/// Scale the supplied point to the current DPI settings
/// </summary>
/// <param name="point"></param>
/// <returns>Point</returns>
[Pure]
public static Point ScaleWithDpi(this Point point)
{
return new Point
{
X = (int)(point.X / DpiFactorX),
Y = (int)(point.Y / DpiFactorY)
};
}
}
}

View File

@@ -0,0 +1,56 @@
// Some interop code taken from Mike Marshall's AnyForm
using System.Drawing;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Resolves the current tray position.
/// </summary>
public static class TrayInfo
{
/// <summary>
/// Gets the position of the system tray.
/// </summary>
/// <returns>Tray coordinates.</returns>
public static Point GetTrayLocation()
{
int space = 2;
var info = new AppBarInfo();
info.GetSystemTaskBarPosition();
Rectangle rcWorkArea = info.WorkArea;
int x = 0, y = 0;
switch (info.Edge)
{
case AppBarInfo.ScreenEdge.Left:
x = rcWorkArea.Right + space;
y = rcWorkArea.Bottom;
break;
case AppBarInfo.ScreenEdge.Bottom:
x = rcWorkArea.Right;
y = rcWorkArea.Bottom - rcWorkArea.Height - space;
break;
case AppBarInfo.ScreenEdge.Top:
x = rcWorkArea.Right;
y = rcWorkArea.Top + rcWorkArea.Height + space;
break;
case AppBarInfo.ScreenEdge.Right:
x = rcWorkArea.Right - rcWorkArea.Width - space;
y = rcWorkArea.Bottom;
break;
}
return GetDeviceCoordinates(new Point {X = x, Y = y});
}
/// <summary>
/// Recalculates OS coordinates in order to support WPFs coordinate
/// system if OS scaling (DPIs) is not 100%.
/// </summary>
/// <param name="point">Point</param>
/// <returns>Point</returns>
public static Point GetDeviceCoordinates(Point point) => point.ScaleWithDpi();
}
}

View File

@@ -0,0 +1,91 @@
using System;
using System.Runtime.InteropServices;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Win32 API imports.
/// </summary>
internal static class WinApi
{
private const string User32 = "user32.dll";
/// <summary>
/// Creates, updates or deletes the taskbar icon.
/// </summary>
[DllImport("shell32.Dll", CharSet = CharSet.Unicode)]
public static extern bool Shell_NotifyIcon(NotifyCommand cmd, [In] ref NotifyIconData data);
/// <summary>
/// Creates the helper window that receives messages from the taskar icon.
/// </summary>
[DllImport(User32, EntryPoint = "CreateWindowExW", SetLastError = true)]
public static extern IntPtr CreateWindowEx(int dwExStyle, [MarshalAs(UnmanagedType.LPWStr)] string lpClassName,
[MarshalAs(UnmanagedType.LPWStr)] string lpWindowName, int dwStyle, int x, int y,
int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance,
IntPtr lpParam);
/// <summary>
/// Processes a default windows procedure.
/// </summary>
[DllImport(User32)]
public static extern IntPtr DefWindowProc(IntPtr hWnd, uint msg, IntPtr wparam, IntPtr lparam);
/// <summary>
/// Registers the helper window class.
/// </summary>
[DllImport(User32, EntryPoint = "RegisterClassW", SetLastError = true)]
public static extern short RegisterClass(ref WindowClass lpWndClass);
/// <summary>
/// Registers a listener for a window message.
/// </summary>
/// <param name="lpString"></param>
/// <returns>uint</returns>
[DllImport(User32, EntryPoint = "RegisterWindowMessageW")]
public static extern uint RegisterWindowMessage([MarshalAs(UnmanagedType.LPWStr)] string lpString);
/// <summary>
/// Used to destroy the hidden helper window that receives messages from the
/// taskbar icon.
/// </summary>
/// <param name="hWnd"></param>
/// <returns>bool</returns>
[DllImport(User32, SetLastError = true)]
public static extern bool DestroyWindow(IntPtr hWnd);
/// <summary>
/// Gives focus to a given window.
/// </summary>
/// <param name="hWnd"></param>
/// <returns>bool</returns>
[DllImport(User32)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
/// <summary>
/// Gets the maximum number of milliseconds that can elapse between a
/// first click and a second click for the OS to consider the
/// mouse action a double-click.
/// </summary>
/// <returns>The maximum amount of time, in milliseconds, that can
/// elapse between a first click and a second click for the OS to
/// consider the mouse action a double-click.</returns>
[DllImport(User32, CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern int GetDoubleClickTime();
/// <summary>
/// Gets the screen coordinates of the current mouse position.
/// </summary>
[DllImport(User32, SetLastError = true)]
public static extern bool GetPhysicalCursorPos(ref Point lpPoint);
[DllImport(User32, SetLastError = true)]
public static extern bool GetCursorPos(ref Point lpPoint);
}
}

View File

@@ -0,0 +1,34 @@
using System;
using System.Runtime.InteropServices;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Callback delegate which is used by the Windows API to
/// submit window messages.
/// </summary>
public delegate IntPtr WindowProcedureHandler(IntPtr hWnd, uint uMsg, IntPtr wParam, IntPtr lParam);
/// <summary>
/// Win API WNDCLASS struct - represents a single window.
/// Used to receive window messages.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct WindowClass
{
#pragma warning disable 1591
public uint style;
public WindowProcedureHandler lpfnWndProc;
public int cbClsExtra;
public int cbWndExtra;
public IntPtr hInstance;
public IntPtr hIcon;
public IntPtr hCursor;
public IntPtr hbrBackground;
[MarshalAs(UnmanagedType.LPWStr)] public string lpszMenuName;
[MarshalAs(UnmanagedType.LPWStr)] public string lpszClassName;
#pragma warning restore 1591
}
}

View File

@@ -0,0 +1,390 @@
// hardcodet.net NotifyIcon for WPF
// Copyright (c) 2009 - 2020 Philipp Sumi
// Contact and Information: http://www.hardcodet.net
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Code Project Open License (CPOL);
// either version 1.0 of the License, or (at your option) any later
// version.
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE
using System;
using System.ComponentModel;
using System.Diagnostics;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// Receives messages from the taskbar icon through
/// window messages of an underlying helper window.
/// </summary>
public class WindowMessageSink : IDisposable
{
#region members
/// <summary>
/// The ID of messages that are received from the the
/// taskbar icon.
/// </summary>
public const int CallbackMessageId = 0x400;
/// <summary>
/// The ID of the message that is being received if the
/// taskbar is (re)started.
/// </summary>
private uint taskbarRestartMessageId;
/// <summary>
/// Used to track whether a mouse-up event is just
/// the aftermath of a double-click and therefore needs
/// to be suppressed.
/// </summary>
private bool isDoubleClick;
/// <summary>
/// A delegate that processes messages of the hidden
/// native window that receives window messages. Storing
/// this reference makes sure we don't loose our reference
/// to the message window.
/// </summary>
private WindowProcedureHandler messageHandler;
/// <summary>
/// Window class ID.
/// </summary>
internal string WindowId { get; private set; }
/// <summary>
/// Handle for the message window.
/// </summary>
internal IntPtr MessageWindowHandle { get; private set; }
/// <summary>
/// The version of the underlying icon. Defines how
/// incoming messages are interpreted.
/// </summary>
public NotifyIconVersion Version { get; set; }
#endregion
#region events
/// <summary>
/// The custom tooltip should be closed or hidden.
/// </summary>
public event Action<bool> ChangeToolTipStateRequest;
/// <summary>
/// Fired in case the user clicked or moved within
/// the taskbar icon area.
/// </summary>
public event Action<MouseEvent> MouseEventReceived;
/// <summary>
/// Fired if a balloon ToolTip was either displayed
/// or closed (indicated by the boolean flag).
/// </summary>
public event Action<bool> BalloonToolTipChanged;
/// <summary>
/// Fired if the taskbar was created or restarted. Requires the taskbar
/// icon to be reset.
/// </summary>
public event Action TaskbarCreated;
#endregion
#region construction
/// <summary>
/// Creates a new message sink that receives message from
/// a given taskbar icon.
/// </summary>
/// <param name="version"></param>
public WindowMessageSink(NotifyIconVersion version)
{
Version = version;
CreateMessageWindow();
}
private WindowMessageSink()
{
}
/// <summary>
/// Creates a dummy instance that provides an empty
/// pointer rather than a real window handler.<br/>
/// Used at design time.
/// </summary>
/// <returns>WindowMessageSink</returns>
internal static WindowMessageSink CreateEmpty()
{
return new WindowMessageSink
{
MessageWindowHandle = IntPtr.Zero,
Version = NotifyIconVersion.Vista
};
}
#endregion
#region CreateMessageWindow
/// <summary>
/// Creates the helper message window that is used
/// to receive messages from the taskbar icon.
/// </summary>
private void CreateMessageWindow()
{
//generate a unique ID for the window
WindowId = "WPFTaskbarIcon_" + Guid.NewGuid();
//register window message handler
messageHandler = OnWindowMessageReceived;
// Create a simple window class which is reference through
//the messageHandler delegate
WindowClass wc;
wc.style = 0;
wc.lpfnWndProc = messageHandler;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = IntPtr.Zero;
wc.hIcon = IntPtr.Zero;
wc.hCursor = IntPtr.Zero;
wc.hbrBackground = IntPtr.Zero;
wc.lpszMenuName = string.Empty;
wc.lpszClassName = WindowId;
// Register the window class
WinApi.RegisterClass(ref wc);
// Get the message used to indicate the taskbar has been restarted
// This is used to re-add icons when the taskbar restarts
taskbarRestartMessageId = WinApi.RegisterWindowMessage("TaskbarCreated");
// Create the message window
MessageWindowHandle = WinApi.CreateWindowEx(0, WindowId, "", 0, 0, 0, 1, 1, IntPtr.Zero, IntPtr.Zero,
IntPtr.Zero, IntPtr.Zero);
if (MessageWindowHandle == IntPtr.Zero)
{
throw new Win32Exception("Message window handle was not a valid pointer");
}
}
#endregion
#region Handle Window Messages
/// <summary>
/// Callback method that receives messages from the taskbar area.
/// </summary>
private IntPtr OnWindowMessageReceived(IntPtr hWnd, uint messageId, IntPtr wParam, IntPtr lParam)
{
if (messageId == taskbarRestartMessageId)
{
//recreate the icon if the taskbar was restarted (e.g. due to Win Explorer shutdown)
var listener = TaskbarCreated;
listener?.Invoke();
}
//forward message
ProcessWindowMessage(messageId, wParam, lParam);
// Pass the message to the default window procedure
return WinApi.DefWindowProc(hWnd, messageId, wParam, lParam);
}
/// <summary>
/// Processes incoming system messages.
/// </summary>
/// <param name="msg">Callback ID.</param>
/// <param name="wParam">If the version is <see cref="NotifyIconVersion.Vista"/>
/// or higher, this parameter can be used to resolve mouse coordinates.
/// Currently not in use.</param>
/// <param name="lParam">Provides information about the event.</param>
private void ProcessWindowMessage(uint msg, IntPtr wParam, IntPtr lParam)
{
// Check if it was a callback message
if (msg != CallbackMessageId)
{
// It was not a callback message, but make sure it's not something else we need to process
switch ((WindowsMessages) msg)
{
case WindowsMessages.WM_DPICHANGED:
Debug.WriteLine("DPI Change");
SystemInfo.UpdateDpiFactors();
break;
}
return;
}
var message = (WindowsMessages)lParam.ToInt32();
Debug.WriteLine("Got message " + message);
switch (message)
{
case WindowsMessages.WM_CONTEXTMENU:
// TODO: Handle WM_CONTEXTMENU, see https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw
Debug.WriteLine("Unhandled WM_CONTEXTMENU");
break;
case WindowsMessages.WM_MOUSEMOVE:
MouseEventReceived?.Invoke(MouseEvent.MouseMove);
break;
case WindowsMessages.WM_LBUTTONDOWN:
MouseEventReceived?.Invoke(MouseEvent.IconLeftMouseDown);
break;
case WindowsMessages.WM_LBUTTONUP:
if (!isDoubleClick)
{
MouseEventReceived?.Invoke(MouseEvent.IconLeftMouseUp);
}
isDoubleClick = false;
break;
case WindowsMessages.WM_LBUTTONDBLCLK:
isDoubleClick = true;
MouseEventReceived?.Invoke(MouseEvent.IconDoubleClick);
break;
case WindowsMessages.WM_RBUTTONDOWN:
MouseEventReceived?.Invoke(MouseEvent.IconRightMouseDown);
break;
case WindowsMessages.WM_RBUTTONUP:
MouseEventReceived?.Invoke(MouseEvent.IconRightMouseUp);
break;
case WindowsMessages.WM_RBUTTONDBLCLK:
//double click with right mouse button - do not trigger event
break;
case WindowsMessages.WM_MBUTTONDOWN:
MouseEventReceived?.Invoke(MouseEvent.IconMiddleMouseDown);
break;
case WindowsMessages.WM_MBUTTONUP:
MouseEventReceived?.Invoke(MouseEvent.IconMiddleMouseUp);
break;
case WindowsMessages.WM_MBUTTONDBLCLK:
//double click with middle mouse button - do not trigger event
break;
case WindowsMessages.NIN_BALLOONSHOW:
BalloonToolTipChanged?.Invoke(true);
break;
case WindowsMessages.NIN_BALLOONHIDE:
case WindowsMessages.NIN_BALLOONTIMEOUT:
BalloonToolTipChanged?.Invoke(false);
break;
case WindowsMessages.NIN_BALLOONUSERCLICK:
MouseEventReceived?.Invoke(MouseEvent.BalloonToolTipClicked);
break;
case WindowsMessages.NIN_POPUPOPEN:
ChangeToolTipStateRequest?.Invoke(true);
break;
case WindowsMessages.NIN_POPUPCLOSE:
ChangeToolTipStateRequest?.Invoke(false);
break;
case WindowsMessages.NIN_SELECT:
// TODO: Handle NIN_SELECT see https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw
Debug.WriteLine("Unhandled NIN_SELECT");
break;
case WindowsMessages.NIN_KEYSELECT:
// TODO: Handle NIN_KEYSELECT see https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw
Debug.WriteLine("Unhandled NIN_KEYSELECT");
break;
default:
Debug.WriteLine("Unhandled NotifyIcon message ID: " + lParam);
break;
}
}
#endregion
#region Dispose
/// <summary>
/// Set to true as soon as <c>Dispose</c> has been invoked.
/// </summary>
public bool IsDisposed { get; private set; }
/// <summary>
/// Disposes the object.
/// </summary>
/// <remarks>This method is not virtual by design. Derived classes
/// should override <see cref="Dispose(bool)"/>.
/// </remarks>
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SuppressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
}
/// <summary>
/// This destructor will run only if the <see cref="Dispose()"/>
/// method does not get called. This gives this base class the
/// opportunity to finalize.
/// <para>
/// Important: Do not provide destructor in types derived from
/// this class.
/// </para>
/// </summary>
~WindowMessageSink()
{
Dispose(false);
}
/// <summary>
/// Removes the windows hook that receives window
/// messages and closes the underlying helper window.
/// </summary>
private void Dispose(bool disposing)
{
//don't do anything if the component is already disposed
if (IsDisposed) return;
IsDisposed = true;
//always destroy the unmanaged handle (even if called from the GC)
WinApi.DestroyWindow(MessageWindowHandle);
messageHandler = null;
}
#endregion
}
}

View File

@@ -0,0 +1,197 @@
// hardcodet.net NotifyIcon for WPF
// Copyright (c) 2009 - 2020 Philipp Sumi
// Contact and Information: http://www.hardcodet.net
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Code Project Open License (CPOL);
// either version 1.0 of the License, or (at your option) any later
// version.
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE
// ReSharper disable InconsistentNaming
using System.Diagnostics.CodeAnalysis;
namespace Hardcodet.Wpf.TaskbarNotification.Interop
{
/// <summary>
/// This enum defines the windows messages we respond to.
/// See more on Windows messages <a href="https://docs.microsoft.com/en-us/windows/win32/learnwin32/window-messages">here</a>
/// </summary>
[SuppressMessage("ReSharper", "IdentifierTypo")]
public enum WindowsMessages : uint
{
/// <summary>
/// Notifies a window that the user clicked the right mouse button (right-clicked) in the window.
/// See <a href="https://docs.microsoft.com/en-us/windows/win32/menurc/wm-contextmenu">WM_CONTEXTMENU message</a>
///
/// In case of a notify icon:
/// If a user selects a notify icon's shortcut menu with the keyboard, the Shell now sends the associated application a WM_CONTEXTMENU message. Earlier versions send WM_RBUTTONDOWN and WM_RBUTTONUP messages.
/// See <a href="https://docs.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shell_notifyiconw">Shell_NotifyIcon function</a>
/// </summary>
WM_CONTEXTMENU = 0x007b,
/// <summary>
/// Posted to a window when the cursor moves.
/// If the mouse is not captured, the message is posted to the window that contains the cursor.
/// Otherwise, the message is posted to the window that has captured the mouse.
///
/// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mousemove">WM_MOUSEMOVE message</a>
/// </summary>
WM_MOUSEMOVE = 0x0200,
/// <summary>
/// Posted when the user presses the left mouse button while the cursor is in the client area of a window.
/// If the mouse is not captured, the message is posted to the window beneath the cursor.
/// Otherwise, the message is posted to the window that has captured the mouse.
///
/// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-lbuttondown">WM_LBUTTONDOWN message</a>
/// </summary>
WM_LBUTTONDOWN = 0x0201,
/// <summary>
/// Posted when the user releases the left mouse button while the cursor is in the client area of a window.
/// If the mouse is not captured, the message is posted to the window beneath the cursor.
/// Otherwise, the message is posted to the window that has captured the mouse.
///
/// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-lbuttonup">WM_LBUTTONUP message</a>
/// </summary>
WM_LBUTTONUP = 0x0202,
/// <summary>
/// Posted when the user double-clicks the left mouse button while the cursor is in the client area of a window.
/// If the mouse is not captured, the message is posted to the window beneath the cursor.
/// Otherwise, the message is posted to the window that has captured the mouse.
///
/// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-lbuttondblclk">WM_LBUTTONDBLCLK message</a>
/// </summary>
WM_LBUTTONDBLCLK = 0x0203,
/// <summary>
/// Posted when the user presses the right mouse button while the cursor is in the client area of a window.
/// If the mouse is not captured, the message is posted to the window beneath the cursor.
/// Otherwise, the message is posted to the window that has captured the mouse.
///
/// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-rbuttondown">WM_RBUTTONDOWN message</a>
/// </summary>
WM_RBUTTONDOWN = 0x0204,
/// <summary>
/// Posted when the user releases the right mouse button while the cursor is in the client area of a window.
/// If the mouse is not captured, the message is posted to the window beneath the cursor.
/// Otherwise, the message is posted to the window that has captured the mouse.
///
/// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-rbuttonup">WM_RBUTTONUP message</a>
/// </summary>
WM_RBUTTONUP = 0x0205,
/// <summary>
/// Posted when the user double-clicks the right mouse button while the cursor is in the client area of a window.
/// If the mouse is not captured, the message is posted to the window beneath the cursor.
/// Otherwise, the message is posted to the window that has captured the mouse.
///
/// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-rbuttondblclk">WM_RBUTTONDBLCLK message</a>
/// </summary>
WM_RBUTTONDBLCLK = 0x0206,
/// <summary>
/// Posted when the user presses the middle mouse button while the cursor is in the client area of a window.
/// If the mouse is not captured, the message is posted to the window beneath the cursor.
/// Otherwise, the message is posted to the window that has captured the mouse.
///
/// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mbuttondown">WM_MBUTTONDOWN message</a>
/// </summary>
WM_MBUTTONDOWN = 0x0207,
/// <summary>
/// Posted when the user releases the middle mouse button while the cursor is in the client area of a window.
/// If the mouse is not captured, the message is posted to the window beneath the cursor.
/// Otherwise, the message is posted to the window that has captured the mouse.
///
/// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mbuttonup">WM_MBUTTONUP message</a>
/// </summary>
WM_MBUTTONUP = 0x0208,
/// <summary>
/// Posted when the user double-clicks the middle mouse button while the cursor is in the client area of a window.
/// If the mouse is not captured, the message is posted to the window beneath the cursor.
/// Otherwise, the message is posted to the window that has captured the mouse.
///
/// See <a href="https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mbuttondblclk">WM_MBUTTONDBLCLK message</a>
/// </summary>
WM_MBUTTONDBLCLK = 0x0209,
/// <summary>
/// Sent when the effective dots per inch (dpi) for a window has changed.
/// The DPI is the scale factor for a window.
/// There are multiple events that can cause the DPI to change.
/// </summary>
WM_DPICHANGED = 0x02e0,
/// <summary>
/// Used to define private messages for use by private window classes, usually of the form WM_USER+x, where x is an integer value.
/// </summary>
WM_USER = 0x0400,
/// <summary>
/// This message is only send when using NOTIFYICON_VERSION_4, the Shell now sends the associated application an NIN_SELECT notification.
/// Send when a notify icon is activated with mouse or ENTER key.
/// Earlier versions send WM_RBUTTONDOWN and WM_RBUTTONUP messages.
/// </summary>
NIN_SELECT = WM_USER,
/// <summary>
/// This message is only send when using NOTIFYICON_VERSION_4, the Shell now sends the associated application an NIN_SELECT notification.
/// Send when a notify icon is activated with SPACEBAR or ENTER key.
/// Earlier versions send WM_RBUTTONDOWN and WM_RBUTTONUP messages.
/// </summary>
NIN_KEYSELECT = WM_USER + 1,
/// <summary>
/// Sent when the balloon is shown (balloons are queued).
/// </summary>
NIN_BALLOONSHOW = WM_USER + 2,
/// <summary>
/// Sent when the balloon disappears. For example, when the icon is deleted.
/// This message is not sent if the balloon is dismissed because of a timeout or if the user clicks the mouse.
///
/// As of Windows 7, NIN_BALLOONHIDE is also sent when a notification with the NIIF_RESPECT_QUIET_TIME flag set attempts to display during quiet time (a user's first hour on a new computer).
/// In that case, the balloon is never displayed at all.
/// </summary>
NIN_BALLOONHIDE = WM_USER + 3,
/// <summary>
/// Sent when the balloon is dismissed because of a timeout.
/// </summary>
NIN_BALLOONTIMEOUT = WM_USER + 4,
/// <summary>
/// Sent when the balloon is dismissed because the user clicked the mouse.
/// </summary>
NIN_BALLOONUSERCLICK = WM_USER + 5,
/// <summary>
/// Sent when the user hovers the cursor over an icon to indicate that the richer pop-up UI should be used in place of a standard textual tooltip.
/// </summary>
NIN_POPUPOPEN = WM_USER + 6,
/// <summary>
/// Sent when a cursor no longer hovers over an icon to indicate that the rich pop-up UI should be closed.
/// </summary>
NIN_POPUPCLOSE = WM_USER + 7
}
}

View File

@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net45;net462;net472;net472;net6.0-windows</TargetFrameworks>
<LangVersion>latest</LangVersion>
<UseWindowsForms>true</UseWindowsForms>
<UseWPF>true</UseWPF>
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
<DebugSymbols>True</DebugSymbols>
<DebugType>embedded</DebugType>
</PropertyGroup>
<PropertyGroup>
<RootNamespace>Hardcodet.Wpf.TaskbarNotification</RootNamespace>
<AssemblyName>Hardcodet.NotifyIcon.Wpf</AssemblyName>
<AssemblyTitle>NotifyIcon for WPF</AssemblyTitle>
<Product>NotifyIcon WPF</Product>
</PropertyGroup>
<ItemGroup>
<None Include="Diagrams\TaskbarIcon Overview.cd" />
</ItemGroup>
<ItemGroup>
<Compile DependentUpon="%(Filename)" SubType="Code" Update="**\obj\**\*.g$(DefaultLanguageSourceExtension)" />
<Compile DependentUpon="%(Filename)" SubType="Designer" Update="**\*.xaml$(DefaultLanguageSourceExtension)" />
</ItemGroup>
</Project>

Binary file not shown.

View File

@@ -0,0 +1,75 @@
// hardcodet.net NotifyIcon for WPF
// Copyright (c) 2009 - 2020 Philipp Sumi
// Contact and Information: http://www.hardcodet.net
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Code Project Open License (CPOL);
// either version 1.0 of the License, or (at your option) any later
// version.
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE
namespace Hardcodet.Wpf.TaskbarNotification
{
/// <summary>
/// Defines flags that define when a popup
/// is being displyed.
/// </summary>
public enum PopupActivationMode
{
/// <summary>
/// The item is displayed if the user clicks the
/// tray icon with the left mouse button.
/// </summary>
LeftClick,
/// <summary>
/// The item is displayed if the user clicks the
/// tray icon with the right mouse button.
/// </summary>
RightClick,
/// <summary>
/// The item is displayed if the user double-clicks the
/// tray icon.
/// </summary>
DoubleClick,
/// <summary>
/// The item is displayed if the user clicks the
/// tray icon with the left or the right mouse button.
/// </summary>
LeftOrRightClick,
/// <summary>
/// The item is displayed if the user clicks the
/// tray icon with the left mouse button or if a
/// double-click is being performed.
/// </summary>
LeftOrDoubleClick,
/// <summary>
/// The item is displayed if the user clicks the
/// tray icon with the middle mouse button.
/// </summary>
MiddleClick,
/// <summary>
/// The item is displayed whenever a click occurs.
/// </summary>
All
}
}

View File

@@ -0,0 +1,45 @@
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Markup;
//provides simplified declaration in XAML
[assembly: XmlnsPrefix("http://www.hardcodet.net/taskbar", "tb")]
[assembly: XmlnsDefinition("http://www.hardcodet.net/taskbar", "Hardcodet.Wpf.TaskbarNotification")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// 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.*")]

View File

@@ -0,0 +1,71 @@
using System;
using System.Windows;
namespace Hardcodet.Wpf.TaskbarNotification
{
/// <summary>
/// Helper class used by routed events of the
/// <see cref="TaskbarIcon"/> class.
/// </summary>
internal static class RoutedEventHelper
{
#region RoutedEvent Helper Methods
/// <summary>
/// A static helper method to raise a routed event on a target UIElement or ContentElement.
/// </summary>
/// <param name="target">UIElement or ContentElement on which to raise the event</param>
/// <param name="args">RoutedEventArgs to use when raising the event</param>
internal static void RaiseEvent(DependencyObject target, RoutedEventArgs args)
{
if (target is UIElement uiElement)
{
uiElement.RaiseEvent(args);
}
else if (target is ContentElement contentElement)
{
contentElement.RaiseEvent(args);
}
}
/// <summary>
/// A static helper method that adds a handler for a routed event
/// to a target UIElement or ContentElement.
/// </summary>
/// <param name="element">UIElement or ContentElement that listens to the event</param>
/// <param name="routedEvent">Event that will be handled</param>
/// <param name="handler">Event handler to be added</param>
internal static void AddHandler(DependencyObject element, RoutedEvent routedEvent, Delegate handler)
{
if (element is UIElement uie)
{
uie.AddHandler(routedEvent, handler);
}
else if (element is ContentElement ce)
{
ce.AddHandler(routedEvent, handler);
}
}
/// <summary>
/// A static helper method that removes a handler for a routed event
/// from a target UIElement or ContentElement.
/// </summary>
/// <param name="element">UIElement or ContentElement that listens to the event</param>
/// <param name="routedEvent">Event that will no longer be handled</param>
/// <param name="handler">Event handler to be removed</param>
internal static void RemoveHandler(DependencyObject element, RoutedEvent routedEvent, Delegate handler)
{
if (element is UIElement uie)
{
uie.RemoveHandler(routedEvent, handler);
}
else if (element is ContentElement ce)
{
ce.RemoveHandler(routedEvent, handler);
}
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

1103
NotifyIconWpf/TaskbarIcon.cs Normal file

File diff suppressed because it is too large Load Diff

309
NotifyIconWpf/Util.cs Normal file
View File

@@ -0,0 +1,309 @@
// hardcodet.net NotifyIcon for WPF
// Copyright (c) 2009 - 2020 Philipp Sumi
// Contact and Information: http://www.hardcodet.net
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Code Project Open License (CPOL);
// either version 1.0 of the License, or (at your option) any later
// version.
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
//
// THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Resources;
using System.Windows.Threading;
using Hardcodet.Wpf.TaskbarNotification.Interop;
namespace Hardcodet.Wpf.TaskbarNotification
{
/// <summary>
/// Util and extension methods.
/// </summary>
internal static class Util
{
public static readonly object SyncRoot = new object();
#region IsDesignMode
private static readonly bool isDesignMode;
/// <summary>
/// Checks whether the application is currently in design mode.
/// </summary>
public static bool IsDesignMode
{
get { return isDesignMode; }
}
#endregion
#region construction
static Util()
{
isDesignMode =
(bool)
DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty,
typeof (FrameworkElement))
.Metadata.DefaultValue;
}
#endregion
#region CreateHelperWindow
/// <summary>
/// Creates an transparent window without dimension that
/// can be used to temporarily obtain focus and/or
/// be used as a window message sink.
/// </summary>
/// <returns>Empty window.</returns>
public static Window CreateHelperWindow()
{
return new Window
{
Width = 0,
Height = 0,
ShowInTaskbar = false,
WindowStyle = WindowStyle.None,
AllowsTransparency = true,
Opacity = 0
};
}
#endregion
#region WriteIconData
/// <summary>
/// Updates the taskbar icons with data provided by a given
/// <see cref="NotifyIconData"/> instance.
/// </summary>
/// <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);
}
/// <summary>
/// Updates the taskbar icons with data provided by a given
/// <see cref="NotifyIconData"/> instance.
/// </summary>
/// <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
if (IsDesignMode) return true;
data.ValidMembers = flags;
lock (SyncRoot)
{
return WinApi.Shell_NotifyIcon(command, ref data);
}
}
#endregion
#region GetBalloonFlag
/// <summary>
/// Gets a <see cref="BalloonFlags"/> enum value that
/// matches a given <see cref="BalloonIcon"/>.
/// </summary>
public static BalloonFlags GetBalloonFlag(this BalloonIcon icon)
{
switch (icon)
{
case BalloonIcon.None:
return BalloonFlags.None;
case BalloonIcon.Info:
return BalloonFlags.Info;
case BalloonIcon.Warning:
return BalloonFlags.Warning;
case BalloonIcon.Error:
return BalloonFlags.Error;
default:
throw new ArgumentOutOfRangeException("icon");
}
}
#endregion
#region ImageSource to Icon
/// <summary>
/// Reads a given image resource into a WinForms icon.
/// </summary>
/// <param name="imageSource">Image source pointing to
/// an icon file (*.ico).</param>
/// <returns>An icon object that can be used with the
/// taskbar area.</returns>
public static Icon ToIcon(this ImageSource imageSource)
{
if (imageSource == null) return null;
Uri uri = new Uri(imageSource.ToString());
StreamResourceInfo streamInfo = Application.GetResourceStream(uri);
if (streamInfo == null)
{
string msg = "The supplied image source '{0}' could not be resolved.";
msg = string.Format(msg, imageSource);
throw new ArgumentException(msg);
}
return new Icon(streamInfo.Stream);
}
#endregion
#region evaluate listings
/// <summary>
/// Checks a list of candidates for equality to a given
/// reference value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value">The evaluated value.</param>
/// <param name="candidates">A liste of possible values that are
/// regarded valid.</param>
/// <returns>True if one of the submitted <paramref name="candidates"/>
/// matches the evaluated value. If the <paramref name="candidates"/>
/// parameter itself is null, too, the method returns false as well,
/// which allows to check with null values, too.</returns>
/// <exception cref="ArgumentNullException">If <paramref name="candidates"/>
/// is a null reference.</exception>
public static bool Is<T>(this T value, params T[] candidates)
{
if (candidates == null) return false;
foreach (var t in candidates)
{
if (value.Equals(t)) return true;
}
return false;
}
#endregion
#region match MouseEvent to PopupActivation
/// <summary>
/// Checks if a given <see cref="PopupActivationMode"/> is a match for
/// an effectively pressed mouse button.
/// </summary>
public static bool IsMatch(this MouseEvent me, PopupActivationMode activationMode)
{
switch (activationMode)
{
case PopupActivationMode.LeftClick:
return me == MouseEvent.IconLeftMouseUp;
case PopupActivationMode.RightClick:
return me == MouseEvent.IconRightMouseUp;
case PopupActivationMode.LeftOrRightClick:
return me.Is(MouseEvent.IconLeftMouseUp, MouseEvent.IconRightMouseUp);
case PopupActivationMode.LeftOrDoubleClick:
return me.Is(MouseEvent.IconLeftMouseUp, MouseEvent.IconDoubleClick);
case PopupActivationMode.DoubleClick:
return me.Is(MouseEvent.IconDoubleClick);
case PopupActivationMode.MiddleClick:
return me == MouseEvent.IconMiddleMouseUp;
case PopupActivationMode.All:
//return true for everything except mouse movements
return me != MouseEvent.MouseMove;
default:
throw new ArgumentOutOfRangeException("activationMode");
}
}
#endregion
#region execute command
/// <summary>
/// Executes a given command if its <see cref="ICommand.CanExecute"/> method
/// indicates it can run.
/// </summary>
/// <param name="command">The command to be executed, or a null reference.</param>
/// <param name="commandParameter">An optional parameter that is associated with
/// the command.</param>
/// <param name="target">The target element on which to raise the command.</param>
public static void ExecuteIfEnabled(this ICommand command, object commandParameter, IInputElement target)
{
if (command == null) return;
RoutedCommand rc = command as RoutedCommand;
if (rc != null)
{
//routed commands work on a target
if (rc.CanExecute(commandParameter, target)) rc.Execute(commandParameter, target);
}
else if (command.CanExecute(commandParameter))
{
command.Execute(commandParameter);
}
}
#endregion
/// <summary>
/// Returns a dispatcher for multi-threaded scenarios
/// </summary>
/// <returns>Dispatcher</returns>
internal static Dispatcher GetDispatcher(this DispatcherObject source)
{
//use the application's dispatcher by default
if (Application.Current != null) return Application.Current.Dispatcher;
//fallback for WinForms environments
if (source.Dispatcher != null) return source.Dispatcher;
// ultimately use the thread's dispatcher
return Dispatcher.CurrentDispatcher;
}
/// <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;
}
}
}

59
README.md Normal file
View File

@@ -0,0 +1,59 @@
# Hardcodet NotifyIcon for WPF
Quelle: https://github.com/hardcodet/wpf-notifyicon
:rocket: **This is the new official repository of the Hardcodet WPF NotifyIcon** :rocket:
Current version: [![Nuget](https://img.shields.io/nuget/v/Hardcodet.NotifyIcon.Wpf.svg)](https://www.nuget.org/packages/Hardcodet.NotifyIcon.Wpf/)
## Description
This is an implementation of a NotifyIcon (aka system tray icon or taskbar icon) for the WPF platform. It does not just rely on the Windows Forms NotifyIcon component, but is a purely independent control which leverages several features of the WPF framework in order to display rich tooltips, popups, context menus, and balloon messages. It can be used directly in code or embedded in any XAML file.
### Features at a glance
- Custom Popups (interactive controls) on mouse clicks.
- Customized ToolTips (Vista and above) with fallback mechanism for xp/2003.
- Rich event model including attached events to trigger animations in Popups, ToolTips, and balloon messages. I just love that.
- Full support for standard Windows balloons, including custom icons.
- Custom balloons that pop up in the tray area. Go wild with styles and animations 🙂
- Support for WPF context menus.
- You can define whether to show Popups on left-, right-, double-clicks etc. The same goes for context menus.
- Simple data binding for Popups, ToolTips and custom balloons through attached properties and derived data context.
- Command support for single / double clicks on the tray icon.
### Tutorial and Support
A comprehensive tutorial that complements the attached sample application can be found on the Code Project:
http://www.codeproject.com/KB/WPF/wpf_notifyicon.aspx
## XAML Declaration Sample
The sample below shows some of the properties of the control. For a more comprehensive sample, have a look at the sample application that comes with the download.
``` XML
<Window
x:Class="Hardcodet.NetDrives.UI.SystemTray.Sample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tb="http://www.hardcodet.net/taskbar">
<tb:TaskbarIcon x:Name="myNotifyIcon"
Visibility="Visible"
ToolTipText="Fallback ToolTip for Windows xp"
IconSource="/Images/TrayIcons/Logo.ico"
ContextMenu="{StaticResource TrayMenu}"
MenuActivation="LeftOrRightClick"
TrayPopup="{StaticResoure TrayStatusPopup}"
PopupActivation="DoubleClick"
TrayToolTip="{StaticResource TrayToolTip}"
/>
</Window>
```
## Contributors and Thanks
Hi, I'm Philipp! This little library was originally written by me, but is currently mostly maintained by [Jan Karger](https://github.com/punker76) and [Robin Krom](https://github.com/Lakritzator). Big, big kudos to the two of you, and everybody else who [contributed](https://github.com/hardcodet/wpf-notifyicon/graphs/contributors) to this library. You rock!
Make sure to check out Robin's great [Greenshot](https://getgreenshot.org/) tool (that I use on a daily basis), and Jan's [MahApps](https://github.com/MahApps) UI framework.

7
global.json Normal file
View File

@@ -0,0 +1,7 @@
{
"sdk": {
"version": "5.0.0",
"rollForward": "latestMajor",
"allowPrerelease": true
}
}