23 Commits

Author SHA1 Message Date
Daniel Clark 10499366d6 further work to get placement in a multi mon setup working properly 2021-03-02 20:36:14 +00:00
Daniel Clark 24bdc3caa2 Continue to tweak offset 2021-03-01 20:36:31 +00:00
Daniel Clark ab7ea6415d Remove test code for resizing until a better solution comes up 2021-03-01 17:20:10 +00:00
Daniel Clark 0a6b227fc6 fixed issue with DPI not updating 2021-03-01 16:02:58 +00:00
Daniel Clark dd92d25d23 Amend how we hide the xaml window 2021-02-28 18:48:49 +00:00
Daniel Clark b815985963 fix issue with DPI 2021-02-28 18:45:12 +00:00
Daniel Clark 04de82cda0 Allow placement to be updated at run time 2021-02-27 20:27:56 +00:00
Daniel Clark efc2f75d85 implemented FullRight placement mode 2021-02-27 20:19:58 +00:00
Daniel Clark 47540457b8 show popup first and then set the placement... this is to ensure we are getting the correct size 2021-02-27 17:40:05 +00:00
Daniel Clark 1800eefd5a Amend how we hide via deactivation as the user may still want to call Hide explicitly while having IsLightDismissedEnabled set to false 2021-02-27 15:38:09 +00:00
Daniel Clark f9c688aa02 Added ability to keep the flyout open on the desktop which can be set via IsLightDismissEnabled DP 2021-02-27 15:24:47 +00:00
Daniel Clark 8e334912b9 Added offset value to offset the popup position by 1px 2021-02-27 14:18:32 +00:00
Daniel Clark 5db230c83c re-wired opened and closed events 2021-02-27 12:03:36 +00:00
Daniel Clark 240609270e fixed issue with margin 2021-02-27 11:57:23 +00:00
Daniel Clark 737dbe9b32 Major refactor to use Popup replacing the Flyout. This will allow for future enhancements. 2021-02-26 20:48:10 +00:00
Daniel Clark c408eafdde [WIP] Positioning of popup 2021-02-26 16:21:23 +00:00
Daniel Clark f0b42d1551 [WIP] Move over to a popup 2021-02-26 14:34:13 +00:00
Daniel Clark d25744a9f4 Added ability to set Auto or Right flyout placement 2021-02-25 17:39:19 +00:00
Daniel Clark 36f2953fd4 Added NotificationFlyoutPlacement enum 2021-02-25 15:08:45 +00:00
Daniel Clark bc42e0cff1 Remove max width and height from flyout style 2021-02-25 15:02:42 +00:00
Daniel Clark d48d0bd590 Added showcase section to read me 2021-02-15 22:50:40 +00:00
Daniel Clark 6751bc914e Update readme 2021-02-15 22:37:00 +00:00
Daniel Clark ac1ace291c Remove steps for setting notification icons 2021-02-15 22:35:51 +00:00
45 changed files with 1090 additions and 1079 deletions
+8 -6
View File
@@ -4,6 +4,12 @@ A Notification Flyout that looks and feels exactly like the native Volume, Netwo
# Demo # # Demo #
[![](http://img.youtube.com/vi/8EoZ4pGWTkY/0.jpg)](http://www.youtube.com/watch?v=8EoZ4pGWTkY "Notification flyout demo") [![](http://img.youtube.com/vi/8EoZ4pGWTkY/0.jpg)](http://www.youtube.com/watch?v=8EoZ4pGWTkY "Notification flyout demo")
# Show case #
[NotificationFlyout.NowPlaying](https://github.com/TheXamlGuy/NotificationFlyout.NowPlaying)
![](https://github.com/TheXamlGuy/NotificationFlyout.NowPlaying/blob/master/wip_concept.png)
# Getting started # # Getting started #
Many parts of this guide refers to the [Host a custom WinRT XAML control in a WPF app using XAML Islands](https://docs.microsoft.com/en-us/windows/apps/desktop/modernize/host-custom-control-with-xaml-islands) article. If in doubt, refer to the article, or post an issue on this repro. Many parts of this guide refers to the [Host a custom WinRT XAML control in a WPF app using XAML Islands](https://docs.microsoft.com/en-us/windows/apps/desktop/modernize/host-custom-control-with-xaml-islands) article. If in doubt, refer to the article, or post an issue on this repro.
@@ -34,15 +40,13 @@ namespace MyUWPApp
} }
``` ```
5. In the UWP app project, install the [TheXamlGuy.NotificationFlyout.Uwp.UI.Controls](https://www.nuget.org/packages/TheXamlGuy.NotificationFlyout.Uwp.UI.Controls/) NuGet package (latest stable version). 5. In the UWP app project, install the [TheXamlGuy.NotificationFlyout.Uwp.UI.Controls](https://www.nuget.org/packages/TheXamlGuy.NotificationFlyout.Uwp.UI.Controls/) NuGet package (latest stable version).
3. Open the `MainPage.xaml` file and replace the contents of this file with the following XAML. Replace `MyUWPApp` with the namespace of your UWP app project. 6. Open the `MainPage.xaml` file and replace the contents of this file with the following XAML. Replace `MyUWPApp` with the namespace of your UWP app project.
```xaml ```xaml
<controls:NotificationFlyout <controls:NotificationFlyout
x:Class="MyUWPApp.MainPage" x:Class="MyUWPApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:NotificationFlyout.Uwp.UI.Controls" xmlns:controls="using:NotificationFlyout.Uwp.UI.Controls">
IconSource="/Assets/Icon.ico"
LightIconSource="/Assets/Icon-Light.ico">
<Grid Width="400" Height="500"> <Grid Width="400" Height="500">
<Button <Button
HorizontalAlignment="Center" HorizontalAlignment="Center"
@@ -51,8 +55,6 @@ namespace MyUWPApp
</Grid> </Grid>
</controls:NotificationFlyout> </controls:NotificationFlyout>
``` ```
5. In the UWP app project, add two icons (.ico) to the Assets folder.
6. Replace the values of `IconSource` and `LightIconSource` with the paths of the icons that you have added to your Assets folder.
7. Clean the UWP app project and then build it. 7. Clean the UWP app project and then build it.
## Create a WPF project ## ## Create a WPF project ##
@@ -4,18 +4,22 @@
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<Platforms>AnyCPU;x64</Platforms>
<StartupObject>NotificationFlyoutSample.Host.Program</StartupObject> <StartupObject>NotificationFlyoutSample.Host.Program</StartupObject>
<AssetTargetFallback>uap10.0.19041</AssetTargetFallback> <AssetTargetFallback>uap10.0.19041</AssetTargetFallback>
<Platforms>x64</Platforms>
<ApplicationManifest>app.manifest</ApplicationManifest>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.Toolkit.Wpf.UI.XamlHost" Version="6.1.2" /> <PackageReference Include="Microsoft.Toolkit.Wpf.UI.XamlHost" Version="6.1.2" />
<PackageReference Include="Microsoft.Win32.Registry" Version="6.0.0-preview.1.21102.12" />
<PackageReference Include="System.Drawing.Common" Version="6.0.0-preview.1.21102.12" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\TheXamlGuy.NotificationFlyout.Common\TheXamlGuy.NotificationFlyout.Common.csproj" /> <ProjectReference Include="..\..\src\TheXamlGuy.NotificationFlyout.Common\TheXamlGuy.NotificationFlyout.Common.csproj" />
<ProjectReference Include="..\..\src\TheXamlGuy.NotificationFlyout.Shared.UI\TheXamlGuy.NotificationFlyout.Shared.UI.csproj" /> <ProjectReference Include="..\..\src\TheXamlGuy.NotificationFlyout.Shared.UI\TheXamlGuy.NotificationFlyout.Shared.UI.csproj" />
<ProjectReference Include="..\..\src\TheXamlGuy.NotificationFlyout.Uwp.UI.Controls\TheXamlGuy.NotificationFlyout.Uwp.UI.Controls.csproj" />
<ProjectReference Include="..\..\src\TheXamlGuy.NotificationFlyout.Wpf.UI.Controls\TheXamlGuy.NotificationFlyout.Wpf.UI.Controls.csproj" /> <ProjectReference Include="..\..\src\TheXamlGuy.NotificationFlyout.Wpf.UI.Controls\TheXamlGuy.NotificationFlyout.Wpf.UI.Controls.csproj" />
<ProjectReference Include="..\..\src\TheXamlGuy.NotificationFlyout.Wpf.UI\TheXamlGuy.NotificationFlyout.Wpf.UI.csproj" /> <ProjectReference Include="..\..\src\TheXamlGuy.NotificationFlyout.Wpf.UI\TheXamlGuy.NotificationFlyout.Wpf.UI.csproj" />
<ProjectReference Include="..\NotificationFlyoutSample\NotificationFlyoutSample.csproj" /> <ProjectReference Include="..\NotificationFlyoutSample\NotificationFlyoutSample.csproj" />
@@ -15,6 +15,7 @@ namespace NotificationFlyoutSample.Host
{ {
Flyout = new SampleFlyout() Flyout = new SampleFlyout()
}; };
app.Run(); app.Run();
} }
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

@@ -0,0 +1,83 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '15.0'">
<VisualStudioVersion>15.0</VisualStudioVersion>
</PropertyGroup>
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x86">
<Configuration>Debug</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x86">
<Configuration>Release</Configuration>
<Platform>x86</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM">
<Configuration>Debug</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM">
<Configuration>Release</Configuration>
<Platform>ARM</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|AnyCPU">
<Configuration>Debug</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|AnyCPU">
<Configuration>Release</Configuration>
<Platform>AnyCPU</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup>
<WapProjPath Condition="'$(WapProjPath)'==''">$(MSBuildExtensionsPath)\Microsoft\DesktopBridge\</WapProjPath>
</PropertyGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.props" />
<PropertyGroup>
<ProjectGuid>faa7e8e0-032d-4c2a-bab6-6e0eed3d5a6d</ProjectGuid>
<TargetPlatformVersion>10.0.19041.0</TargetPlatformVersion>
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
<DefaultLanguage>en-US</DefaultLanguage>
<AppxPackageSigningEnabled>false</AppxPackageSigningEnabled>
<EntryPointProjectUniqueName>..\NotificationFlyoutSample.Launcher\NotificationFlyoutSample.Launcher.csproj</EntryPointProjectUniqueName>
</PropertyGroup>
<ItemGroup>
<AppxManifest Include="Package.appxmanifest">
<SubType>Designer</SubType>
</AppxManifest>
</ItemGroup>
<ItemGroup>
<Content Include="Images\SplashScreen.scale-200.png" />
<Content Include="Images\LockScreenLogo.scale-200.png" />
<Content Include="Images\Square150x150Logo.scale-200.png" />
<Content Include="Images\Square44x44Logo.scale-200.png" />
<Content Include="Images\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Images\StoreLogo.png" />
<Content Include="Images\Wide310x150Logo.scale-200.png" />
</ItemGroup>
<Import Project="$(WapProjPath)\Microsoft.DesktopBridge.targets" />
<ItemGroup>
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.19041.8" PrivateAssets="all" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NotificationFlyoutSample.Launcher\NotificationFlyoutSample.Launcher.csproj">
<SkipGetTargetFrameworkProperties>True</SkipGetTargetFrameworkProperties>
</ProjectReference>
</ItemGroup>
</Project>
@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
IgnorableNamespaces="uap rescap">
<Identity
Name="541ef8e5-df48-4089-bae4-7851e8c5d592"
Publisher="CN=Daniel Clark"
Version="1.0.0.0" />
<Properties>
<DisplayName>NotificationFlyoutSample.Package</DisplayName>
<PublisherDisplayName>Daniel Clark</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.0.0" MaxVersionTested="10.0.0.0" />
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.14393.0" MaxVersionTested="10.0.14393.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="NotificationFlyoutSample.Package"
Description="NotificationFlyoutSample.Package"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" />
<uap:SplashScreen Image="Images\SplashScreen.png" />
</uap:VisualElements>
</Application>
</Applications>
<Capabilities>
<Capability Name="internetClient" />
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>
+126 -126
View File
@@ -10,17 +10,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
global.json = global.json global.json = global.json
EndProjectSection EndProjectSection
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotificationFlyoutSample.Host", "NotificationFlyoutSample.Host\NotificationFlyoutSample.Host.csproj", "{591F26F7-C057-434A-B612-AEB37B1234AE}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotificationFlyoutSample.Launcher", "NotificationFlyoutSample.Launcher\NotificationFlyoutSample.Launcher.csproj", "{5EDD254A-3F8E-4825-B806-5C230488E192}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheXamlGuy.NotificationFlyout.Shared.UI", "..\src\TheXamlGuy.NotificationFlyout.Shared.UI\TheXamlGuy.NotificationFlyout.Shared.UI.csproj", "{38E34B61-E389-4EE1-8D5E-5372568DE982}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheXamlGuy.NotificationFlyout.Common", "..\src\TheXamlGuy.NotificationFlyout.Common\TheXamlGuy.NotificationFlyout.Common.csproj", "{5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheXamlGuy.NotificationFlyout.Uwp.UI.Controls", "..\src\TheXamlGuy.NotificationFlyout.Uwp.UI.Controls\TheXamlGuy.NotificationFlyout.Uwp.UI.Controls.csproj", "{ACA2CC23-A9AE-427F-A900-ED75A96698F4}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheXamlGuy.NotificationFlyout.Shared.UI", "..\src\TheXamlGuy.NotificationFlyout.Shared.UI\TheXamlGuy.NotificationFlyout.Shared.UI.csproj", "{875E7116-3A9B-4CBE-B6D0-20818DB77280}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheXamlGuy.NotificationFlyout.Wpf.UI.Controls", "..\src\TheXamlGuy.NotificationFlyout.Wpf.UI.Controls\TheXamlGuy.NotificationFlyout.Wpf.UI.Controls.csproj", "{BE3B1281-CD44-4291-BE1D-33FC13E61E06}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheXamlGuy.NotificationFlyout.Uwp.UI.Controls", "..\src\TheXamlGuy.NotificationFlyout.Uwp.UI.Controls\TheXamlGuy.NotificationFlyout.Uwp.UI.Controls.csproj", "{0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheXamlGuy.NotificationFlyout.Wpf.UI", "..\src\TheXamlGuy.NotificationFlyout.Wpf.UI\TheXamlGuy.NotificationFlyout.Wpf.UI.csproj", "{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheXamlGuy.NotificationFlyout.Wpf.UI", "..\src\TheXamlGuy.NotificationFlyout.Wpf.UI\TheXamlGuy.NotificationFlyout.Wpf.UI.csproj", "{F6040CB8-83EE-47B9-8DD7-DF43CD555956}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheXamlGuy.NotificationFlyout.Common", "..\src\TheXamlGuy.NotificationFlyout.Common\TheXamlGuy.NotificationFlyout.Common.csproj", "{293834F2-4A99-4C92-A165-7C617D98FCC7}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheXamlGuy.NotificationFlyout.Wpf.UI.Controls", "..\src\TheXamlGuy.NotificationFlyout.Wpf.UI.Controls\TheXamlGuy.NotificationFlyout.Wpf.UI.Controls.csproj", "{66433384-A10C-44A5-B734-400990A569F0}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -63,126 +63,126 @@ Global
{2057ADE0-C61E-45EE-BB7E-A469FE4D4C41}.Release|x86.ActiveCfg = Release|x86 {2057ADE0-C61E-45EE-BB7E-A469FE4D4C41}.Release|x86.ActiveCfg = Release|x86
{2057ADE0-C61E-45EE-BB7E-A469FE4D4C41}.Release|x86.Build.0 = Release|x86 {2057ADE0-C61E-45EE-BB7E-A469FE4D4C41}.Release|x86.Build.0 = Release|x86
{2057ADE0-C61E-45EE-BB7E-A469FE4D4C41}.Release|x86.Deploy.0 = Release|x86 {2057ADE0-C61E-45EE-BB7E-A469FE4D4C41}.Release|x86.Deploy.0 = Release|x86
{591F26F7-C057-434A-B612-AEB37B1234AE}.Debug|Any CPU.ActiveCfg = Debug|x64 {5EDD254A-3F8E-4825-B806-5C230488E192}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{591F26F7-C057-434A-B612-AEB37B1234AE}.Debug|Any CPU.Build.0 = Debug|x64 {5EDD254A-3F8E-4825-B806-5C230488E192}.Debug|Any CPU.Build.0 = Debug|Any CPU
{591F26F7-C057-434A-B612-AEB37B1234AE}.Debug|ARM.ActiveCfg = Debug|Any CPU {5EDD254A-3F8E-4825-B806-5C230488E192}.Debug|ARM.ActiveCfg = Debug|Any CPU
{591F26F7-C057-434A-B612-AEB37B1234AE}.Debug|ARM.Build.0 = Debug|Any CPU {5EDD254A-3F8E-4825-B806-5C230488E192}.Debug|ARM.Build.0 = Debug|Any CPU
{591F26F7-C057-434A-B612-AEB37B1234AE}.Debug|ARM64.ActiveCfg = Debug|Any CPU {5EDD254A-3F8E-4825-B806-5C230488E192}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{591F26F7-C057-434A-B612-AEB37B1234AE}.Debug|ARM64.Build.0 = Debug|Any CPU {5EDD254A-3F8E-4825-B806-5C230488E192}.Debug|ARM64.Build.0 = Debug|Any CPU
{591F26F7-C057-434A-B612-AEB37B1234AE}.Debug|x64.ActiveCfg = Debug|x64 {5EDD254A-3F8E-4825-B806-5C230488E192}.Debug|x64.ActiveCfg = Debug|x64
{591F26F7-C057-434A-B612-AEB37B1234AE}.Debug|x64.Build.0 = Debug|x64 {5EDD254A-3F8E-4825-B806-5C230488E192}.Debug|x64.Build.0 = Debug|x64
{591F26F7-C057-434A-B612-AEB37B1234AE}.Debug|x86.ActiveCfg = Debug|Any CPU {5EDD254A-3F8E-4825-B806-5C230488E192}.Debug|x86.ActiveCfg = Debug|Any CPU
{591F26F7-C057-434A-B612-AEB37B1234AE}.Debug|x86.Build.0 = Debug|Any CPU {5EDD254A-3F8E-4825-B806-5C230488E192}.Debug|x86.Build.0 = Debug|Any CPU
{591F26F7-C057-434A-B612-AEB37B1234AE}.Release|Any CPU.ActiveCfg = Release|Any CPU {5EDD254A-3F8E-4825-B806-5C230488E192}.Release|Any CPU.ActiveCfg = Release|Any CPU
{591F26F7-C057-434A-B612-AEB37B1234AE}.Release|Any CPU.Build.0 = Release|Any CPU {5EDD254A-3F8E-4825-B806-5C230488E192}.Release|Any CPU.Build.0 = Release|Any CPU
{591F26F7-C057-434A-B612-AEB37B1234AE}.Release|ARM.ActiveCfg = Release|Any CPU {5EDD254A-3F8E-4825-B806-5C230488E192}.Release|ARM.ActiveCfg = Release|Any CPU
{591F26F7-C057-434A-B612-AEB37B1234AE}.Release|ARM.Build.0 = Release|Any CPU {5EDD254A-3F8E-4825-B806-5C230488E192}.Release|ARM.Build.0 = Release|Any CPU
{591F26F7-C057-434A-B612-AEB37B1234AE}.Release|ARM64.ActiveCfg = Release|Any CPU {5EDD254A-3F8E-4825-B806-5C230488E192}.Release|ARM64.ActiveCfg = Release|Any CPU
{591F26F7-C057-434A-B612-AEB37B1234AE}.Release|ARM64.Build.0 = Release|Any CPU {5EDD254A-3F8E-4825-B806-5C230488E192}.Release|ARM64.Build.0 = Release|Any CPU
{591F26F7-C057-434A-B612-AEB37B1234AE}.Release|x64.ActiveCfg = Release|x64 {5EDD254A-3F8E-4825-B806-5C230488E192}.Release|x64.ActiveCfg = Release|x64
{591F26F7-C057-434A-B612-AEB37B1234AE}.Release|x64.Build.0 = Release|x64 {5EDD254A-3F8E-4825-B806-5C230488E192}.Release|x64.Build.0 = Release|x64
{591F26F7-C057-434A-B612-AEB37B1234AE}.Release|x86.ActiveCfg = Release|Any CPU {5EDD254A-3F8E-4825-B806-5C230488E192}.Release|x86.ActiveCfg = Release|Any CPU
{591F26F7-C057-434A-B612-AEB37B1234AE}.Release|x86.Build.0 = Release|Any CPU {5EDD254A-3F8E-4825-B806-5C230488E192}.Release|x86.Build.0 = Release|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Debug|Any CPU.Build.0 = Debug|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Debug|ARM.ActiveCfg = Debug|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Debug|ARM.ActiveCfg = Debug|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Debug|ARM.Build.0 = Debug|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Debug|ARM.Build.0 = Debug|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Debug|ARM64.ActiveCfg = Debug|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Debug|ARM64.Build.0 = Debug|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Debug|ARM64.Build.0 = Debug|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Debug|x64.ActiveCfg = Debug|x64 {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Debug|x64.ActiveCfg = Debug|x64
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Debug|x64.Build.0 = Debug|x64 {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Debug|x64.Build.0 = Debug|x64
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Debug|x86.ActiveCfg = Debug|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Debug|x86.ActiveCfg = Debug|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Debug|x86.Build.0 = Debug|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Debug|x86.Build.0 = Debug|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Release|Any CPU.ActiveCfg = Release|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Release|Any CPU.Build.0 = Release|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Release|Any CPU.Build.0 = Release|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Release|ARM.ActiveCfg = Release|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Release|ARM.ActiveCfg = Release|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Release|ARM.Build.0 = Release|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Release|ARM.Build.0 = Release|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Release|ARM64.ActiveCfg = Release|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Release|ARM64.ActiveCfg = Release|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Release|ARM64.Build.0 = Release|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Release|ARM64.Build.0 = Release|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Release|x64.ActiveCfg = Release|x64 {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Release|x64.ActiveCfg = Release|x64
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Release|x64.Build.0 = Release|x64 {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Release|x64.Build.0 = Release|x64
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Release|x86.ActiveCfg = Release|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Release|x86.ActiveCfg = Release|Any CPU
{38E34B61-E389-4EE1-8D5E-5372568DE982}.Release|x86.Build.0 = Release|Any CPU {5EE122E5-AFD9-4B03-A98D-34CBB0B3B3F0}.Release|x86.Build.0 = Release|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Debug|Any CPU.Build.0 = Debug|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Debug|ARM.ActiveCfg = Debug|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Debug|ARM.ActiveCfg = Debug|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Debug|ARM.Build.0 = Debug|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Debug|ARM.Build.0 = Debug|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Debug|ARM64.ActiveCfg = Debug|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Debug|ARM64.Build.0 = Debug|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Debug|ARM64.Build.0 = Debug|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Debug|x64.ActiveCfg = Debug|x64 {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Debug|x64.ActiveCfg = Debug|x64
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Debug|x64.Build.0 = Debug|x64 {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Debug|x64.Build.0 = Debug|x64
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Debug|x86.ActiveCfg = Debug|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Debug|x86.ActiveCfg = Debug|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Debug|x86.Build.0 = Debug|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Debug|x86.Build.0 = Debug|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Release|Any CPU.ActiveCfg = Release|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Release|Any CPU.Build.0 = Release|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Release|Any CPU.Build.0 = Release|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Release|ARM.ActiveCfg = Release|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Release|ARM.ActiveCfg = Release|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Release|ARM.Build.0 = Release|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Release|ARM.Build.0 = Release|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Release|ARM64.ActiveCfg = Release|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Release|ARM64.ActiveCfg = Release|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Release|ARM64.Build.0 = Release|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Release|ARM64.Build.0 = Release|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Release|x64.ActiveCfg = Release|x64 {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Release|x64.ActiveCfg = Release|x64
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Release|x64.Build.0 = Release|x64 {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Release|x64.Build.0 = Release|x64
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Release|x86.ActiveCfg = Release|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Release|x86.ActiveCfg = Release|Any CPU
{ACA2CC23-A9AE-427F-A900-ED75A96698F4}.Release|x86.Build.0 = Release|Any CPU {875E7116-3A9B-4CBE-B6D0-20818DB77280}.Release|x86.Build.0 = Release|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Debug|Any CPU.Build.0 = Debug|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Debug|ARM.ActiveCfg = Debug|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Debug|ARM.ActiveCfg = Debug|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Debug|ARM.Build.0 = Debug|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Debug|ARM.Build.0 = Debug|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Debug|ARM64.ActiveCfg = Debug|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Debug|ARM64.Build.0 = Debug|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Debug|ARM64.Build.0 = Debug|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Debug|x64.ActiveCfg = Debug|x64 {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Debug|x64.ActiveCfg = Debug|x64
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Debug|x64.Build.0 = Debug|x64 {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Debug|x64.Build.0 = Debug|x64
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Debug|x86.ActiveCfg = Debug|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Debug|x86.ActiveCfg = Debug|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Debug|x86.Build.0 = Debug|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Debug|x86.Build.0 = Debug|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Release|Any CPU.ActiveCfg = Release|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Release|Any CPU.Build.0 = Release|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Release|Any CPU.Build.0 = Release|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Release|ARM.ActiveCfg = Release|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Release|ARM.ActiveCfg = Release|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Release|ARM.Build.0 = Release|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Release|ARM.Build.0 = Release|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Release|ARM64.ActiveCfg = Release|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Release|ARM64.ActiveCfg = Release|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Release|ARM64.Build.0 = Release|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Release|ARM64.Build.0 = Release|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Release|x64.ActiveCfg = Release|x64 {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Release|x64.ActiveCfg = Release|x64
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Release|x64.Build.0 = Release|x64 {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Release|x64.Build.0 = Release|x64
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Release|x86.ActiveCfg = Release|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Release|x86.ActiveCfg = Release|Any CPU
{BE3B1281-CD44-4291-BE1D-33FC13E61E06}.Release|x86.Build.0 = Release|Any CPU {0C268B32-CED0-4F79-9CB0-B7AE84BE9EC8}.Release|x86.Build.0 = Release|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Debug|Any CPU.Build.0 = Debug|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Debug|ARM.ActiveCfg = Debug|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Debug|ARM.ActiveCfg = Debug|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Debug|ARM.Build.0 = Debug|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Debug|ARM.Build.0 = Debug|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Debug|ARM64.ActiveCfg = Debug|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Debug|ARM64.Build.0 = Debug|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Debug|ARM64.Build.0 = Debug|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Debug|x64.ActiveCfg = Debug|x64 {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Debug|x64.ActiveCfg = Debug|x64
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Debug|x64.Build.0 = Debug|x64 {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Debug|x64.Build.0 = Debug|x64
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Debug|x86.ActiveCfg = Debug|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Debug|x86.ActiveCfg = Debug|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Debug|x86.Build.0 = Debug|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Debug|x86.Build.0 = Debug|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Release|Any CPU.ActiveCfg = Release|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Release|Any CPU.Build.0 = Release|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Release|Any CPU.Build.0 = Release|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Release|ARM.ActiveCfg = Release|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Release|ARM.ActiveCfg = Release|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Release|ARM.Build.0 = Release|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Release|ARM.Build.0 = Release|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Release|ARM64.ActiveCfg = Release|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Release|ARM64.ActiveCfg = Release|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Release|ARM64.Build.0 = Release|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Release|ARM64.Build.0 = Release|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Release|x64.ActiveCfg = Release|x64 {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Release|x64.ActiveCfg = Release|x64
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Release|x64.Build.0 = Release|x64 {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Release|x64.Build.0 = Release|x64
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Release|x86.ActiveCfg = Release|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Release|x86.ActiveCfg = Release|Any CPU
{A38BA7F7-5FEC-49F2-9FEB-F80AFE5934AF}.Release|x86.Build.0 = Release|Any CPU {F6040CB8-83EE-47B9-8DD7-DF43CD555956}.Release|x86.Build.0 = Release|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Debug|Any CPU.Build.0 = Debug|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Debug|ARM.ActiveCfg = Debug|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Debug|ARM.ActiveCfg = Debug|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Debug|ARM.Build.0 = Debug|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Debug|ARM.Build.0 = Debug|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Debug|ARM64.ActiveCfg = Debug|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Debug|ARM64.Build.0 = Debug|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Debug|ARM64.Build.0 = Debug|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Debug|x64.ActiveCfg = Debug|x64 {66433384-A10C-44A5-B734-400990A569F0}.Debug|x64.ActiveCfg = Debug|x64
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Debug|x64.Build.0 = Debug|x64 {66433384-A10C-44A5-B734-400990A569F0}.Debug|x64.Build.0 = Debug|x64
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Debug|x86.ActiveCfg = Debug|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Debug|x86.ActiveCfg = Debug|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Debug|x86.Build.0 = Debug|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Debug|x86.Build.0 = Debug|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Release|Any CPU.ActiveCfg = Release|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Release|Any CPU.Build.0 = Release|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Release|Any CPU.Build.0 = Release|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Release|ARM.ActiveCfg = Release|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Release|ARM.ActiveCfg = Release|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Release|ARM.Build.0 = Release|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Release|ARM.Build.0 = Release|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Release|ARM64.ActiveCfg = Release|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Release|ARM64.ActiveCfg = Release|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Release|ARM64.Build.0 = Release|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Release|ARM64.Build.0 = Release|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Release|x64.ActiveCfg = Release|x64 {66433384-A10C-44A5-B734-400990A569F0}.Release|x64.ActiveCfg = Release|x64
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Release|x64.Build.0 = Release|x64 {66433384-A10C-44A5-B734-400990A569F0}.Release|x64.Build.0 = Release|x64
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Release|x86.ActiveCfg = Release|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Release|x86.ActiveCfg = Release|Any CPU
{293834F2-4A99-4C92-A165-7C617D98FCC7}.Release|x86.Build.0 = Release|Any CPU {66433384-A10C-44A5-B734-400990A569F0}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE
@@ -123,6 +123,9 @@
<Compile Include="SampleFlyout.xaml.cs"> <Compile Include="SampleFlyout.xaml.cs">
<DependentUpon>SampleFlyout.xaml</DependentUpon> <DependentUpon>SampleFlyout.xaml</DependentUpon>
</Compile> </Compile>
<Compile Include="Test.xaml.cs">
<DependentUpon>Test.xaml</DependentUpon>
</Compile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<AppxManifest Include="Package.appxmanifest"> <AppxManifest Include="Package.appxmanifest">
@@ -161,16 +164,20 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</Page> </Page>
<Page Include="Test.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\src\TheXamlGuy.NotificationFlyout.Uwp.UI.Controls\TheXamlGuy.NotificationFlyout.Uwp.UI.Controls.csproj"> <Reference Include="TheXamlGuy.NotificationFlyout.Shared.UI, Version=0.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<Project>{a970d11a-ad9f-4a3f-a509-16fa5f9ac779}</Project> <SpecificVersion>False</SpecificVersion>
<Name>TheXamlGuy.NotificationFlyout.Uwp.UI.Controls</Name> <HintPath>..\..\src\TheXamlGuy.NotificationFlyout.Shared.UI\bin\x64\Release\uap10.0.19041\TheXamlGuy.NotificationFlyout.Shared.UI.dll</HintPath>
</ProjectReference> </Reference>
<ProjectReference Include="..\..\src\TheXamlGuy.NotificationFlyout.Shared.UI\TheXamlGuy.NotificationFlyout.Shared.UI.csproj"> <Reference Include="TheXamlGuy.NotificationFlyout.Uwp.UI.Controls, Version=1.0.0.0, Culture=neutral, processorArchitecture=AMD64">
<Project>{a970d11a-ad9f-4a3f-a509-16fa5f9ac779}</Project> <SpecificVersion>False</SpecificVersion>
<Name>TheXamlGuy.NotificationFlyout.Shared.UI</Name> <HintPath>..\..\src\TheXamlGuy.NotificationFlyout.Uwp.UI.Controls\bin\x64\Release\uap10.0.19041\TheXamlGuy.NotificationFlyout.Uwp.UI.Controls.dll</HintPath>
</ProjectReference> </Reference>
</ItemGroup> </ItemGroup>
<PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' "> <PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
<VisualStudioVersion>14.0</VisualStudioVersion> <VisualStudioVersion>14.0</VisualStudioVersion>
@@ -2,11 +2,32 @@
x:Class="NotificationFlyoutSample.SampleFlyout" x:Class="NotificationFlyoutSample.SampleFlyout"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:TheXamlGuy.NotificationFlyout.Uwp.UI.Controls"> xmlns:controls="using:TheXamlGuy.NotificationFlyout.Uwp.UI.Controls"
<Grid Width="400" Height="600"> VerticalContentAlignment="Top">
<Button <controls:NotificationFlyout.ContextFlyout>
HorizontalAlignment="Center" <MenuFlyout>
VerticalAlignment="Center" <MenuFlyoutItem Click="OnCloseMenuFlyoutItemClick" Text="Close" />
Content="Hello World!" /> </MenuFlyout>
</controls:NotificationFlyout.ContextFlyout>
<Grid Margin="24" VerticalAlignment="Top">
<StackPanel Background="Red">
<ToggleSwitch
Header="Is light dimissed enabled"
IsOn="True"
OffContent="False"
OnContent="True"
Toggled="ToggleSwitch_Toggled" />
<ComboBox Header="Placement" SelectionChanged="ComboBox_SelectionChanged">
<ComboBoxItem Content="Auto" />
<ComboBoxItem Content="FullRight" />
</ComboBox>
<Slider />
<TextBox />
<CalendarDatePicker />
<CalendarView />
<Button Click="Button_Click" Content="hello" />
<TimePicker />
</StackPanel>
</Grid> </Grid>
</controls:NotificationFlyout> </controls:NotificationFlyout>
@@ -1,4 +1,6 @@
using Windows.UI.Xaml; using TheXamlGuy.NotificationFlyout.Uwp.UI.Controls;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
namespace NotificationFlyoutSample namespace NotificationFlyoutSample
{ {
@@ -14,5 +16,38 @@ namespace NotificationFlyoutSample
var app = GetApplication(); var app = GetApplication();
app.Exit(); app.Exit();
} }
private void ToggleSwitch_Toggled(object sender, RoutedEventArgs e)
{
var toggleSwitch = sender as ToggleSwitch;
if (toggleSwitch.IsOn)
{
this.IsLightDismissEnabled = true;
}
else
{
this.IsLightDismissEnabled = false;
}
}
private void ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var comboBox = sender as ComboBox;
if (comboBox.SelectedIndex == 0)
{
this.Placement = NotificationFlyoutPlacement.Auto;
}
else
{
this.Placement = NotificationFlyoutPlacement.FullRight;
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var app = GetApplication();
app.OpenAsWindow<Test>();
}
} }
} }
@@ -0,0 +1,25 @@
<UserControl
x:Class="NotificationFlyoutSample.Test"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:NotificationFlyoutSample"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
d:DesignHeight="300"
d:DesignWidth="400"
mc:Ignorable="d">
<Grid>
<Button Click="TestButtonClick1" Content="Show TeachingTip" />
<muxc:TeachingTip x:Name="ToggleThemeTeachingTip1" ShouldConstrainToRootBounds="False">
<muxc:TeachingTip.Content>
<Border Width="500" Height="500">
<Slider />
</Border>
</muxc:TeachingTip.Content>
</muxc:TeachingTip>
</Grid>
</UserControl>
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
// The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
namespace NotificationFlyoutSample
{
public sealed partial class Test : UserControl
{
public Test()
{
this.InitializeComponent();
}
private void TestButtonClick1(object sender, RoutedEventArgs e)
{
ToggleThemeTeachingTip1.XamlRoot = this.XamlRoot;
ToggleThemeTeachingTip1.IsOpen = true;
}
}
}
@@ -24,7 +24,7 @@ namespace TheXamlGuy.NotificationFlyout.Common.Helpers
GetAppBarPosition(ref appBarData); GetAppBarPosition(ref appBarData);
state.Rect = appBarData.rect.ToRect(); state.Rect = appBarData.rect.ToRect();
state.Position = (TaskbarPosition)appBarData.uEdge; state.Placement = (TaskbarPlacement)appBarData.uEdge;
return state; return state;
} }
@@ -1,7 +1,7 @@
namespace TheXamlGuy.NotificationFlyout.Common.Helpers namespace TheXamlGuy.NotificationFlyout.Common.Helpers
{ {
public enum TaskbarPosition public enum TaskbarPlacement
{ {
Left = 0, Left = 0,
Top = 1, Top = 1,
@@ -4,7 +4,7 @@ namespace TheXamlGuy.NotificationFlyout.Common.Helpers
{ {
public struct TaskbarState public struct TaskbarState
{ {
public TaskbarPosition Position; public TaskbarPlacement Placement;
public Rect Rect; public Rect Rect;
public Screen Screen; public Screen Screen;
} }
@@ -6,6 +6,10 @@ namespace TheXamlGuy.NotificationFlyout.Shared.UI
{ {
void Exit(); void Exit();
void OpenFlyout();
void CloseFlyout();
void OpenAsWindow<TUIElement>() where TUIElement : UIElement; void OpenAsWindow<TUIElement>() where TUIElement : UIElement;
} }
} }
@@ -1,72 +1,70 @@
using System; using System;
using System.Numerics;
using TheXamlGuy.NotificationFlyout.Shared.UI; using TheXamlGuy.NotificationFlyout.Shared.UI;
using Windows.Foundation; using Windows.Foundation;
using Windows.UI.Xaml; using Windows.UI.Xaml;
using Windows.UI.Xaml.Markup; using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media; using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Shapes;
namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
{ {
[ContentProperty(Name = "Content")] public class NotificationFlyout : ContentControl
public class NotificationFlyout : DependencyObject
{ {
public static readonly DependencyProperty FlyoutPresenterStyleProperty =
DependencyProperty.Register(nameof(FlyoutPresenterStyle),
typeof(Style), typeof(NotificationFlyout),
new PropertyMetadata(null));
public static readonly DependencyProperty IconSourceProperty = public static readonly DependencyProperty IconSourceProperty =
DependencyProperty.Register(nameof(IconSource), DependencyProperty.Register(nameof(IconSource),
typeof(ImageSource), typeof(NotificationFlyout), typeof(ImageSource), typeof(NotificationFlyout),
new PropertyMetadata(null, OnIconPropertyChanged)); new PropertyMetadata(null, OnIconPropertyChanged));
public static readonly DependencyProperty IsLightDismissEnabledProperty =
DependencyProperty.Register(nameof(IsLightDismissEnabled),
typeof(bool), typeof(NotificationFlyout),
new PropertyMetadata(true));
public static readonly DependencyProperty LightIconSourceProperty = public static readonly DependencyProperty LightIconSourceProperty =
DependencyProperty.Register(nameof(LightIconSource), DependencyProperty.Register(nameof(LightIconSource),
typeof(ImageSource), typeof(NotificationFlyout), typeof(ImageSource), typeof(NotificationFlyout),
new PropertyMetadata(null)); new PropertyMetadata(null));
public static readonly DependencyProperty RequestedThemeProperty = public static readonly DependencyProperty PlacementProperty =
DependencyProperty.Register(nameof(RequestedTheme), DependencyProperty.Register(nameof(Placement),
typeof(ElementTheme), typeof(NotificationFlyout), typeof(NotificationFlyoutPlacement), typeof(NotificationFlyout),
new PropertyMetadata(ElementTheme.Default)); new PropertyMetadata(NotificationFlyoutPlacement.Auto, OnPlacementPropertyChanged));
public static DependencyProperty ContentProperty = public static readonly DependencyProperty TemplateSettingsProperty =
DependencyProperty.Register(nameof(Content), DependencyProperty.Register(nameof(TemplateSettings),
typeof(UIElement), typeof(NotificationFlyout), typeof(NotificationFlyoutTemplateSettings), typeof(NotificationFlyout),
new PropertyMetadata(null)); new PropertyMetadata(null));
public static DependencyProperty ContextMenuProperty = private const double OffsetValue = 6;
DependencyProperty.Register(nameof(ContextMenu),
typeof(NotificationFlyoutContextMenu), typeof(NotificationFlyout),
new PropertyMetadata(null, OnContextMenuPropertyChanged));
private static INotificationFlyoutApplication _applicationInstance; private static INotificationFlyoutApplication _applicationInstance;
private Border _backgroundElement;
private UIElement _child;
private Border _container;
private Popup _popup;
public NotificationFlyout()
{
DefaultStyleKey = typeof(NotificationFlyout);
TemplateSettings = new NotificationFlyoutTemplateSettings();
}
public event EventHandler<object> Closed; public event EventHandler<object> Closed;
public event TypedEventHandler<NotificationFlyout, NotificationFlyoutClosingEventArgs> Closing;
public event EventHandler<object> Opened; public event EventHandler<object> Opened;
public event EventHandler<object> Opening;
internal event EventHandler ContextMenuChanged; internal event EventHandler IconSourcePropertyChanged;
internal event EventHandler IconSourceChanged;
public UIElement Content internal event EventHandler InteractedWith;
{
get => (UIElement)GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
public NotificationFlyoutContextMenu ContextMenu internal event EventHandler PlacementPropertyChanged;
{
get => (NotificationFlyoutContextMenu)GetValue(ContextMenuProperty);
set => SetValue(ContextMenuProperty, value);
}
public Style FlyoutPresenterStyle
{
get => (Style)GetValue(FlyoutPresenterStyleProperty);
set => SetValue(FlyoutPresenterStyleProperty, value);
}
public ImageSource IconSource public ImageSource IconSource
{ {
@@ -74,34 +72,188 @@ namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
set => SetValue(IconSourceProperty, value); set => SetValue(IconSourceProperty, value);
} }
public bool IsLightDismissEnabled
{
get => (bool)GetValue(IsLightDismissEnabledProperty);
set => SetValue(IsLightDismissEnabledProperty, value);
}
public ImageSource LightIconSource public ImageSource LightIconSource
{ {
get => (ImageSource)GetValue(LightIconSourceProperty); get => (ImageSource)GetValue(LightIconSourceProperty);
set => SetValue(LightIconSourceProperty, value); set => SetValue(LightIconSourceProperty, value);
} }
public ElementTheme RequestedTheme public NotificationFlyoutPlacement Placement
{ {
get => (ElementTheme)GetValue(RequestedThemeProperty); get => (NotificationFlyoutPlacement)GetValue(PlacementProperty);
set => SetValue(RequestedThemeProperty, value); set => SetValue(PlacementProperty, value);
}
public NotificationFlyoutTemplateSettings TemplateSettings
{
get => (NotificationFlyoutTemplateSettings)GetValue(TemplateSettingsProperty);
set => SetValue(TemplateSettingsProperty, value);
} }
public static INotificationFlyoutApplication GetApplication() => _applicationInstance; public static INotificationFlyoutApplication GetApplication() => _applicationInstance;
public void Close()
{
if (_popup == null)
{
PreparePopup();
}
_popup.IsOpen = false;
}
public void Open()
{
if (_popup == null)
{
PreparePopup();
}
if (!_popup.IsOpen)
{
_popup.Child = _child;
_popup.IsOpen = true;
}
}
internal static void SetApplication(INotificationFlyoutApplication application) => _applicationInstance = application; internal static void SetApplication(INotificationFlyoutApplication application) => _applicationInstance = application;
internal void InvokeClosedEvent(object obj) => Closed?.Invoke(this, obj); internal void Close(bool shouldRespectIsLightDismissEnbabled)
internal void InvokeClosingEvent(NotificationFlyoutClosingEventArgs eventArgs) => Closing?.Invoke(this, eventArgs);
internal void InvokeOpenedEvent(object obj) => Opened?.Invoke(this, obj);
internal void InvokeOpeningEvent(object obj) => Opening?.Invoke(this, obj);
private static void OnContextMenuPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{ {
var sender = dependencyObject as NotificationFlyout; if (!shouldRespectIsLightDismissEnbabled || IsLightDismissEnabled)
sender?.OnContextMenuPropertyChanged(); {
Close();
}
}
internal void SetPlacement(double horizontalOffset, double verticalOffset, double workingAreaHeight, double workingAreaWidth, NotificationFlyoutTaskbarPlacement flyoutTaskbarPlacement)
{
if (_popup == null)
{
PreparePopup();
}
VisualStateManager.GoToState(this, "DefaultPlacement", true);
_child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
var width = _child.DesiredSize.Width - 1;
var height = Placement == NotificationFlyoutPlacement.Auto ? _child.DesiredSize.Height : workingAreaHeight + 1;
var desiredHorizontalOffset = horizontalOffset;
var desiredVerticalOffset = verticalOffset;
var visualState = "";
switch (Placement)
{
case NotificationFlyoutPlacement.Auto:
visualState = $"{flyoutTaskbarPlacement}";
switch (flyoutTaskbarPlacement)
{
case NotificationFlyoutTaskbarPlacement.Left:
desiredHorizontalOffset -= OffsetValue;
desiredVerticalOffset -= height;
break;
case NotificationFlyoutTaskbarPlacement.Top:
desiredHorizontalOffset -= width + OffsetValue;
desiredVerticalOffset -= OffsetValue;
break;
case NotificationFlyoutTaskbarPlacement.Right:
desiredHorizontalOffset -= width + OffsetValue;
desiredVerticalOffset -= height;
break;
case NotificationFlyoutTaskbarPlacement.Bottom:
desiredHorizontalOffset -= width + OffsetValue;
desiredVerticalOffset -= height;
break;
}
break;
case NotificationFlyoutPlacement.FullRight:
visualState = $"{Placement}";
switch (flyoutTaskbarPlacement)
{
case NotificationFlyoutTaskbarPlacement.Left:
desiredHorizontalOffset += workingAreaWidth - width - OffsetValue;
desiredVerticalOffset = -OffsetValue;
break;
case NotificationFlyoutTaskbarPlacement.Top:
desiredHorizontalOffset = workingAreaWidth - width - OffsetValue;
desiredVerticalOffset += -OffsetValue;
break;
case NotificationFlyoutTaskbarPlacement.Right:
desiredHorizontalOffset -= width + OffsetValue;
desiredVerticalOffset = -OffsetValue;
break;
case NotificationFlyoutTaskbarPlacement.Bottom:
desiredHorizontalOffset -= width + OffsetValue;
desiredVerticalOffset = -OffsetValue;
break;
}
break;
}
TemplateSettings.SetValue(NotificationFlyoutTemplateSettings.HeightProperty, height);
TemplateSettings.SetValue(NotificationFlyoutTemplateSettings.WidthProperty, width);
TemplateSettings.SetValue(NotificationFlyoutTemplateSettings.NegativeHeightProperty, -height);
TemplateSettings.SetValue(NotificationFlyoutTemplateSettings.NegativeWidthProperty, -width);
_popup.SetValue(Popup.HorizontalOffsetProperty, desiredHorizontalOffset);
_popup.SetValue(Popup.VerticalOffsetProperty, desiredVerticalOffset);
VisualStateManager.GoToState(this, $"{visualState}Placement", true);
}
internal void ShowContextMenuAt(double x, double y)
{
if (ContextFlyout == null) return;
ContextFlyout.ShouldConstrainToRootBounds = false;
ContextFlyout.XamlRoot = XamlRoot;
ContextFlyout.ShowAt(_container);
ContextFlyout.ShowAt(_container, new FlyoutShowOptions
{
Position = new Point(x, y),
ShowMode = FlyoutShowMode.Standard
});
}
internal void UpdateTheme(bool isColorPrevalence) => VisualStateManager.GoToState(this, isColorPrevalence ? "ColorPrevalenceTheme" : "DefaultTheme", true);
protected override void OnApplyTemplate()
{
_container = GetTemplateChild("Container") as Border;
if (_container != null)
{
if (_child != null)
{
_child.PointerPressed += OnPointerPressed;
_child.GotFocus -= OnGotFocus;
}
_child = _container.Child;
_child.PointerPressed += OnPointerPressed;
_child.GotFocus += OnGotFocus;
_container.Child = null;
}
_backgroundElement = GetTemplateChild("BackgroundElement") as Border;
if (_backgroundElement != null)
{
_backgroundElement.Shadow = new ThemeShadow();
var currentTranslation = _backgroundElement.Translation;
var translation = new Vector3(currentTranslation.X, currentTranslation.Y, 32.0f);
_backgroundElement.Translation = translation;
}
} }
private static void OnIconPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) private static void OnIconPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
@@ -110,8 +262,42 @@ namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
sender?.OnIconPropertyChanged(); sender?.OnIconPropertyChanged();
} }
private void OnContextMenuPropertyChanged() => ContextMenuChanged?.Invoke(this, EventArgs.Empty); private static void OnPlacementPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
var sender = dependencyObject as NotificationFlyout;
sender?.OnPlacementPropertyChanged();
}
private void OnIconPropertyChanged() => IconSourceChanged?.Invoke(this, EventArgs.Empty); private void OnGotFocus(object sender, RoutedEventArgs args) => InteractedWith?.Invoke(this, EventArgs.Empty);
private void OnIconPropertyChanged() => IconSourcePropertyChanged?.Invoke(this, EventArgs.Empty);
private void OnPlacementPropertyChanged() => PlacementPropertyChanged?.Invoke(this, EventArgs.Empty);
private void OnPointerPressed(object sender, PointerRoutedEventArgs args) => InteractedWith?.Invoke(this, EventArgs.Empty);
private void OnPopupClosed(object sender, object args) => Closed?.Invoke(this, args);
private void OnPopupOpened(object sender, object args) => Opened?.Invoke(this, args);
private void PreparePopup()
{
if (_popup != null)
{
_popup.Opened -= OnPopupOpened;
_popup.Closed -= OnPopupClosed;
}
_popup = new Popup
{
XamlRoot = XamlRoot,
ShouldConstrainToRootBounds = false,
HorizontalOffset = -OffsetValue,
VerticalOffset = -OffsetValue
};
_popup.Opened += OnPopupOpened;
_popup.Closed += OnPopupClosed;
}
} }
} }
@@ -0,0 +1,123 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:TheXamlGuy.NotificationFlyout.Uwp.UI.Controls">
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<AcrylicBrush
x:Key="AcrylicBackgroundFillColorBrush"
BackgroundSource="HostBackdrop"
FallbackColor="#2C2C2C"
TintColor="#2C2C2C"
TintOpacity="0.8" />
<StaticResource x:Key="NotificationFlyoutPresenterBackgroundBrush" ResourceKey="AcrylicBackgroundFillColorBrush" />
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<AcrylicBrush
x:Key="AcrylicBackgroundFillColorBrush"
BackgroundSource="HostBackdrop"
FallbackColor="#F9F9F9"
TintColor="#FCFCFC"
TintOpacity="0.8" />
<StaticResource x:Key="NotificationFlyoutPresenterBackgroundBrush" ResourceKey="AcrylicBackgroundFillColorBrush" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<AcrylicBrush
x:Key="NotificationFlyoutPresenterBackgroundAccentBrush"
BackgroundSource="HostBackdrop"
FallbackColor="{ThemeResource SystemAccentColorDark1}"
TintColor="{ThemeResource SystemAccentColorDark1}"
TintOpacity="0.8" />
<Style TargetType="controls:NotificationFlyout">
<Setter Property="Background" Value="{ThemeResource NotificationFlyoutPresenterBackgroundBrush}" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:NotificationFlyout">
<Border x:Name="Container">
<Grid x:Name="LayoutRoot" Margin="{TemplateBinding Margin}">
<Border
x:Name="BackgroundElement"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BackgroundSizing="OuterBorderEdge"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Border.Transitions>
<TransitionCollection>
<EntranceThemeTransition x:Name="EntranceThemeTransition" />
</TransitionCollection>
</Border.Transitions>
<Grid>
<ScrollViewer
x:Name="ScrollViewer"
AutomationProperties.AccessibilityView="Raw"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}">
<ContentControl
x:Name="ContentPresenter"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}" />
</ScrollViewer>
</Grid>
</Border>
</Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="PlacementStates">
<VisualState x:Name="DefaultPlacement" />
<VisualState x:Name="BottomPlacement">
<VisualState.Setters>
<Setter Target="EntranceThemeTransition.FromHorizontalOffset" Value="0" />
<Setter Target="EntranceThemeTransition.FromVerticalOffset" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.Height}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="TopPlacement">
<VisualState.Setters>
<Setter Target="EntranceThemeTransition.FromHorizontalOffset" Value="0" />
<Setter Target="EntranceThemeTransition.FromVerticalOffset" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.NegativeHeight}" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="LeftPlacement">
<VisualState.Setters>
<Setter Target="EntranceThemeTransition.FromHorizontalOffset" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.NegativeWidth}" />
<Setter Target="EntranceThemeTransition.FromVerticalOffset" Value="0" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="RightPlacement">
<VisualState.Setters>
<Setter Target="EntranceThemeTransition.FromHorizontalOffset" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.Width}" />
<Setter Target="EntranceThemeTransition.FromVerticalOffset" Value="0" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="FullRightPlacement">
<VisualState.Setters>
<Setter Target="EntranceThemeTransition.FromHorizontalOffset" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.Width}" />
<Setter Target="EntranceThemeTransition.FromVerticalOffset" Value="0" />
<Setter Target="BackgroundElement.Height" Value="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.Height, Mode=TwoWay}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ThemeStates">
<VisualState x:Name="DefaultTheme" />
<VisualState x:Name="ColorPrevalenceTheme">
<VisualState.Setters>
<Setter Target="BackgroundElement.Background" Value="{ThemeResource NotificationFlyoutPresenterBackgroundAccentBrush}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
@@ -1,9 +0,0 @@
using System;
namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
{
public sealed class NotificationFlyoutClosingEventArgs : EventArgs
{
public bool Cancel { get; set; }
}
}
@@ -1,25 +0,0 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Markup;
namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
{
[ContentProperty(Name = "MenuItems")]
public class NotificationFlyoutContextMenu : DependencyObject
{
public static DependencyProperty MenuItemsProperty =
DependencyProperty.Register(nameof(MenuItems),
typeof(IList<MenuFlyoutItemBase>), typeof(NotificationFlyout),
new PropertyMetadata(null));
public NotificationFlyoutContextMenu() => MenuItems = new ObservableCollection<MenuFlyoutItemBase>();
public IList<MenuFlyoutItemBase> MenuItems
{
get => (IList<MenuFlyoutItemBase>)GetValue(MenuItemsProperty);
set => SetValue(MenuItemsProperty, value);
}
}
}
@@ -0,0 +1,10 @@
using Windows.UI.Xaml.Controls.Primitives;
namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
{
public enum NotificationFlyoutPlacement
{
Auto,
FullRight
}
}
@@ -0,0 +1,10 @@
namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
{
internal enum NotificationFlyoutTaskbarPlacement
{
Left,
Top,
Right,
Bottom,
}
}
@@ -0,0 +1,50 @@
using Windows.UI.Xaml;
namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
{
public class NotificationFlyoutTemplateSettings : DependencyObject
{
public static readonly DependencyProperty HeightProperty =
DependencyProperty.Register(nameof(Height),
typeof(double), typeof(NotificationFlyoutTemplateSettings),
new PropertyMetadata(0d));
public static readonly DependencyProperty NegativeHeightProperty =
DependencyProperty.Register(nameof(NegativeHeight),
typeof(double), typeof(NotificationFlyoutTemplateSettings),
new PropertyMetadata(0d));
public static readonly DependencyProperty NegativeWidthProperty =
DependencyProperty.Register(nameof(NegativeWidth),
typeof(double), typeof(NotificationFlyoutTemplateSettings),
new PropertyMetadata(0d));
public static readonly DependencyProperty WidthProperty =
DependencyProperty.Register(nameof(Width),
typeof(double), typeof(NotificationFlyoutTemplateSettings),
new PropertyMetadata(0d));
public double Height
{
get => (double)GetValue(HeightProperty);
set => SetValue(HeightProperty, value);
}
public double NegativeHeight
{
get => (double)GetValue(NegativeHeightProperty);
set => SetValue(NegativeHeightProperty, value);
}
public double NegativeWidth
{
get => (double)GetValue(NegativeWidthProperty);
set => SetValue(NegativeWidthProperty, value);
}
public double Width
{
get => (double)GetValue(WidthProperty);
set => SetValue(WidthProperty, value);
}
}
}
@@ -1,100 +0,0 @@
using System.Collections.Specialized;
using System.Linq;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
{
internal class NotificationFlyoutContextMenuFlyoutHost : Control
{
private NotificationFlyout _flyout;
private MenuFlyout _menuFlyout;
private Grid _root;
public NotificationFlyoutContextMenuFlyoutHost() => DefaultStyleKey = typeof(NotificationFlyoutContextMenuFlyoutHost);
public void HideFlyout()
{
if (_menuFlyout == null) return;
_menuFlyout.Hide();
}
public void ShowFlyout()
{
if (_root == null) return;
if (_menuFlyout == null) return;
_menuFlyout.ShowAt(_root, new FlyoutShowOptions
{
Placement = FlyoutPlacementMode.BottomEdgeAlignedLeft,
ShowMode = FlyoutShowMode.TransientWithDismissOnPointerMoveAway
});
}
internal void SetOwningFlyout(NotificationFlyout flyout)
{
if (_flyout != null)
{
(_flyout.ContextMenu.MenuItems as INotifyCollectionChanged).CollectionChanged -= OnContextMenuItemsChanged;
}
_flyout = flyout;
var contextMenu = _flyout.ContextMenu;
if (contextMenu == null) return;
(contextMenu.MenuItems as INotifyCollectionChanged).CollectionChanged += OnContextMenuItemsChanged;
PrepareMenuItems();
}
protected override void OnApplyTemplate()
{
_root = GetTemplateChild("Root") as Grid;
_menuFlyout = GetTemplateChild("Flyout") as MenuFlyout;
PrepareMenuItems();
}
private void OnContextMenuItemsChanged(object sender, NotifyCollectionChangedEventArgs args)
{
if (_flyout == null) return;
var contextMenu = _flyout.ContextMenu;
if (contextMenu == null) return;
var addedItems = args.NewItems.Cast<MenuFlyoutItemBase>().ToList();
var removedItems = args.NewItems.Cast<MenuFlyoutItemBase>().ToList();
if (removedItems != null)
{
foreach (var item in removedItems)
{
_menuFlyout.Items.Remove(item);
}
}
foreach (var item in addedItems)
{
_menuFlyout.Items.Add(item);
}
}
private void PrepareMenuItems()
{
if (_menuFlyout == null) return;
if (_flyout == null) return;
var contextMenu = _flyout.ContextMenu;
if (contextMenu == null) return;
_menuFlyout.Items.Clear();
var items = contextMenu.MenuItems;
foreach (var item in items)
{
_menuFlyout.Items.Add(item);
}
}
}
}
@@ -1,18 +0,0 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:TheXamlGuy.NotificationFlyout.Uwp.UI.Controls">
<Style TargetType="controls:NotificationFlyoutContextMenuFlyoutHost">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:NotificationFlyoutContextMenuFlyoutHost">
<Grid x:Name="Root">
<FlyoutBase.AttachedFlyout>
<MenuFlyout x:Name="Flyout" />
</FlyoutBase.AttachedFlyout>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
@@ -1,134 +0,0 @@
using System.Numerics;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;
namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
{
internal class NotificationFlyoutHost : Control
{
public static readonly DependencyProperty ContentProperty =
DependencyProperty.Register(nameof(Content),
typeof(UIElement), typeof(NotificationFlyoutHost),
new PropertyMetadata(null));
public static readonly DependencyProperty FlyoutPresenterStyleProperty =
DependencyProperty.Register(nameof(FlyoutPresenterStyle),
typeof(Style), typeof(NotificationFlyoutHost),
new PropertyMetadata(null));
private Flyout _flyout;
private NotificationFlyout _notificationFlyout;
private NotificationFlyoutPresenter _notificationFlyoutPresenter;
private Grid _root;
public NotificationFlyoutHost() => DefaultStyleKey = typeof(NotificationFlyoutHost);
public UIElement Content
{
get => (UIElement)GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
public Style FlyoutPresenterStyle
{
get => (Style)GetValue(FlyoutPresenterStyleProperty);
set => SetValue(FlyoutPresenterStyleProperty, value);
}
public void HideFlyout()
{
if (_root == null) return;
FlyoutBase flyout = FlyoutBase.GetAttachedFlyout(_root);
flyout.Hide();
}
public void SetFlyoutPlacement(string placement)
{
if (_notificationFlyoutPresenter == null) return;
_notificationFlyoutPresenter.UpdatePlacementVisualState(placement);
}
public void SetOwningFlyout(NotificationFlyout flyout)
{
_notificationFlyout = flyout;
BindingOperations.SetBinding(this, ContentProperty,
new Binding
{
Source = _notificationFlyout,
Path =
new PropertyPath(nameof(Content)),
Mode = BindingMode.TwoWay
});
BindingOperations.SetBinding(this, RequestedThemeProperty,
new Binding
{
Source = _notificationFlyout,
Path = new PropertyPath(nameof(RequestedTheme)),
Mode = BindingMode.TwoWay
});
BindingOperations.SetBinding(this, FlyoutPresenterStyleProperty,
new Binding
{
Source = _notificationFlyout,
Path = new PropertyPath(nameof(FlyoutPresenterStyle)),
Mode = BindingMode.TwoWay
});
}
public void ShowFlyout(FlyoutPlacementMode placementMode)
{
if (_root == null) return;
var flyout = FlyoutBase.GetAttachedFlyout(_root);
flyout.ShowAt(_root, new FlyoutShowOptions
{
Placement = placementMode,
ShowMode = FlyoutShowMode.Transient,
});
}
public void UpdateTheme(bool isColorPrevalence)
{
if (_notificationFlyoutPresenter == null) return;
_notificationFlyoutPresenter.UpdateThemeVisualState(isColorPrevalence);
}
protected override void OnApplyTemplate()
{
_notificationFlyoutPresenter = GetTemplateChild("NotificationFlyoutPresenter") as NotificationFlyoutPresenter;
if (_notificationFlyoutPresenter != null)
{
_notificationFlyoutPresenter.ApplyTemplate();
}
_flyout = GetTemplateChild("Flyout") as Flyout;
if (_flyout != null)
{
_flyout.Closing -= OnFlyoutClosing;
_flyout.Closed -= OnFlyoutClosed;
_flyout.Opening -= OnFlyoutOpening;
_flyout.Opened -= OnFlyoutOpened;
_flyout.Closing += OnFlyoutClosing;
_flyout.Closed += OnFlyoutClosed;
_flyout.Opening += OnFlyoutOpening;
_flyout.Opened += OnFlyoutOpened;
}
_root = GetTemplateChild("Root") as Grid;
}
private void OnFlyoutClosed(object sender, object args) => _notificationFlyout?.InvokeClosedEvent(args);
private void OnFlyoutClosing(FlyoutBase sender, FlyoutBaseClosingEventArgs args) => _notificationFlyout?.InvokeClosingEvent(new NotificationFlyoutClosingEventArgs());
private void OnFlyoutOpened(object sender, object args) => _notificationFlyout?.InvokeOpenedEvent(args);
private void OnFlyoutOpening(object sender, object args) => _notificationFlyout?.InvokeOpeningEvent(args);
}
}
@@ -1,100 +0,0 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:TheXamlGuy.NotificationFlyout.Uwp.UI.Controls">
<Style TargetType="controls:NotificationFlyoutHost">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:NotificationFlyoutHost">
<Grid x:Name="Root">
<Grid.Resources>
<Style x:Key="DefaultFlyoutPresenterStyle" TargetType="FlyoutPresenter">
<Setter Property="IsDefaultShadowEnabled" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="FlyoutPresenter">
<ContentPresenter
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="TopFlyoutPresenterStyle"
BasedOn="{StaticResource DefaultFlyoutPresenterStyle}"
TargetType="FlyoutPresenter">
<Setter Property="Margin" Value="0,-7,0,0" />
</Style>
<Style
x:Key="BottomFlyoutPresenterStyle"
BasedOn="{StaticResource DefaultFlyoutPresenterStyle}"
TargetType="FlyoutPresenter">
<Setter Property="Margin" Value="0,7,0,0" />
</Style>
<Style
x:Key="LeftFlyoutPresenterStyle"
BasedOn="{StaticResource DefaultFlyoutPresenterStyle}"
TargetType="FlyoutPresenter">
<Setter Property="Margin" Value="-7,0,0,0" />
</Style>
<Style
x:Key="RightFlyoutPresenterStyle"
BasedOn="{StaticResource DefaultFlyoutPresenterStyle}"
TargetType="FlyoutPresenter">
<Setter Property="Margin" Value="7,0,0,0" />
</Style>
</Grid.Resources>
<FlyoutBase.AttachedFlyout>
<Flyout
x:Name="Flyout"
AreOpenCloseAnimationsEnabled="False"
FlyoutPresenterStyle="{StaticResource BottomFlyoutPresenterStyle}"
ShouldConstrainToRootBounds="False">
<controls:NotificationFlyoutPresenter
x:Name="NotificationFlyoutPresenter"
Content="{TemplateBinding Content}"
Style="{TemplateBinding FlyoutPresenterStyle}" />
</Flyout>
</FlyoutBase.AttachedFlyout>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="PlacementStates">
<VisualState x:Name="Bottom">
<VisualState.Setters>
<Setter Target="Flyout.FlyoutPresenterStyle" Value="{StaticResource BottomFlyoutPresenterStyle}" />
<!--<Setter Target="EntranceThemeTransition.FromHorizontalOffset" Value="0" />
<Setter Target="EntranceThemeTransition.FromVerticalOffset" Value="80" />-->
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Top">
<VisualState.Setters>
<Setter Target="Flyout.FlyoutPresenterStyle" Value="{StaticResource TopFlyoutPresenterStyle}" />
<!--<Setter Target="EntranceThemeTransition.FromHorizontalOffset" Value="0" />
<Setter Target="EntranceThemeTransition.FromVerticalOffset" Value="-80" />-->
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Left">
<VisualState.Setters>
<Setter Target="Flyout.FlyoutPresenterStyle" Value="{StaticResource LeftFlyoutPresenterStyle}" />
<!--<Setter Target="EntranceThemeTransition.FromHorizontalOffset" Value="-80" />
<Setter Target="EntranceThemeTransition.FromVerticalOffset" Value="0" />-->
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Right">
<VisualState.Setters>
<Setter Target="Flyout.FlyoutPresenterStyle" Value="{StaticResource RightFlyoutPresenterStyle}" />
<!--<Setter Target="EntranceThemeTransition.FromHorizontalOffset" Value="80" />
<Setter Target="EntranceThemeTransition.FromVerticalOffset" Value="0" />-->
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
@@ -1,28 +0,0 @@
using System.Numerics;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
{
public class NotificationFlyoutPresenter : ContentControl
{
public NotificationFlyoutPresenter() => DefaultStyleKey = typeof(NotificationFlyoutPresenter);
protected override void OnApplyTemplate()
{
if (GetTemplateChild("Root") is Grid contentRoot)
{
contentRoot.Shadow = new ThemeShadow();
var currentTranslation = contentRoot.Translation;
var translation = new Vector3(currentTranslation.X, currentTranslation.Y, 16.0f);
contentRoot.Translation = translation;
}
}
internal void UpdatePlacementVisualState(string placement) => VisualStateManager.GoToState(this, placement, true);
internal void UpdateThemeVisualState(bool isColorPrevalence) => VisualStateManager.GoToState(this, isColorPrevalence ? "ColorPrevalenceTheme" : "DefaultTheme", true);
}
}
@@ -1,112 +0,0 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:TheXamlGuy.NotificationFlyout.Uwp.UI.Controls">
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<AcrylicBrush
x:Key="AcrylicBackgroundFillColorBrush"
BackgroundSource="HostBackdrop"
FallbackColor="#2C2C2C"
TintColor="#2C2C2C"
TintOpacity="0.8" />
<StaticResource x:Key="NotificationFlyoutPresenterBackgroundBrush" ResourceKey="AcrylicBackgroundFillColorBrush" />
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<AcrylicBrush
x:Key="AcrylicBackgroundFillColorBrush"
BackgroundSource="HostBackdrop"
FallbackColor="#F9F9F9"
TintColor="#FCFCFC"
TintOpacity="0.8" />
<StaticResource x:Key="NotificationFlyoutPresenterBackgroundBrush" ResourceKey="AcrylicBackgroundFillColorBrush" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<AcrylicBrush
x:Key="NotificationFlyoutPresenterBackgroundAccentBrush"
BackgroundSource="HostBackdrop"
FallbackColor="{ThemeResource SystemAccentColorDark1}"
TintColor="{ThemeResource SystemAccentColorDark1}"
TintOpacity="0.8" />
<Style TargetType="controls:NotificationFlyoutPresenter">
<Setter Property="Background" Value="{ThemeResource NotificationFlyoutPresenterBackgroundBrush}" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:NotificationFlyoutPresenter">
<Grid
x:Name="Root"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BackgroundSizing="OuterBorderEdge"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Grid.Transitions>
<TransitionCollection>
<EntranceThemeTransition
x:Name="EntranceThemeTransition"
FromHorizontalOffset="0"
FromVerticalOffset="0" />
</TransitionCollection>
</Grid.Transitions>
<ScrollViewer
x:Name="ScrollViewer"
AutomationProperties.AccessibilityView="Raw"
HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}">
<ContentControl
x:Name="ContentPresenter"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}" />
</ScrollViewer>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="PlacementStates">
<VisualState x:Name="Bottom">
<VisualState.Setters>
<Setter Target="EntranceThemeTransition.FromHorizontalOffset" Value="0" />
<Setter Target="EntranceThemeTransition.FromVerticalOffset" Value="80" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Top">
<VisualState.Setters>
<Setter Target="EntranceThemeTransition.FromHorizontalOffset" Value="0" />
<Setter Target="EntranceThemeTransition.FromVerticalOffset" Value="-80" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Left">
<VisualState.Setters>
<Setter Target="EntranceThemeTransition.FromHorizontalOffset" Value="-80" />
<Setter Target="EntranceThemeTransition.FromVerticalOffset" Value="0" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Right">
<VisualState.Setters>
<Setter Target="EntranceThemeTransition.FromHorizontalOffset" Value="80" />
<Setter Target="EntranceThemeTransition.FromVerticalOffset" Value="0" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup x:Name="ThemeStates">
<VisualState x:Name="DefaultTheme" />
<VisualState x:Name="ColorPrevalenceTheme">
<VisualState.Setters>
<Setter Target="Root.Background" Value="{ThemeResource NotificationFlyoutPresenterBackgroundAccentBrush}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
@@ -14,15 +14,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Page Include="NotificationFlyoutHost\NotificationFlyoutContextMenuFlyoutHost.xaml"> <Page Include="NotificationFlyout\NotificationFlyout.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="NotificationFlyoutHost\NotificationFlyoutHost.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="NotificationFlyoutPresenter\NotificationFlyoutPresenter.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
@@ -1,7 +1,5 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///TheXamlGuy.NotificationFlyout.Uwp.UI.Controls/NotificationFlyoutHost/NotificationFlyoutHost.xaml" /> <ResourceDictionary Source="ms-appx:///TheXamlGuy.NotificationFlyout.Uwp.UI.Controls/NotificationFlyout/NotificationFlyout.xaml" />
<ResourceDictionary Source="ms-appx:///TheXamlGuy.NotificationFlyout.Uwp.UI.Controls/NotificationFlyoutPresenter/NotificationFlyoutPresenter.xaml" />
<ResourceDictionary Source="ms-appx:///TheXamlGuy.NotificationFlyout.Uwp.UI.Controls/NotificationFlyoutHost/NotificationFlyoutContextMenuFlyoutHost.xaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>
@@ -1,7 +1,19 @@
using TheXamlGuy.NotificationFlyout.Common.Helpers; using TheXamlGuy.NotificationFlyout.Common.Helpers;
using System.Windows; using System.Windows;
using System.Windows.Markup; using System.Windows.Markup;
using System;
using Windows.UI.Xaml.Controls;
using TheXamlGuy.NotificationFlyout.Uwp.UI.Controls;
using TheXamlGuy.NotificationFlyout.Wpf.UI.Extensions;
using System.Windows.Media.Imaging;
using TheXamlGuy.NotificationFlyout.Common.Extensions;
using Microsoft.Windows.Sdk;
using TheXamlGuy.NotificationFlyout.Shared.UI; using TheXamlGuy.NotificationFlyout.Shared.UI;
using System.Windows.Media;
using System.Threading.Tasks;
using Microsoft.Win32;
using System.Windows.Threading;
using System.Threading;
namespace TheXamlGuy.NotificationFlyout.Wpf.UI.Controls namespace TheXamlGuy.NotificationFlyout.Wpf.UI.Controls
{ {
@@ -13,19 +25,29 @@ namespace TheXamlGuy.NotificationFlyout.Wpf.UI.Controls
typeof(Uwp.UI.Controls.NotificationFlyout), typeof(NotificationFlyoutApplication), typeof(Uwp.UI.Controls.NotificationFlyout), typeof(NotificationFlyoutApplication),
new PropertyMetadata(null, OnFlyoutPropertyChanged)); new PropertyMetadata(null, OnFlyoutPropertyChanged));
private static NotificationFlyoutApplication _application; private const string ShellTrayHandleName = "Shell_TrayWnd";
private NotificationFlyoutXamlHost _notificationFlyoutXamlHost; private readonly NotificationIconHelper _notificationIconHelper;
private readonly SystemPersonalisationHelper _systemPersonalisationHelper;
private readonly TaskbarHelper _taskbarHelper;
private bool _isDpiChanging;
private TransparentXamlHost<ContentControl> _notificationFlyoutXamlHost;
public NotificationFlyoutApplication() public NotificationFlyoutApplication()
{ {
_application = this;
Uwp.UI.Controls.NotificationFlyout.SetApplication(this); Uwp.UI.Controls.NotificationFlyout.SetApplication(this);
WndProcListener.Current.Start(); _notificationIconHelper = NotificationIconHelper.Create();
PrepareFlyoutHost(); _notificationIconHelper.IconInvoked += OnIconInvoked;
}
public static INotificationFlyoutApplication Current => _application; _taskbarHelper = TaskbarHelper.Create();
_taskbarHelper.TaskbarChanged += OnTaskbarChanged;
_systemPersonalisationHelper = SystemPersonalisationHelper.Current;
_systemPersonalisationHelper.ThemeChanged += OnThemeChanged;
PrepareFlyoutHost();
WndProcListener.Current.Start();
}
public Uwp.UI.Controls.NotificationFlyout Flyout public Uwp.UI.Controls.NotificationFlyout Flyout
{ {
@@ -33,17 +55,31 @@ namespace TheXamlGuy.NotificationFlyout.Wpf.UI.Controls
set => SetValue(FlyoutProperty, value); set => SetValue(FlyoutProperty, value);
} }
public void Exit() => _notificationFlyoutXamlHost.Close(); public void CloseFlyout(bool shouldRespectIsLightDismissEnbabled)
{
if (Flyout == null) return;
Flyout.Close(shouldRespectIsLightDismissEnbabled);
}
public void HideFlyout() => _notificationFlyoutXamlHost.HideFlyout(); public void CloseFlyout() => CloseFlyout(false);
public void Exit() => _notificationFlyoutXamlHost.Close();
public void OpenAsWindow<TUIElement>() where TUIElement : Windows.UI.Xaml.UIElement public void OpenAsWindow<TUIElement>() where TUIElement : Windows.UI.Xaml.UIElement
{ {
var window = new XamlHost<TUIElement>(); var window = new XamlHost<TUIElement>();
window.Hidden();
window.Show(); window.Show();
} }
public void ShowFlyout() => _notificationFlyoutXamlHost.ShowFlyout(); public void OpenFlyout()
{
if (Flyout == null) return;
_notificationFlyoutXamlHost.Activate();
Flyout.Open();
UpdateFlyoutPlacement();
}
private static void OnFlyoutPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) private static void OnFlyoutPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{ {
@@ -51,12 +87,188 @@ namespace TheXamlGuy.NotificationFlyout.Wpf.UI.Controls
sender?.OnFlyoutPropertyChanged(); sender?.OnFlyoutPropertyChanged();
} }
private void OnFlyoutPropertyChanged() => _notificationFlyoutXamlHost.SetOwningFlyout(Flyout); private void OnFlyoutIconSourcePropertyChanged(object sender, EventArgs args) => UpdateIcons();
private void OnFlyoutInteractedWith(object sender, EventArgs args) => _notificationFlyoutXamlHost.Activate();
private void OnFlyoutPlacementPropertyChanged(object sender, EventArgs args) => UpdateFlyoutPlacement();
private void OnFlyoutPropertyChanged() => PrepareFlyout();
private void OnIconInvoked(object sender, NotificationIconInvokedEventArgs args)
{
if (args.PointerButton == PointerButton.Left)
{
OpenFlyout();
}
if (args.PointerButton == PointerButton.Right)
{
ShowContextMenu();
}
}
private void OnNotificationFlyoutXamlHostClosed(object sender, EventArgs args) => _notificationIconHelper?.Dispose();
private void OnNotificationFlyoutXamlHostDeactivated(object sender, EventArgs args) => CloseFlyout(true);
private async void OnNotificationFlyoutXamlHostDpiChanged(object sender, DpiChangedEventArgs args)
{
if (_isDpiChanging)
return;
_isDpiChanging = true;
await Application.Current.Dispatcher.Invoke(async () =>
{
_notificationFlyoutXamlHost.Visibility = Visibility.Visible;
await Dispatcher.BeginInvoke(new Action(() =>
{
VisualTreeHelper.SetRootDpi(_notificationFlyoutXamlHost, args.OldDpi);
}), DispatcherPriority.ContextIdle, null);
await Dispatcher.BeginInvoke(new Action(() =>
{
VisualTreeHelper.SetRootDpi(_notificationFlyoutXamlHost, args.NewDpi);
}), DispatcherPriority.ContextIdle, null);
await Dispatcher.BeginInvoke(new Action(() =>
{
_notificationFlyoutXamlHost.Visibility = Visibility.Hidden;
_isDpiChanging = false;
}), DispatcherPriority.ContextIdle, null);
});
UpdateIcons();
}
private void OnTaskbarChanged(object sender, EventArgs args) => UpdateFlyoutPlacement();
private void OnThemeChanged(object sender, SystemPersonalisationChangedEventArgs args)
{
UpdateIcons();
UpdateTheme();
}
private void PrepareFlyout()
{
if (Flyout == null) return;
Flyout.IconSourcePropertyChanged += OnFlyoutIconSourcePropertyChanged;
Flyout.PlacementPropertyChanged += OnFlyoutPlacementPropertyChanged;
Flyout.InteractedWith += OnFlyoutInteractedWith;
var content = _notificationFlyoutXamlHost.GetHostContent();
if (content != null)
{
content.Content = Flyout;
}
UpdateIcons();
}
private void PrepareFlyoutHost() private void PrepareFlyoutHost()
{ {
_notificationFlyoutXamlHost = new NotificationFlyoutXamlHost(); _notificationFlyoutXamlHost = new TransparentXamlHost<ContentControl>();
_notificationFlyoutXamlHost.DpiChanged += OnNotificationFlyoutXamlHostDpiChanged;
_notificationFlyoutXamlHost.Closed += OnNotificationFlyoutXamlHostClosed;
_notificationFlyoutXamlHost.Deactivated += OnNotificationFlyoutXamlHostDeactivated;
var taskbarState = _taskbarHelper.GetCurrentState();
_notificationFlyoutXamlHost.Left = taskbarState.Screen.WorkingArea.Left;
_notificationFlyoutXamlHost.Top = taskbarState.Screen.WorkingArea.Top;
_notificationFlyoutXamlHost.Show(); _notificationFlyoutXamlHost.Show();
} }
private void ShowContextMenu()
{
var dpiX = _notificationFlyoutXamlHost.DpiX();
var dpiY = _notificationFlyoutXamlHost.DpiY();
PInvoke.GetPhysicalCursorPos(out POINT point);
Flyout.ShowContextMenuAt(point.x / dpiX, point.y / dpiY);
}
private void UpdateFlyoutPlacement()
{
if (Flyout == null) return;
var dpiX = _notificationFlyoutXamlHost.DpiX();
var dpiY = _notificationFlyoutXamlHost.DpiY();
var taskbarState = _taskbarHelper.GetCurrentState();
_notificationFlyoutXamlHost.Left = taskbarState.Screen.Bounds.Left / dpiX; ;
_notificationFlyoutXamlHost.Top = 0;
double horizontalOffset;
double verticalOffset;
var workingAreaHeight = taskbarState.Screen.WorkingArea.Height / dpiX;
var workingAreaWidth = taskbarState.Screen.WorkingArea.Width / dpiY;
NotificationFlyoutTaskbarPlacement flyoutTaskBarPlacement;
switch (taskbarState.Placement)
{
case TaskbarPlacement.Left:
flyoutTaskBarPlacement = NotificationFlyoutTaskbarPlacement.Left;
verticalOffset = taskbarState.Screen.WorkingArea.Height / dpiX;
horizontalOffset = taskbarState.Rect.Width / dpiY;
break;
case TaskbarPlacement.Top:
flyoutTaskBarPlacement = NotificationFlyoutTaskbarPlacement.Top;
verticalOffset = taskbarState.Rect.Height / dpiX;
horizontalOffset = (_notificationFlyoutXamlHost.FlowDirection == FlowDirection.RightToLeft ? 0 : taskbarState.Screen.WorkingArea.Width) / dpiY;
break;
case TaskbarPlacement.Right:
flyoutTaskBarPlacement = NotificationFlyoutTaskbarPlacement.Right;
verticalOffset = taskbarState.Screen.WorkingArea.Height / dpiX;
horizontalOffset = taskbarState.Screen.WorkingArea.Width / dpiY;
break;
case TaskbarPlacement.Bottom:
flyoutTaskBarPlacement = NotificationFlyoutTaskbarPlacement.Bottom;
verticalOffset = taskbarState.Screen.WorkingArea.Height / dpiX;
horizontalOffset = (_notificationFlyoutXamlHost.FlowDirection == FlowDirection.RightToLeft ? 0 : taskbarState.Screen.WorkingArea.Width) / dpiY;
break;
default:
throw new ArgumentOutOfRangeException();
}
Flyout.SetPlacement(horizontalOffset, verticalOffset, workingAreaHeight, workingAreaWidth, flyoutTaskBarPlacement);
}
private async void UpdateIcons()
{
if (Flyout == null) return;
var shellTrayHandle = WindowHelper.GetHandle(ShellTrayHandleName);
if (shellTrayHandle == null) return;
var dpi = WindowHelper.GetDpi(shellTrayHandle);
var desiredIconSource = _systemPersonalisationHelper.Theme == SystemTheme.Dark ? Flyout.IconSource : Flyout.LightIconSource;
if (desiredIconSource == null)
{
var fallbackIconSource = new BitmapImage(new Uri($"pack://application:,,,/{GetType().Namespace};component/Assets/notification-icon-{(_systemPersonalisationHelper.Theme == SystemTheme.Dark ? "default" : "light")}.ico"));
using var icon = fallbackIconSource.ConvertToIcon(dpi);
_notificationIconHelper.SetIcon(icon.Handle);
}
else
{
using var icon = await desiredIconSource.ConvertToIconAsync(dpi);
_notificationIconHelper.SetIcon(icon.Handle);
}
}
private void UpdateTheme()
{
if (Flyout == null) return;
Flyout.UpdateTheme(_systemPersonalisationHelper.IsColorPrevalence);
}
} }
} }
@@ -1,44 +0,0 @@
using TheXamlGuy.NotificationFlyout.Uwp.UI.Controls;
using TheXamlGuy.NotificationFlyout.Common.Helpers;
using TheXamlGuy.NotificationFlyout.Wpf.UI.Extensions;
using System;
namespace TheXamlGuy.NotificationFlyout.Wpf.UI.Controls
{
internal class NotificationFlyoutContextMenuXamlHost : TransparentXamlHost<NotificationFlyoutContextMenuFlyoutHost>
{
public NotificationFlyoutContextMenuXamlHost() => Topmost = true;
internal void SetOwningFlyout(Uwp.UI.Controls.NotificationFlyout flyout)
{
var content = GetHostContent();
if (content != null)
{
content.SetOwningFlyout(flyout);
}
}
internal void ShowContextMenuFlyout()
{
var position = CursorHelper.GetPhysicalCursorPos();
this.SetWindowPosition(position.y, position.x, WindowSize, WindowSize);
var flyoutHost = GetHostContent();
if (flyoutHost != null)
{
flyoutHost.ShowFlyout();
}
Activate();
}
protected override void OnDeactivated(EventArgs args)
{
var flyoutHost = GetHostContent();
if (flyoutHost != null)
{
flyoutHost.HideFlyout();
}
}
}
}
@@ -1,248 +0,0 @@
using TheXamlGuy.NotificationFlyout.Common.Extensions;
using TheXamlGuy.NotificationFlyout.Common.Helpers;
using TheXamlGuy.NotificationFlyout.Uwp.UI.Controls;
using TheXamlGuy.NotificationFlyout.Wpf.UI.Extensions;
using System;
using System.Windows;
using Windows.UI.Xaml.Controls.Primitives;
using System.Windows.Media.Imaging;
namespace TheXamlGuy.NotificationFlyout.Wpf.UI.Controls
{
internal class NotificationFlyoutXamlHost : TransparentXamlHost<NotificationFlyoutHost>
{
private const string ShellTrayHandleName = "Shell_TrayWnd";
private NotificationFlyoutContextMenuXamlHost _contextMenuXamlHost;
private Uwp.UI.Controls.NotificationFlyout _flyout;
private NotificationIconHelper _notificationIconHelper;
private SystemPersonalisationHelper _systemPersonalisationHelper;
private TaskbarHelper _taskbarHelper;
internal void HideFlyout()
{
var flyoutHost = GetHostContent();
if (flyoutHost != null)
{
flyoutHost.HideFlyout();
}
}
internal void SetOwningFlyout(Uwp.UI.Controls.NotificationFlyout flyout)
{
if (_flyout != null)
{
_flyout.IconSourceChanged -= OnIconSourceChanged;
_flyout.ContextMenuChanged -= OnContextMenuChanged;
}
_flyout = flyout;
_flyout.IconSourceChanged += OnIconSourceChanged;
_flyout.ContextMenuChanged += OnContextMenuChanged;
var content = GetHostContent();
if (content != null)
{
content.SetOwningFlyout(_flyout);
}
UpdateIcons();
PrepareContextMenu();
}
internal void ShowFlyout()
{
var content = GetHostContent();
if (content != null)
{
var taskbarState = _taskbarHelper.GetCurrentState();
var flyoutPlacement = taskbarState.Position switch
{
TaskbarPosition.Left => FlyoutPlacementMode.Right,
TaskbarPosition.Top => FlyoutPlacementMode.Bottom,
TaskbarPosition.Right => FlyoutPlacementMode.Left,
TaskbarPosition.Bottom => FlyoutPlacementMode.Top,
_ => throw new ArgumentOutOfRangeException(),
};
Activate();
content.ShowFlyout(flyoutPlacement);
}
}
protected override void OnClosed(EventArgs args)
{
_notificationIconHelper.Dispose();
if (_contextMenuXamlHost == null) return;
_contextMenuXamlHost.Close();
}
protected override void OnContentLoaded()
{
PrepareNotificationIcon();
PrepareTaskbar();
UpdateWindow();
UpdateTheme();
}
protected override void OnDeactivated(EventArgs args) => HideFlyout();
private void OnContextMenuChanged(object sender, EventArgs args) => PrepareContextMenu();
private void OnIconInvoked(object sender, NotificationIconInvokedEventArgs args)
{
if (args.PointerButton == PointerButton.Left)
{
ShowFlyout();
}
if (args.PointerButton == PointerButton.Right)
{
ShowContextMenuFlyout();
}
}
private void OnIconSourceChanged(object sender, EventArgs args) => UpdateIcons();
private void OnTaskbarChanged(object sender, EventArgs args) => UpdateWindow();
private void OnThemeChanged(object sender, SystemPersonalisationChangedEventArgs args)
{
UpdateTheme();
UpdateIcons();
}
private void PrepareContextMenu()
{
if (_contextMenuXamlHost != null)
{
_contextMenuXamlHost.Close();
_contextMenuXamlHost = null;
}
var contextMenu = _flyout.ContextMenu;
if (contextMenu == null) return;
if (_contextMenuXamlHost == null)
{
_contextMenuXamlHost = new NotificationFlyoutContextMenuXamlHost();
_contextMenuXamlHost.Show();
}
_contextMenuXamlHost.SetOwningFlyout(_flyout);
}
private void PrepareNotificationIcon()
{
_notificationIconHelper = NotificationIconHelper.Create();
_notificationIconHelper.IconInvoked += OnIconInvoked;
_systemPersonalisationHelper = SystemPersonalisationHelper.Current;
_systemPersonalisationHelper.ThemeChanged += OnThemeChanged;
UpdateIcons();
}
private void PrepareTaskbar()
{
_taskbarHelper = TaskbarHelper.Create();
_taskbarHelper.TaskbarChanged += OnTaskbarChanged;
}
private void ShowContextMenuFlyout()
{
if (_contextMenuXamlHost == null) return;
_contextMenuXamlHost.ShowContextMenuFlyout();
}
private async void UpdateIcons()
{
if (!IsLoaded) return;
if (_flyout == null) return;
var shellTrayHandle = WindowHelper.GetHandle(ShellTrayHandleName);
if (shellTrayHandle == null) return;
var dpi = WindowHelper.GetDpi(shellTrayHandle);
var desiredIconSource = _systemPersonalisationHelper.Theme == SystemTheme.Dark ? _flyout.IconSource : _flyout.LightIconSource;
if (desiredIconSource == null)
{
var fallbackIconSource = new BitmapImage(new Uri($"pack://application:,,,/{GetType().Namespace};component/Assets/notification-icon-{(_systemPersonalisationHelper.Theme == SystemTheme.Dark ? "default" : "light")}.ico"));
using var icon = fallbackIconSource.ConvertToIcon(dpi);
_notificationIconHelper.SetIcon(icon.Handle);
}
else
{
using var icon = await desiredIconSource.ConvertToIconAsync(dpi);
_notificationIconHelper.SetIcon(icon.Handle);
}
}
private void UpdateTheme()
{
var content = GetHostContent();
if (content != null)
{
content.UpdateTheme(_systemPersonalisationHelper.IsColorPrevalence);
}
}
private void UpdateWindow()
{
if (!IsLoaded) return;
var flyoutHost = GetHostContent();
if (flyoutHost == null) return;
var taskbarState = _taskbarHelper.GetCurrentState();
Left = taskbarState.Screen.WorkingArea.Left;
Top = taskbarState.Screen.WorkingArea.Top;
var windowWidth = WindowSize * this.DpiX();
var windowHeight = WindowSize * this.DpiY();
double top, left, height, width;
var taskbarRect = taskbarState.Rect;
switch (taskbarState.Position)
{
case TaskbarPosition.Left:
top = taskbarRect.Bottom - windowHeight;
left = taskbarRect.Right;
height = windowHeight;
width = windowWidth;
break;
case TaskbarPosition.Top:
top = taskbarRect.Bottom;
left = FlowDirection == FlowDirection.RightToLeft ? taskbarRect.Left : taskbarRect.Right - windowWidth;
height = windowHeight;
width = windowWidth;
break;
case TaskbarPosition.Right:
top = taskbarRect.Bottom - windowHeight;
left = taskbarRect.Left - windowWidth;
height = windowHeight;
width = windowWidth;
break;
case TaskbarPosition.Bottom:
top = taskbarRect.Top - windowHeight;
left = FlowDirection == FlowDirection.RightToLeft ? taskbarRect.Left : taskbarRect.Right - windowWidth;
height = windowHeight;
width = windowWidth;
break;
default:
throw new ArgumentOutOfRangeException();
}
this.SetWindowPosition(top, left, height, width);
flyoutHost.SetFlyoutPlacement(taskbarState.Position.ToString());
}
}
}
@@ -22,6 +22,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\TheXamlGuy.NotificationFlyout.Common\TheXamlGuy.NotificationFlyout.Common.csproj" />
<ProjectReference Include="..\TheXamlGuy.NotificationFlyout.Shared.UI\TheXamlGuy.NotificationFlyout.Shared.UI.csproj" />
<ProjectReference Include="..\TheXamlGuy.NotificationFlyout.Uwp.UI.Controls\TheXamlGuy.NotificationFlyout.Uwp.UI.Controls.csproj" /> <ProjectReference Include="..\TheXamlGuy.NotificationFlyout.Uwp.UI.Controls\TheXamlGuy.NotificationFlyout.Uwp.UI.Controls.csproj" />
<ProjectReference Include="..\TheXamlGuy.NotificationFlyout.Wpf.UI\TheXamlGuy.NotificationFlyout.Wpf.UI.csproj" /> <ProjectReference Include="..\TheXamlGuy.NotificationFlyout.Wpf.UI\TheXamlGuy.NotificationFlyout.Wpf.UI.csproj" />
</ItemGroup> </ItemGroup>
@@ -1,37 +1,33 @@
using Microsoft.Toolkit.Wpf.UI.XamlHost; using Microsoft.Toolkit.Wpf.UI.XamlHost;
using TheXamlGuy.NotificationFlyout.Wpf.UI.Extensions; using System;
using System.Windows; using System.Windows;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Threading;
namespace TheXamlGuy.NotificationFlyout.Wpf.UI.Controls namespace TheXamlGuy.NotificationFlyout.Wpf.UI.Controls
{ {
internal class TransparentXamlHost<TXamlContent> : XamlHost<TXamlContent> where TXamlContent : Windows.UI.Xaml.UIElement internal class TransparentXamlHost<TXamlContent> : XamlHost<TXamlContent> where TXamlContent : Windows.UI.Xaml.UIElement
{ {
internal const double WindowSize = 5; internal const double WindowSize = 10;
public TransparentXamlHost() public TransparentXamlHost() => PrepareDefaultWindow();
{
Loaded += OnLoaded;
PrepareDefaultWindow();
}
protected override WindowsXamlHost OnPreparingXamlHost(WindowsXamlHost xamlHost) protected override WindowsXamlHost OnPreparingXamlHost(WindowsXamlHost xamlHost)
{ {
xamlHost.Height = 0; xamlHost.Height = 0;
xamlHost.Width = 0; xamlHost.Width = 0;
return base.OnPreparingXamlHost(xamlHost); Dispatcher.BeginInvoke(new Action(() =>
}
private void OnLoaded(object sender, RoutedEventArgs args)
{ {
this.Hidden(); Hide();
}), DispatcherPriority.ContextIdle, null);
return base.OnPreparingXamlHost(xamlHost);
} }
private void PrepareDefaultWindow() private void PrepareDefaultWindow()
{ {
ShowInTaskbar = false; ShowInTaskbar = false;
ShowActivated = false;
WindowStyle = WindowStyle.None; WindowStyle = WindowStyle.None;
ResizeMode = ResizeMode.NoResize; ResizeMode = ResizeMode.NoResize;
AllowsTransparency = true; AllowsTransparency = true;
@@ -6,13 +6,11 @@ namespace TheXamlGuy.NotificationFlyout.Wpf.UI.Controls
{ {
internal class XamlHost<TXamlContent> : Window where TXamlContent : Windows.UI.Xaml.UIElement internal class XamlHost<TXamlContent> : Window where TXamlContent : Windows.UI.Xaml.UIElement
{ {
protected new bool IsLoaded;
private WindowsXamlHost _xamlHost; private WindowsXamlHost _xamlHost;
public XamlHost() public XamlHost()
{ {
PrepareWindowsXamlHost(); PrepareWindowsXamlHost();
ContentRendered += OnContentRendered;
} }
internal TXamlContent GetHostContent() internal TXamlContent GetHostContent()
@@ -21,11 +19,6 @@ namespace TheXamlGuy.NotificationFlyout.Wpf.UI.Controls
return _xamlHost.GetUwpInternalObject() as TXamlContent; return _xamlHost.GetUwpInternalObject() as TXamlContent;
} }
protected virtual void OnContentLoaded()
{
}
protected virtual WindowsXamlHost OnPreparingXamlHost(WindowsXamlHost xamlHost) protected virtual WindowsXamlHost OnPreparingXamlHost(WindowsXamlHost xamlHost)
{ {
xamlHost.InitialTypeName = typeof(TXamlContent).FullName; xamlHost.InitialTypeName = typeof(TXamlContent).FullName;
@@ -35,12 +28,6 @@ namespace TheXamlGuy.NotificationFlyout.Wpf.UI.Controls
return xamlHost; return xamlHost;
} }
private void OnContentRendered(object sender, EventArgs args)
{
IsLoaded = true;
OnContentLoaded();
}
private void PrepareWindowsXamlHost() private void PrepareWindowsXamlHost()
{ {
_xamlHost = new WindowsXamlHost(); _xamlHost = new WindowsXamlHost();
@@ -20,7 +20,6 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\TheXamlGuy.NotificationFlyout.Common\TheXamlGuy.NotificationFlyout.Common.csproj" /> <ProjectReference Include="..\TheXamlGuy.NotificationFlyout.Common\TheXamlGuy.NotificationFlyout.Common.csproj" />
<ProjectReference Include="..\TheXamlGuy.NotificationFlyout.Shared.UI\TheXamlGuy.NotificationFlyout.Shared.UI.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>
+2 -2
View File
@@ -14,9 +14,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheXamlGuy.NotificationFlyo
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheXamlGuy.NotificationFlyout.Wpf.UI.Controls", "TheXamlGuy.NotificationFlyout.Wpf.UI.Controls\TheXamlGuy.NotificationFlyout.Wpf.UI.Controls.csproj", "{3205F101-E5F3-4B57-B0BB-33693F906B77}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheXamlGuy.NotificationFlyout.Wpf.UI.Controls", "TheXamlGuy.NotificationFlyout.Wpf.UI.Controls\TheXamlGuy.NotificationFlyout.Wpf.UI.Controls.csproj", "{3205F101-E5F3-4B57-B0BB-33693F906B77}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheXamlGuy.NotificationFlyout.Shared.UI", "TheXamlGuy.NotificationFlyout.Shared.UI\TheXamlGuy.NotificationFlyout.Shared.UI.csproj", "{341F9830-BB2F-4A2F-A81A-3DBAF307B4EF}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheXamlGuy.NotificationFlyout.Shared.UI", "TheXamlGuy.NotificationFlyout.Shared.UI\TheXamlGuy.NotificationFlyout.Shared.UI.csproj", "{341F9830-BB2F-4A2F-A81A-3DBAF307B4EF}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TheXamlGuy.NotificationFlyout.Common", "TheXamlGuy.NotificationFlyout.Common\TheXamlGuy.NotificationFlyout.Common.csproj", "{4F05A3D6-DBBC-4921-97BA-6843925CD74B}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TheXamlGuy.NotificationFlyout.Common", "TheXamlGuy.NotificationFlyout.Common\TheXamlGuy.NotificationFlyout.Common.csproj", "{4F05A3D6-DBBC-4921-97BA-6843925CD74B}"
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution