This commit is contained in:
Daniel Clark
2021-02-05 01:39:51 +00:00
parent 666067a36c
commit 45a9eb9cd2
73 changed files with 2669 additions and 0 deletions
@@ -0,0 +1,19 @@
<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>
</Project>
@@ -0,0 +1,81 @@
using NotificationFlyout.Wpf.UI.Extensions;
using NotificationFlyout.Wpf.UI.Helpers;
using System.Windows;
namespace NotificationFlyout.Wpf.UI.Controls
{
public class NotificationFlyout : DependencyObject
{
private const string ShellTrayHandleName = "Shell_TrayWnd";
public static readonly DependencyProperty IconProperty =
DependencyProperty.Register(nameof(Icon),
typeof(NotificationFlyoutIcon), typeof(NotificationFlyout),
new PropertyMetadata(null, OnIconPropertyChanged));
public static DependencyProperty FlyoutContentProperty =
DependencyProperty.Register(nameof(FlyoutContent),
typeof(Windows.UI.Xaml.UIElement), typeof(NotificationFlyout),
new PropertyMetadata(null, OnFlyoutContentPropertyChanged));
private NotificationFlyoutXamlHost _xamlHost;
public NotificationFlyout()
{
_xamlHost = new NotificationFlyoutXamlHost();
_xamlHost.Show();
}
public Windows.UI.Xaml.UIElement FlyoutContent
{
get => (Windows.UI.Xaml.UIElement)GetValue(FlyoutContentProperty);
set => SetValue(FlyoutContentProperty, value);
}
public NotificationFlyoutIcon Icon
{
get => (NotificationFlyoutIcon)GetValue(IconProperty);
set => SetValue(IconProperty, value);
}
public void HideFlyout()
{
_xamlHost.HideFlyout();
}
public void ShowFlyout()
{
_xamlHost.ShowFlyout();
}
private static void OnFlyoutContentPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var sender = dependencyObject as NotificationFlyout;
sender?.OnFlyoutContentPropertyChanged();
}
private static void OnIconPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
{
var sender = dependencyObject as NotificationFlyout;
sender?.OnIconPropertyChanged();
}
private void OnFlyoutContentPropertyChanged()
{
_xamlHost.FlyoutContent = FlyoutContent;
}
private void OnIconPropertyChanged()
{
var shellTrayHandle = WindowHelper.GetHandle(ShellTrayHandleName);
if (shellTrayHandle == null) return;
var dpi = WindowHelper.GetDpi(shellTrayHandle);
var iconSource = SystemSettingsHelper.DefaultSystemTheme == SystemTheme.Dark ? Icon.IconSource : Icon.LightIconSource;
using var icon = iconSource.ConvertToIcon(dpi);
_xamlHost.SetNotificationIcon(icon.Handle);
}
}
}
@@ -0,0 +1,28 @@
using System.Windows;
using System.Windows.Media;
namespace NotificationFlyout.Wpf.UI.Controls
{
public class NotificationFlyoutIcon : DependencyObject
{
public static readonly DependencyProperty IconSourceProperty =
DependencyProperty.Register(nameof(IconSource),
typeof(ImageSource), typeof(NotificationFlyout));
public static readonly DependencyProperty LightIconSourceProperty =
DependencyProperty.Register(nameof(LightIconSource),
typeof(ImageSource), typeof(NotificationFlyout));
public ImageSource IconSource
{
get => (ImageSource)GetValue(IconSourceProperty);
set => SetValue(IconSourceProperty, value);
}
public ImageSource LightIconSource
{
get => (ImageSource)GetValue(LightIconSourceProperty);
set => SetValue(LightIconSourceProperty, value);
}
}
}
@@ -0,0 +1,193 @@
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 Windows.UI.Xaml.Controls.Primitives;
namespace NotificationFlyout.Wpf.UI.Controls
{
internal class NotificationFlyoutXamlHost : Window
{
internal static DependencyProperty FlyoutContentProperty =
DependencyProperty.Register(nameof(FlyoutContent),
typeof(Windows.UI.Xaml.UIElement), typeof(NotificationFlyoutXamlHost),
new PropertyMetadata(null, OnFlyoutContentPropertyChanged));
private WindowsXamlHost _host;
private NotificationIconHelper _notificationIconHelper;
private bool _taskbarChanged;
private TaskbarHelper _taskbarHelper;
public NotificationFlyoutXamlHost()
{
PrepareDefaultWindow();
PrepareWindowsXamlHost();
Loaded += OnLoaded;
}
public Windows.UI.Xaml.UIElement FlyoutContent
{
get => (Windows.UI.Xaml.UIElement)GetValue(FlyoutContentProperty);
set => SetValue(FlyoutContentProperty, value);
}
internal void HideFlyout()
{
var flyoutContentControl = GetNotificationFlyoutPresenter();
if (flyoutContentControl != null)
{
flyoutContentControl.HideFlyout();
}
}
internal void SetNotificationIcon(IntPtr handle)
{
_notificationIconHelper.SetIcon(handle);
}
internal void ShowFlyout()
{
var flyoutContentControl = GetNotificationFlyoutPresenter();
if (flyoutContentControl != null)
{
var taskbarState = _taskbarHelper.GetCurrentState();
var flyoutPlacement = FlyoutPlacementMode.Bottom;
switch (taskbarState.Position)
{
case TaskbarPosition.Left:
flyoutPlacement = FlyoutPlacementMode.Right;
break;
case TaskbarPosition.Top:
flyoutPlacement = FlyoutPlacementMode.Bottom;
break;
case TaskbarPosition.Right:
flyoutPlacement = FlyoutPlacementMode.Left;
break;
case TaskbarPosition.Bottom:
flyoutPlacement = FlyoutPlacementMode.Top;
break;
}
UpdateWindow();
Activate();
flyoutContentControl.ShowFlyout(flyoutPlacement);
}
}
private static void OnFlyoutContentPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var sender = dependencyObject as NotificationFlyoutXamlHost;
sender?.OnFlyoutContentPropertyChanged();
}
private NotificationFlyoutPresenter GetNotificationFlyoutPresenter()
{
return _host.GetUwpInternalObject() as NotificationFlyoutPresenter;
}
private void OnFlyoutContentPropertyChanged()
{
var flyoutContentControl = GetNotificationFlyoutPresenter();
if (flyoutContentControl != null)
{
flyoutContentControl.Content = FlyoutContent;
}
}
private void OnIconInvoked(object sender, NotificationIconInvokedEventArgs args)
{
ShowFlyout();
}
private void OnLoaded(object sender, RoutedEventArgs args)
{
PrepareNotificationIcon();
PrepareTaskbar();
UpdateWindow();
}
private void OnTaskbarChanged(object sender, EventArgs args)
{
_taskbarChanged = true;
var taskbarState = _taskbarHelper.GetCurrentState();
Left = taskbarState.Screen.WorkingArea.Left;
Top = taskbarState.Screen.WorkingArea.Top;
UpdateWindow();
}
private void PrepareDefaultWindow()
{
ShowInTaskbar = false;
ShowActivated = false;
WindowStyle = WindowStyle.None;
ResizeMode = ResizeMode.NoResize;
AllowsTransparency = true;
Height = 0;
Width = 0;
}
private void PrepareNotificationIcon()
{
_notificationIconHelper = NotificationIconHelper.Create(this);
_notificationIconHelper.IconInvoked += OnIconInvoked;
}
private void PrepareTaskbar()
{
_taskbarHelper = TaskbarHelper.Create(this);
_taskbarHelper.TaskbarChanged += OnTaskbarChanged;
}
private void PrepareWindowsXamlHost()
{
_host = new WindowsXamlHost
{
InitialTypeName = typeof(NotificationFlyoutPresenter).FullName
};
_host.Height = 0;
_host.Width = 0;
Content = _host;
}
private void UpdateWindow()
{
var taskbarState = _taskbarHelper.GetCurrentState();
var screen = Screen.FromHandle(this.GetHandle());
MaxHeight = screen.Bounds.Height / 2;
var windowWidth = DesiredSize.Width * this.DpiX();
var windowHeight = DesiredSize.Height * this.DpiY();
var taskbarRect = taskbarState.Rect;
switch (taskbarState.Position)
{
case TaskbarPosition.Left:
this.SetWindowPosition(taskbarRect.Bottom - windowHeight, taskbarRect.Right, windowHeight, windowWidth);
break;
case TaskbarPosition.Top:
this.SetWindowPosition(taskbarRect.Bottom, FlowDirection == FlowDirection.RightToLeft ? taskbarRect.Left : taskbarRect.Right - windowWidth, windowHeight, windowWidth);
break;
case TaskbarPosition.Right:
this.SetWindowPosition(taskbarRect.Bottom - windowHeight, taskbarRect.Left - windowWidth, windowHeight, windowWidth);
break;
case TaskbarPosition.Bottom:
this.SetWindowPosition(taskbarRect.Top - windowHeight, FlowDirection == FlowDirection.RightToLeft ? taskbarRect.Left : taskbarRect.Right - windowWidth, windowHeight, windowWidth);
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
}
@@ -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")]