Split sample project up

This commit is contained in:
Daniel Clark
2021-02-09 17:11:24 +00:00
parent d8581f33e7
commit aa16180509
71 changed files with 460 additions and 274 deletions
@@ -0,0 +1,24 @@
<Project Sdk="MSBuild.Sdk.Extras">
<PropertyGroup>
<TargetFrameworks>uap10.0.19041</TargetFrameworks>
<Platforms>AnyCPU;x64</Platforms>
<EnableTypeInfoReflection>false</EnableTypeInfoReflection>
<EnableXBindDiagnostics>false</EnableXBindDiagnostics>
<LangVersion>9.0</LangVersion>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
</PropertyGroup>
<ItemGroup>
<Page Include="NotificationFlyoutHost\NotificationFlyoutHost.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="NotificationFlyoutPresenter\NotificationFlyoutContentPresenter.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Themes\Generic.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
</Project>
@@ -0,0 +1,75 @@
using System.Numerics;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Media;
namespace NotificationFlyout.Uwp.UI.Controls
{
public class NotificationFlyoutHost : Control
{
public static readonly DependencyProperty ContentProperty =
DependencyProperty.Register(nameof(Content),
typeof(UIElement), typeof(NotificationFlyoutHost),
new PropertyMetadata(null));
private bool _isLoaded;
private string _placement;
private Grid _root;
public NotificationFlyoutHost()
{
DefaultStyleKey = typeof(NotificationFlyoutHost);
}
public UIElement Content
{
get => (UIElement)GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
public void HideFlyout()
{
if (_root == null) return;
FlyoutBase flyout = FlyoutBase.GetAttachedFlyout(_root);
flyout.Hide();
}
public void SetFlyoutPlacement(string placement)
{
if (!_isLoaded)
{
_placement = placement;
}
VisualStateManager.GoToState(this, placement, true);
}
public void ShowFlyout(FlyoutPlacementMode placementMode)
{
if (_root == null) return;
var flyout = FlyoutBase.GetAttachedFlyout(_root);
flyout.ShowAt(_root, new FlyoutShowOptions
{
Placement = placementMode,
ShowMode = FlyoutShowMode.Standard,
});
}
protected override void OnApplyTemplate()
{
_root = GetTemplateChild("Root") as Grid;
if (GetTemplateChild("ContentRoot") is Grid contentRoot)
{
contentRoot.Shadow = new ThemeShadow();
var currentTranslation = contentRoot.Translation;
var translation = new Vector3(currentTranslation.X, currentTranslation.Y, 16.0f);
contentRoot.Translation = translation;
}
_isLoaded = true;
SetFlyoutPlacement(_placement);
}
}
}
@@ -0,0 +1,102 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using: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="BorderThickness" Value="0" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="IsDefaultShadowEnabled" Value="False" />
<Setter Property="Padding" Value="0" />
</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">
<Grid x:Name="ContentRoot">
<Grid.Transitions>
<TransitionCollection>
<EntranceThemeTransition
x:Name="EntranceThemeTransition"
FromHorizontalOffset="0"
FromVerticalOffset="0" />
</TransitionCollection>
</Grid.Transitions>
<controls:NotificationFlyoutContentPresenter Content="{TemplateBinding Content}" />
</Grid>
</Flyout>
</FlyoutBase.AttachedFlyout>
<Border
Width="300"
Height="400"
Background="Blue" />
<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>
@@ -0,0 +1,12 @@
using Windows.UI.Xaml.Controls;
namespace NotificationFlyout.Uwp.UI.Controls
{
public class NotificationFlyoutContentPresenter : ContentControl
{
public NotificationFlyoutContentPresenter()
{
DefaultStyleKey = typeof(NotificationFlyoutContentPresenter);
}
}
}
@@ -0,0 +1,78 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using: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 x:Key="HighContrast">
<SolidColorBrush x:Key="NotificationFlyoutPresenterBackgroundBrush" Color="Green" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<AcrylicBrush
x:Key="NotificationFlyoutPresenterBackgroundAccentBrush"
BackgroundSource="HostBackdrop"
FallbackColor="{StaticResource SystemAccentColorDark1}"
TintColor="{StaticResource SystemAccentColorDark1}"
TintOpacity="0.8" />
<Style TargetType="controls:NotificationFlyoutContentPresenter">
<Setter Property="Background" Value="{ThemeResource NotificationFlyoutPresenterBackgroundBrush}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="controls:NotificationFlyoutContentPresenter">
<Border
x:Name="Root"
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BackgroundSizing="OuterBorderEdge"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<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}">
<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="ThemeStates">
<VisualState x:Name="DefaultTheme" />
<VisualState x:Name="ColorPrevalenceTheme">
<VisualState.Setters>
<Setter Target="Root.Background" Value="{ThemeResource NotificationFlyoutPresenterBackgroundAccentBrush}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
@@ -0,0 +1,14 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("NotificationFlyout.Uwp.UI.Controls")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("NotificationFlyout.Uwp.UI.Controls")]
[assembly: AssemblyCopyright("Copyright © 2021")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: ComVisible(false)]
@@ -0,0 +1,7 @@
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ms-appx:///NotificationFlyout.Uwp.UI.Controls/NotificationFlyoutHost/NotificationFlyoutHost.xaml" />
<ResourceDictionary Source="ms-appx:///NotificationFlyout.Uwp.UI.Controls/NotificationFlyoutPresenter/NotificationFlyoutContentPresenter.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWPF>true</UseWPF>
<AssetTargetFallback>uap10.0.19041</AssetTargetFallback>
<Platforms>AnyCPU;x64</Platforms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Toolkit.Wpf.UI.XamlHost" Version="6.1.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\NotificationFlyout.Uwp.UI.Controls\NotificationFlyout.Uwp.UI.Controls.csproj" />
<ProjectReference Include="..\NotificationFlyout.Wpf.UI\NotificationFlyout.Wpf.UI.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="Microsoft.VCRTForwarders.140" Version="1.0.7" />
</ItemGroup>
</Project>
@@ -0,0 +1,83 @@
using System.Windows;
using System.Windows.Markup;
using System.Windows.Media;
namespace NotificationFlyout.Wpf.UI.Controls
{
[ContentProperty(nameof(Content))]
public class NotificationFlyout : DependencyObject
{
public static readonly DependencyProperty IconSourceProperty =
DependencyProperty.Register(nameof(IconSource),
typeof(ImageSource), typeof(NotificationFlyout),
new PropertyMetadata(null, OnIconPropertyChanged));
public static readonly DependencyProperty LightIconSourceProperty =
DependencyProperty.Register(nameof(LightIconSource),
typeof(ImageSource), typeof(NotificationFlyout),
new PropertyMetadata(null, OnIconPropertyChanged));
public static DependencyProperty ContentProperty =
DependencyProperty.Register(nameof(Content),
typeof(Windows.UI.Xaml.UIElement), typeof(NotificationFlyout),
new PropertyMetadata(null, OnFlyoutPresenterPropertyChanged));
private readonly NotificationFlyoutXamlHost _xamlHost;
public NotificationFlyout()
{
_xamlHost = new NotificationFlyoutXamlHost();
_xamlHost.Show();
}
public Windows.UI.Xaml.UIElement Content
{
get => (Windows.UI.Xaml.UIElement)GetValue(ContentProperty);
set => SetValue(ContentProperty, value);
}
public ImageSource IconSource
{
get => (ImageSource)GetValue(IconSourceProperty);
set => SetValue(IconSourceProperty, value);
}
public ImageSource LightIconSource
{
get => (ImageSource)GetValue(LightIconSourceProperty);
set => SetValue(LightIconSourceProperty, value);
}
public void HideFlyout()
{
_xamlHost.HideFlyout();
}
public void ShowFlyout()
{
_xamlHost.ShowFlyout();
}
private static void OnFlyoutPresenterPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var sender = dependencyObject as NotificationFlyout;
sender?.OnFlyoutPresenterPropertyChanged();
}
private static void OnIconPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
var sender = dependencyObject as NotificationFlyout;
sender?.OnIconPropertyChanged();
}
private void OnFlyoutPresenterPropertyChanged()
{
_xamlHost.SetFlyoutContent(Content);
}
private void OnIconPropertyChanged()
{
_xamlHost.SetIcons(IconSource, LightIconSource);
}
}
}
@@ -0,0 +1,220 @@
using Microsoft.Toolkit.Wpf.UI.XamlHost;
using NotificationFlyout.Uwp.UI.Controls;
using NotificationFlyout.Wpf.UI.Extensions;
using NotificationFlyout.Wpf.UI.Helpers;
using System;
using System.Windows;
using System.Windows.Media;
using Windows.UI.Xaml.Controls.Primitives;
namespace NotificationFlyout.Wpf.UI.Controls
{
internal class NotificationFlyoutXamlHost : Window
{
private const string ShellTrayHandleName = "Shell_TrayWnd";
private const double WindowSize = 5;
private ImageSource _defaultIconSource;
private bool _isLoaded;
private ImageSource _lightIconSource;
private NotificationIconHelper _notificationIconHelper;
private SystemPersonalisationHelper _systemPersonalisationHelper;
private TaskbarHelper _taskbarHelper;
private WindowsXamlHost _xamlHost;
public NotificationFlyoutXamlHost()
{
PrepareDefaultWindow();
PrepareWindowsXamlHost();
Loaded += OnLoaded;
}
public void SetFlyoutContent(Windows.UI.Xaml.UIElement content)
{
var flyoutHost = GetFlyoutHost();
if (flyoutHost != null)
{
flyoutHost.Content = content;
}
}
internal void HideFlyout()
{
var flyoutHost = GetFlyoutHost();
if (flyoutHost != null)
{
flyoutHost.HideFlyout();
}
}
internal void SetIcons(ImageSource defaultIconSource, ImageSource lightIconSource)
{
_defaultIconSource = defaultIconSource;
_lightIconSource = lightIconSource;
UpdateIcon();
}
internal void ShowFlyout()
{
var flyoutHost = GetFlyoutHost();
if (flyoutHost != 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();
flyoutHost.ShowFlyout(flyoutPlacement);
}
}
private NotificationFlyoutHost GetFlyoutHost()
{
if (_xamlHost == null) return null;
return _xamlHost.GetUwpInternalObject() as NotificationFlyoutHost;
}
private void OnIconInvoked(object sender, NotificationIconInvokedEventArgs args)
{
ShowFlyout();
}
private void OnLoaded(object sender, RoutedEventArgs args)
{
PrepareNotificationIcon();
PrepareTaskbar();
_isLoaded = true;
UpdateWindow();
UpdateIcon();
this.Hidden();
}
private void OnTaskbarChanged(object sender, EventArgs args)
{
UpdateWindow();
}
private void OnThemeChanged(object sender, SystemPersonalisationChangedEventArgs args)
{
UpdateIcon();
}
private void PrepareDefaultWindow()
{
ShowInTaskbar = false;
ShowActivated = false;
WindowStyle = WindowStyle.None;
ResizeMode = ResizeMode.NoResize;
AllowsTransparency = true;
Background = new SolidColorBrush(Colors.Transparent);
Height = WindowSize;
Width = WindowSize;
}
private void PrepareNotificationIcon()
{
_notificationIconHelper = NotificationIconHelper.Create(this);
_notificationIconHelper.IconInvoked += OnIconInvoked;
_systemPersonalisationHelper = SystemPersonalisationHelper.Create(this);
_systemPersonalisationHelper.ThemeChanged += OnThemeChanged;
}
private void PrepareTaskbar()
{
_taskbarHelper = TaskbarHelper.Create(this);
_taskbarHelper.TaskbarChanged += OnTaskbarChanged;
}
private void PrepareWindowsXamlHost()
{
_xamlHost = new WindowsXamlHost
{
InitialTypeName = typeof(NotificationFlyoutHost).FullName
};
_xamlHost.Height = 0;
_xamlHost.Width = 0;
Content = _xamlHost;
}
private void UpdateIcon()
{
if (!_isLoaded) return;
var shellTrayHandle = WindowHelper.GetHandle(ShellTrayHandleName);
if (shellTrayHandle == null) return;
var dpi = WindowHelper.GetDpi(shellTrayHandle);
var iconSource = _systemPersonalisationHelper.Theme == SystemTheme.Dark ? _defaultIconSource : _lightIconSource;
if (iconSource == null) return;
using var icon = iconSource.ConvertToIcon(dpi);
_notificationIconHelper.SetIcon(icon.Handle);
}
private void UpdateWindow()
{
if (!_isLoaded) return;
var flyoutHost = GetFlyoutHost();
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());
}
}
}
@@ -0,0 +1,5 @@
using System.Windows;
using System.Windows.Markup;
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "NotificationFlyout.Wpf.UI.Controls")]
@@ -0,0 +1,31 @@
using Microsoft.Windows.Sdk;
using System;
using System.Drawing;
using System.Windows;
using System.Windows.Media;
namespace NotificationFlyout.Wpf.UI.Extensions
{
public static class ImageSourceExtensions
{
public static Icon ConvertToIcon(this ImageSource imageSource, uint dpi)
{
if (imageSource == null) return null;
var uri = new Uri(imageSource.ToString(), UriKind.RelativeOrAbsolute);
var streamResource = Application.GetResourceStream(uri);
if (streamResource == null) throw new ArgumentException(nameof(streamResource));
return new Icon(streamResource.Stream, new System.Drawing.Size(PInvoke.GetSystemMetricsForDpi((int)SystemMetricFlag.SM_CXICON, dpi), PInvoke.GetSystemMetricsForDpi((int)SystemMetricFlag.SM_CYICON, dpi)));
}
private enum SystemMetricFlag : int
{
SM_CXICON = 11,
SM_CYICON = 12,
SM_CXSMICON = 49,
SM_CYSMICON = 50
}
}
}
@@ -0,0 +1,13 @@
using NotificationFlyout.Wpf.UI.Helpers;
using System;
namespace NotificationFlyout.Wpf.UI.Extensions
{
public static class OperatingSystemExtensions
{
public static bool IsGreaterThan(this OperatingSystem operatingSystem, OperatingSystemVersion version)
{
return operatingSystem.Version.Build > (int)version;
}
}
}
@@ -0,0 +1,14 @@
namespace NotificationFlyout.Wpf.UI.Helpers
{
public enum OperatingSystemVersion : int
{
Windows10 = 10240,
Windows10_1511 = 10586,
Windows10_1607 = 14393,
Windows10_1703 = 15063,
Windows10_1709 = 16299,
Windows10_1803 = 17134,
Windows10_1809 = 17763,
Windows10_1903 = 18362
}
}
@@ -0,0 +1,15 @@
using Microsoft.Windows.Sdk;
using System.Windows;
namespace NotificationFlyout.Wpf.UI.Extensions
{
internal static class RECTExtensions
{
internal static Rect ToRect(this RECT rect)
{
if (rect.right - rect.left < 0 || rect.bottom - rect.top < 0) return new Rect(rect.left, rect.top, 0, 0);
return new Rect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
}
}
}
@@ -0,0 +1,12 @@
using Microsoft.Win32;
namespace NotificationFlyout.Wpf.UI.Extensions
{
public static class RegistryKeyExtensions
{
public static T GetValue<T>(this RegistryKey key, string valueName, T defaultValue = default)
{
return string.IsNullOrWhiteSpace(valueName) ? defaultValue : key.GetValue(valueName, defaultValue) is T value ? value : defaultValue;
}
}
}
@@ -0,0 +1,39 @@
using System.Windows;
using System.Windows.Media;
namespace NotificationFlyout.Wpf.UI.Extensions
{
public static class VisualExtensions
{
private static Matrix GetDpi(this Visual visual)
{
var source = PresentationSource.FromVisual(visual);
if (source?.CompositionTarget != null) return (Matrix)source?.CompositionTarget.TransformToDevice;
return default;
}
public static double DpiY(this Visual visual)
{
return GetDpi(visual).M22;
}
public static double DpiX(this Visual visual)
{
return GetDpi(visual).M11;
}
public static bool TryGetTransformToDevice(this Visual visual, out Matrix value)
{
var presentationSource = PresentationSource.FromVisual(visual);
if (presentationSource != null)
{
value = presentationSource.CompositionTarget.TransformToDevice;
return true;
}
value = default;
return false;
}
}
}
@@ -0,0 +1,47 @@
using Microsoft.Windows.Sdk;
using System;
using System.Windows;
using System.Windows.Interop;
namespace NotificationFlyout.Wpf.UI.Extensions
{
public static class WindowExtensions
{
private const int GWL_EX_STYLE = -20;
[Flags]
private enum WindowFlag : uint
{
SWP_NOSIZE = 0x0001,
SWP_NOMOVE = 0x0002,
SWP_NOZORDER = 0x0004,
SWP_NOACTIVATE = 0x0010,
WS_EX_NOACTIVATE = 0x08000000,
SWP_SHOWWINDOW = 0x0040,
WS_EX_APPWINDOW = 0x00040000,
WS_EX_TOOLWINDOW = 0x00000080
}
public static IntPtr GetHandle(this Window window)
{
var helper = new WindowInteropHelper(window);
return helper.Handle;
}
public static void Hidden(this Window window)
{
var handle = window.GetHandle();
PInvoke.SetWindowLong((HWND)handle, GWL_EX_STYLE, (PInvoke.GetWindowLong((HWND)handle, GWL_EX_STYLE) | (int)WindowFlag.WS_EX_TOOLWINDOW) & ~(int)WindowFlag.WS_EX_APPWINDOW);
}
public static void SetTopAll(this Window window)
{
PInvoke.SetWindowPos((HWND)window.GetHandle(), (HWND)new IntPtr(-1), 0, 0, 0, 0, (uint)WindowFlag.SWP_NOMOVE | (uint)WindowFlag.SWP_NOSIZE | (uint)WindowFlag.WS_EX_NOACTIVATE);
}
public static void SetWindowPosition(this Window window, double top, double left, double height, double width)
{
PInvoke.SetWindowPos((HWND)window.GetHandle(), (HWND)IntPtr.Zero, (int)left, (int)top, (int)width, (int)height, (uint)WindowFlag.SWP_NOSIZE | (uint)WindowFlag.SWP_NOZORDER | (uint)WindowFlag.SWP_NOACTIVATE);
}
}
}
@@ -0,0 +1,200 @@
using NotificationFlyout.Wpf.UI.Extensions;
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
namespace NotificationFlyout.Wpf.UI.Helpers
{
public class NotificationIconHelper : IDisposable
{
private const int CallbackMessage = 0x400;
private const uint IconVersion = 0x4;
private readonly object _lock = new();
private readonly IntPtr _windowHandle;
private bool _isDisposed;
private NotifyIconData _notifyIconData;
private NotificationIconHelper(Window window)
{
_windowHandle = window.GetHandle();
var source = HwndSource.FromHwnd(_windowHandle);
source.AddHook(new HwndSourceHook(WndProc));
CreateNotificationIcon();
}
~NotificationIconHelper()
{
Dispose(false);
}
public event EventHandler<NotificationIconInvokedEventArgs> IconInvoked;
private enum NotifyIconBalloonType
{
None = 0x00,
Info = 0x01,
Warning = 0x02,
Error = 0x03,
User = 0x04,
NoSound = 0x10,
LargeIcon = 0x20,
RespectQuietTime = 0x80
}
private enum NotifyIconCommand : uint
{
Add = 0x0,
Delete = 0x2,
Modify = 0x1,
SetVersion = 0x4
}
[Flags]
private enum NotifyIconDataMember : uint
{
Message = 0x01,
Icon = 0x02,
Tip = 0x04,
State = 0x08,
Info = 0x10,
Realtime = 0x40,
UseLegacyToolTips = 0x80
}
private enum NotifyIconState : uint
{
Visible = 0x00,
Hidden = 0x01
}
public static NotificationIconHelper Create(Window window)
{
return new NotificationIconHelper(window);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void SetIcon(IntPtr iconHandle)
{
lock (_lock)
{
_notifyIconData.IconHandle = iconHandle;
WriteNotifyIconData(NotifyIconCommand.Modify, NotifyIconDataMember.Icon);
}
}
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr DefWindowProcW(IntPtr handle, uint msg, IntPtr wParam, IntPtr lParam);
[DllImport("shell32.dll", SetLastError = true)]
private static extern int Shell_NotifyIcon(NotifyIconCommand notifyCommand, ref NotifyIconData notifyIconData);
private void CreateNotificationIcon()
{
lock (_lock)
{
_notifyIconData = new NotifyIconData();
_notifyIconData.cbSize = (uint)Marshal.SizeOf(_notifyIconData);
_notifyIconData.WindowHandle = _windowHandle;
_notifyIconData.TaskbarIconId = 0x0;
_notifyIconData.CallbackMessageId = CallbackMessage;
_notifyIconData.VersionOrTimeout = IconVersion;
_notifyIconData.IconHandle = IntPtr.Zero;
_notifyIconData.IconState = NotifyIconState.Hidden;
_notifyIconData.StateMask = NotifyIconState.Hidden;
WriteNotifyIconData(NotifyIconCommand.Add, NotifyIconDataMember.Message | NotifyIconDataMember.Icon | NotifyIconDataMember.Tip);
}
}
private void Dispose(bool disposing)
{
if (_isDisposed || !disposing) return;
lock (_lock)
{
_isDisposed = true;
RemoveNotificationIcon();
}
}
private void InvokeIconInvoked(MouseButton mouseButton)
{
IconInvoked?.Invoke(this, new NotificationIconInvokedEventArgs { MouseButton = mouseButton });
}
private void RemoveNotificationIcon() => WriteNotifyIconData(NotifyIconCommand.Delete, NotifyIconDataMember.Message);
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == CallbackMessage)
{
switch ((uint)lParam)
{
case (uint)WndProcMessages.WM_LBUTTONUP:
InvokeIconInvoked(MouseButton.Left);
break;
case (uint)WndProcMessages.WM_MBUTTONUP:
InvokeIconInvoked(MouseButton.Middle);
break;
case (uint)WndProcMessages.WM_RBUTTONUP:
InvokeIconInvoked(MouseButton.Right);
break;
}
}
return DefWindowProcW(hwnd, (uint)msg, wParam, (lParam));
}
private void WriteNotifyIconData(NotifyIconCommand command, NotifyIconDataMember flags)
{
_notifyIconData.ValidMembers = flags;
lock (_lock)
{
Shell_NotifyIcon(command, ref _notifyIconData);
}
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
private struct NotifyIconData
{
public uint cbSize;
public IntPtr WindowHandle;
public uint TaskbarIconId;
public NotifyIconDataMember ValidMembers;
public uint CallbackMessageId;
public IntPtr IconHandle;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string ToolTipText;
public NotifyIconState IconState;
public NotifyIconState StateMask;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
public string BalloonText;
public uint VersionOrTimeout;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
public string BalloonTitle;
public NotifyIconBalloonType BalloonFlags;
public Guid TaskbarIconGuid;
public IntPtr CustomBalloonIconHandle;
}
}
}
@@ -0,0 +1,10 @@
using System;
using System.Windows.Input;
namespace NotificationFlyout.Wpf.UI.Helpers
{
public class NotificationIconInvokedEventArgs : EventArgs
{
public MouseButton MouseButton { get; internal set; }
}
}
@@ -0,0 +1,44 @@
using Microsoft.Windows.Sdk;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Windows;
namespace NotificationFlyout.Wpf.UI.Helpers
{
public static class SystemInformationHelper
{
private const int SM_CXSCREEN = 0;
private const int SM_CYSCREEN = 1;
private const int SPI_GETWORKAREA = 48;
public static Rect VirtualScreen => GetVirtualScreen();
public static Rect WorkingArea => GetWorkingArea();
public static int GetCurrentDpi()
{
return (int)typeof(SystemParameters).GetProperty("Dpi", BindingFlags.Static | BindingFlags.NonPublic).GetValue(null, null);
}
public static double GetCurrentDpiScaleFactor()
{
return (double)GetCurrentDpi() / 96;
}
private static Rect GetVirtualScreen()
{
var size = new Size(PInvoke.GetSystemMetrics(SM_CXSCREEN), PInvoke.GetSystemMetrics(SM_CYSCREEN));
return new Rect(0, 0, size.Width, size.Height);
}
private static Rect GetWorkingArea()
{
var rect = new RECT();
SystemParametersInfo(SPI_GETWORKAREA, 0, ref rect, 0);
return new Rect(rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top);
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern bool SystemParametersInfo(int nAction, int nParam, ref RECT rc, int nUpdate);
}
}
@@ -0,0 +1,77 @@
using Microsoft.Win32;
using NotificationFlyout.Wpf.UI.Extensions;
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using Windows.UI.ViewManagement;
namespace NotificationFlyout.Wpf.UI.Helpers
{
public class SystemPersonalisationHelper
{
private readonly UISettings _settings = new();
private readonly string PersonalizeKey = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
private SystemTheme _currentTheme;
private bool _isColorPrevalence;
private SystemPersonalisationHelper(Window window)
{
var source = HwndSource.FromHwnd(window.GetHandle());
source.AddHook(new HwndSourceHook(WndProc));
_currentTheme = GetTheme();
_isColorPrevalence = GetIsColorPrevalence();
}
public event EventHandler<SystemPersonalisationChangedEventArgs> ThemeChanged;
public bool IsColorPrevalence => GetIsColorPrevalence();
public SystemTheme Theme => GetTheme();
public static SystemPersonalisationHelper Create(Window window)
{
return new SystemPersonalisationHelper(window);
}
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr DefWindowProcW(IntPtr handle, uint msg, IntPtr wParam, IntPtr lParam);
private bool GetIsColorPrevalence()
{
using var baseKey = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, RegistryView.Registry64);
using var subKey = baseKey.OpenSubKey(PersonalizeKey);
return subKey.GetValue<int>("ColorPrevalence", 0) > 0;
}
private SystemTheme GetTheme()
{
var color = _settings.GetColorValue(UIColorType.Background).ToString();
return color == "#FFFFFFFF" ? SystemTheme.Light : SystemTheme.Dark;
}
private void RaiseThemeChangedEvent()
{
var theme = GetTheme();
var isColorPrevalence = GetIsColorPrevalence();
if (theme != _currentTheme || _isColorPrevalence != isColorPrevalence)
{
_currentTheme = theme;
_isColorPrevalence = isColorPrevalence;
ThemeChanged?.Invoke(this, new SystemPersonalisationChangedEventArgs(theme, isColorPrevalence));
}
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == (int)WndProcMessages.WM_SETTINGCHANGE)
{
RaiseThemeChangedEvent();
}
return DefWindowProcW(hwnd, (uint)msg, wParam, (lParam));
}
}
}
@@ -0,0 +1,8 @@
namespace NotificationFlyout.Wpf.UI.Helpers
{
public enum SystemTheme
{
Dark,
Light,
}
}
@@ -0,0 +1,118 @@
using Microsoft.Windows.Sdk;
using NotificationFlyout.Wpf.UI.Extensions;
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
namespace NotificationFlyout.Wpf.UI.Helpers
{
public class TaskbarHelper
{
private const string ShellTrayHandleName = "Shell_TrayWnd";
private const int SPI_SETWORKAREA = 0x002F;
private readonly uint WM_TASKBARCREATED = PInvoke.RegisterWindowMessage("TaskbarCreated");
private TaskbarHelper(Window window)
{
var handle = window.GetHandle();
var source = HwndSource.FromHwnd(handle);
source.AddHook(new HwndSourceHook(WndProc));
}
public event EventHandler TaskbarChanged;
private enum AppBarEdge : uint
{
Left = 0,
Top = 1,
Right = 2,
Bottom = 3
}
private enum AppBarMessage : uint
{
New = 0x00000000,
Remove = 0x00000001,
QueryPos = 0x00000002,
SetPos = 0x00000003,
GetState = 0x00000004,
GetTaskbarPos = 0x00000005,
Activate = 0x00000006,
GetAutoHideBar = 0x00000007,
SetAutoHideBar = 0x00000008,
WindowPosChanged = 0x00000009,
SetState = 0x0000000A,
}
public static TaskbarHelper Create(Window window)
{
return new TaskbarHelper(window);
}
public TaskbarState GetCurrentState()
{
var handle = GetSystemTrayHandle();
var state = new TaskbarState
{
Screen = Screen.FromHandle(handle)
};
var appBarData = GetAppBarData(handle);
GetAppBarPosition(ref appBarData);
state.Rect = appBarData.rect.ToRect();
state.Position = (TaskbarPosition)appBarData.uEdge;
return state;
}
[DllImport("user32.dll", SetLastError = true)]
private static extern IntPtr DefWindowProcW(IntPtr handle, uint msg, IntPtr wParam, IntPtr lParam);
private static IntPtr GetSystemTrayHandle()
{
return WindowHelper.GetHandle(ShellTrayHandleName);
}
[DllImport("shell32.dll", SetLastError = true)]
private static extern IntPtr SHAppBarMessage(AppBarMessage dwMessage, ref AppBarData pData);
private AppBarData GetAppBarData(IntPtr handle)
{
return new AppBarData
{
cbSize = (uint)Marshal.SizeOf(typeof(AppBarData)),
hWnd = handle
};
}
private void GetAppBarPosition(ref AppBarData appBarData)
{
SHAppBarMessage(AppBarMessage.GetTaskbarPos, ref appBarData);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_TASKBARCREATED || msg == (int)WndProcMessages.WM_SETTINGCHANGE && (int)wParam == SPI_SETWORKAREA)
{
TaskbarChanged?.Invoke(this, EventArgs.Empty);
}
return DefWindowProcW(hwnd, (uint)msg, wParam, (lParam));
}
[StructLayout(LayoutKind.Sequential)]
private struct AppBarData
{
public uint cbSize;
public IntPtr hWnd;
public uint uCallbackMessage;
public AppBarEdge uEdge;
public RECT rect;
public int lParam;
}
}
}
@@ -0,0 +1,11 @@
namespace NotificationFlyout.Wpf.UI
{
public enum TaskbarPosition
{
Left = 0,
Top = 1,
Right = 2,
Bottom = 3
}
}
@@ -0,0 +1,11 @@
using System.Windows;
namespace NotificationFlyout.Wpf.UI
{
public struct TaskbarState
{
public TaskbarPosition Position;
public Rect Rect;
public Screen Screen;
}
}
@@ -0,0 +1,18 @@
using System;
namespace NotificationFlyout.Wpf.UI.Helpers
{
public class SystemPersonalisationChangedEventArgs : EventArgs
{
internal SystemPersonalisationChangedEventArgs(SystemTheme theme, bool isColorPrevalence)
{
Theme = theme;
IsColorPrevalence = isColorPrevalence;
}
public SystemTheme Theme { get; private set; }
public bool IsColorPrevalence { get; private set; }
}
}
@@ -0,0 +1,18 @@
using Microsoft.Windows.Sdk;
using System;
namespace NotificationFlyout.Wpf.UI.Helpers
{
public class WindowHelper
{
public static IntPtr GetHandle(string windowName)
{
return PInvoke.FindWindow(windowName, null);
}
public static uint GetDpi(IntPtr handle)
{
return PInvoke.GetDpiForWindow((HWND)handle);
}
}
}
@@ -0,0 +1,11 @@
namespace NotificationFlyout.Wpf.UI.Helpers
{
internal enum WndProcMessages
{
WM_LBUTTONUP = 0x0202,
WM_MBUTTONUP = 0x0208,
WM_RBUTTONUP = 0x0205,
WM_MOUSEMOVE = 0x0200,
WM_SETTINGCHANGE = 0x001A,
}
}
@@ -0,0 +1,13 @@
Shell_NotifyIcon
GetDpiForWindow
FindWindow
GetSystemMetricsForDpi
DefWindowProcW
GetSystemMetrics
MonitorFromWindow
RegisterWindowMessage
FindWindow
SHAppBarMessage
SetWindowPos
GetWindowLong
SetWindowLong
@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWPF>true</UseWPF>
<LangVersion>9.0</LangVersion>
<Platforms>AnyCPU;x64</Platforms>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.1.319-beta">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.Windows.SDK.Contracts" Version="10.0.19041.1" />
<PackageReference Include="System.Drawing.Common" Version="5.0.0" />
</ItemGroup>
</Project>
@@ -0,0 +1,3 @@
using System.Windows;
[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
+114
View File
@@ -0,0 +1,114 @@
using Microsoft.Windows.Sdk;
using NotificationFlyout.Wpf.UI.Helpers;
using System;
using System.Runtime.InteropServices;
using System.Windows;
namespace NotificationFlyout.Wpf.UI
{
public class Screen
{
private const int CCHDEVICENAME = 32;
private const int PRIMARY_MONITOR = unchecked((int)0xBAADF00D);
private const int SM_CMONITORS = 80;
private static readonly bool _multiMonitorSupport;
private readonly IntPtr _monitorHandle;
static Screen()
{
_multiMonitorSupport = PInvoke.GetSystemMetrics(SM_CMONITORS) != 0;
}
internal Screen(IntPtr monitorHandle)
{
if (!_multiMonitorSupport || monitorHandle == (IntPtr)PRIMARY_MONITOR)
{
Bounds = SystemInformationHelper.VirtualScreen;
Primary = true;
DeviceName = "DISPLAY";
}
else
{
var monitorData = GetMonitorData(monitorHandle);
Bounds = new Rect(monitorData.MonitorRect.left, monitorData.MonitorRect.top, monitorData.MonitorRect.right - monitorData.MonitorRect.left, monitorData.MonitorRect.bottom - monitorData.MonitorRect.top);
Primary = (monitorData.Flags & (int)MonitorFlag.MONITOR_DEFAULTTOPRIMARY) != 0;
DeviceName = monitorData.DeviceName;
}
_monitorHandle = monitorHandle;
}
private enum MonitorFlag : uint
{
MONITOR_DEFAULTTONULL = 0,
MONITOR_DEFAULTTOPRIMARY = 1,
MONITOR_DEFAULTTONEAREST = 2
}
public Rect Bounds { get; }
public string DeviceName { get; }
public bool Primary { get; }
public Rect WorkingArea => GetWorkingArea();
public static Screen FromHandle(IntPtr handle)
{
return _multiMonitorSupport ? new Screen(PInvoke.MonitorFromWindow((HWND)handle, (uint)MonitorFlag.MONITOR_DEFAULTTONEAREST)) : new Screen((IntPtr)PRIMARY_MONITOR);
}
public override bool Equals(object obj)
{
if (obj is Screen monitor)
{
if (_monitorHandle == monitor._monitorHandle)
{
return true;
}
}
return false;
}
public override int GetHashCode()
{
return (int)_monitorHandle;
}
[DllImport("user32.dll", EntryPoint = "GetMonitorInfo", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool GetMonitorInfoEx(IntPtr hMonitor, ref MonitorData lpmi);
private MonitorData GetMonitorData(IntPtr monitorHandle)
{
var monitorData = new MonitorData();
monitorData.Size = Marshal.SizeOf(monitorData);
GetMonitorInfoEx(monitorHandle, ref monitorData);
return monitorData;
}
private Rect GetWorkingArea()
{
if (!_multiMonitorSupport || _monitorHandle == (IntPtr)PRIMARY_MONITOR)
{
return SystemInformationHelper.WorkingArea;
}
var monitorData = GetMonitorData(_monitorHandle);
return new Rect(monitorData.WorkAreaRect.left, monitorData.WorkAreaRect.top, monitorData.WorkAreaRect.right - monitorData.WorkAreaRect.left, monitorData.WorkAreaRect.bottom - monitorData.WorkAreaRect.top);
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private struct MonitorData
{
public int Size;
public RECT MonitorRect;
public RECT WorkAreaRect;
public uint Flags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
public string DeviceName;
}
}
}
+98
View File
@@ -0,0 +1,98 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30914.41
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotificationFlyout.Wpf.UI.Controls", "NotificationFlyout.Wpf.UI.Controls\NotificationFlyout.Wpf.UI.Controls.csproj", "{0A782234-DC9F-4C4A-8820-FC640B03D233}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotificationFlyout.Uwp.UI.Controls", "NotificationFlyout.Uwp.UI.Controls\NotificationFlyout.Uwp.UI.Controls.csproj", "{9987B132-E42C-401A-9AD5-E62529FACA40}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotificationFlyout.Wpf.UI", "NotificationFlyout.Wpf.UI\NotificationFlyout.Wpf.UI.csproj", "{29430194-7EDE-4C33-AF59-CE121F48F66E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{B7EEAC24-4F8A-4C73-90B3-DAC77D44CCF2}"
ProjectSection(SolutionItems) = preProject
global.json = global.json
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Debug|ARM.ActiveCfg = Debug|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Debug|ARM.Build.0 = Debug|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Debug|ARM64.Build.0 = Debug|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Debug|x64.ActiveCfg = Debug|x64
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Debug|x64.Build.0 = Debug|x64
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Debug|x86.ActiveCfg = Debug|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Debug|x86.Build.0 = Debug|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Release|Any CPU.Build.0 = Release|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Release|ARM.ActiveCfg = Release|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Release|ARM.Build.0 = Release|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Release|ARM64.ActiveCfg = Release|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Release|ARM64.Build.0 = Release|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Release|x64.ActiveCfg = Release|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Release|x64.Build.0 = Release|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Release|x86.ActiveCfg = Release|Any CPU
{0A782234-DC9F-4C4A-8820-FC640B03D233}.Release|x86.Build.0 = Release|Any CPU
{9987B132-E42C-401A-9AD5-E62529FACA40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9987B132-E42C-401A-9AD5-E62529FACA40}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9987B132-E42C-401A-9AD5-E62529FACA40}.Debug|ARM.ActiveCfg = Debug|ARM
{9987B132-E42C-401A-9AD5-E62529FACA40}.Debug|ARM.Build.0 = Debug|ARM
{9987B132-E42C-401A-9AD5-E62529FACA40}.Debug|ARM64.ActiveCfg = Debug|ARM64
{9987B132-E42C-401A-9AD5-E62529FACA40}.Debug|ARM64.Build.0 = Debug|ARM64
{9987B132-E42C-401A-9AD5-E62529FACA40}.Debug|x64.ActiveCfg = Debug|x64
{9987B132-E42C-401A-9AD5-E62529FACA40}.Debug|x64.Build.0 = Debug|x64
{9987B132-E42C-401A-9AD5-E62529FACA40}.Debug|x86.ActiveCfg = Debug|x86
{9987B132-E42C-401A-9AD5-E62529FACA40}.Debug|x86.Build.0 = Debug|x86
{9987B132-E42C-401A-9AD5-E62529FACA40}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9987B132-E42C-401A-9AD5-E62529FACA40}.Release|Any CPU.Build.0 = Release|Any CPU
{9987B132-E42C-401A-9AD5-E62529FACA40}.Release|ARM.ActiveCfg = Release|ARM
{9987B132-E42C-401A-9AD5-E62529FACA40}.Release|ARM.Build.0 = Release|ARM
{9987B132-E42C-401A-9AD5-E62529FACA40}.Release|ARM64.ActiveCfg = Release|ARM64
{9987B132-E42C-401A-9AD5-E62529FACA40}.Release|ARM64.Build.0 = Release|ARM64
{9987B132-E42C-401A-9AD5-E62529FACA40}.Release|x64.ActiveCfg = Release|x64
{9987B132-E42C-401A-9AD5-E62529FACA40}.Release|x64.Build.0 = Release|x64
{9987B132-E42C-401A-9AD5-E62529FACA40}.Release|x86.ActiveCfg = Release|x86
{9987B132-E42C-401A-9AD5-E62529FACA40}.Release|x86.Build.0 = Release|x86
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Debug|ARM.ActiveCfg = Debug|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Debug|ARM.Build.0 = Debug|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Debug|ARM64.Build.0 = Debug|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Debug|x64.ActiveCfg = Debug|x64
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Debug|x64.Build.0 = Debug|x64
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Debug|x86.ActiveCfg = Debug|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Debug|x86.Build.0 = Debug|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Release|Any CPU.Build.0 = Release|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Release|ARM.ActiveCfg = Release|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Release|ARM.Build.0 = Release|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Release|ARM64.ActiveCfg = Release|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Release|ARM64.Build.0 = Release|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Release|x64.ActiveCfg = Release|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Release|x64.Build.0 = Release|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Release|x86.ActiveCfg = Release|Any CPU
{29430194-7EDE-4C33-AF59-CE121F48F66E}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EDFFB261-AD00-4C68-BF55-D5CED5BE0039}
EndGlobalSection
EndGlobal
+5
View File
@@ -0,0 +1,5 @@
{
"msbuild-sdks": {
"MSBuild.Sdk.Extras": "3.0.22"
}
}