[WIP] Move over to a popup
This commit is contained in:
+66
-35
@@ -1,20 +1,17 @@
|
||||
using System;
|
||||
using TheXamlGuy.NotificationFlyout.Shared.UI;
|
||||
using Windows.Foundation;
|
||||
using Windows.UI;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Markup;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
||||
namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
|
||||
{
|
||||
[ContentProperty(Name = "Content")]
|
||||
public class NotificationFlyout : DependencyObject
|
||||
public class NotificationFlyout : ContentControl
|
||||
{
|
||||
public static readonly DependencyProperty FlyoutPresenterStyleProperty =
|
||||
DependencyProperty.Register(nameof(FlyoutPresenterStyle),
|
||||
typeof(Style), typeof(NotificationFlyout),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
public static readonly DependencyProperty IconSourceProperty =
|
||||
DependencyProperty.Register(nameof(IconSource),
|
||||
typeof(ImageSource), typeof(NotificationFlyout),
|
||||
@@ -25,16 +22,6 @@ namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
|
||||
typeof(ImageSource), typeof(NotificationFlyout),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
public static readonly DependencyProperty RequestedThemeProperty =
|
||||
DependencyProperty.Register(nameof(RequestedTheme),
|
||||
typeof(ElementTheme), typeof(NotificationFlyout),
|
||||
new PropertyMetadata(ElementTheme.Default));
|
||||
|
||||
public static DependencyProperty ContentProperty =
|
||||
DependencyProperty.Register(nameof(Content),
|
||||
typeof(UIElement), typeof(NotificationFlyout),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
public static DependencyProperty ContextMenuProperty =
|
||||
DependencyProperty.Register(nameof(ContextMenu),
|
||||
typeof(NotificationFlyoutContextMenu), typeof(NotificationFlyout),
|
||||
@@ -47,6 +34,8 @@ namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
|
||||
|
||||
private static INotificationFlyoutApplication _applicationInstance;
|
||||
|
||||
private Popup _popup;
|
||||
|
||||
public event EventHandler<object> Closed;
|
||||
|
||||
public event TypedEventHandler<NotificationFlyout, NotificationFlyoutClosingEventArgs> Closing;
|
||||
@@ -61,24 +50,12 @@ namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
|
||||
|
||||
internal event EventHandler PlacementChanged;
|
||||
|
||||
public UIElement Content
|
||||
{
|
||||
get => (UIElement)GetValue(ContentProperty);
|
||||
set => SetValue(ContentProperty, value);
|
||||
}
|
||||
|
||||
public NotificationFlyoutContextMenu ContextMenu
|
||||
{
|
||||
get => (NotificationFlyoutContextMenu)GetValue(ContextMenuProperty);
|
||||
set => SetValue(ContextMenuProperty, value);
|
||||
}
|
||||
|
||||
public Style FlyoutPresenterStyle
|
||||
{
|
||||
get => (Style)GetValue(FlyoutPresenterStyleProperty);
|
||||
set => SetValue(FlyoutPresenterStyleProperty, value);
|
||||
}
|
||||
|
||||
public ImageSource IconSource
|
||||
{
|
||||
get => (ImageSource)GetValue(IconSourceProperty);
|
||||
@@ -97,12 +74,6 @@ namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
|
||||
set => SetValue(PlacementProperty, value);
|
||||
}
|
||||
|
||||
public ElementTheme RequestedTheme
|
||||
{
|
||||
get => (ElementTheme)GetValue(RequestedThemeProperty);
|
||||
set => SetValue(RequestedThemeProperty, value);
|
||||
}
|
||||
|
||||
public static INotificationFlyoutApplication GetApplication() => _applicationInstance;
|
||||
|
||||
internal static void SetApplication(INotificationFlyoutApplication application) => _applicationInstance = application;
|
||||
@@ -115,6 +86,51 @@ namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
|
||||
|
||||
internal void InvokeOpeningEvent(object obj) => Opening?.Invoke(this, obj);
|
||||
|
||||
internal void SetPlacement(double horizontalOffset, double verticalOffset, NotificationFlyoutTaskbarPlacement flyoutTaskbarPlacement)
|
||||
{
|
||||
if (_popup == null)
|
||||
{
|
||||
PreparePopup();
|
||||
}
|
||||
|
||||
var width = 100;
|
||||
var height = 100;
|
||||
|
||||
var desiredHorizontalOffset = horizontalOffset;
|
||||
var desiredVerticalOffset = verticalOffset;
|
||||
|
||||
switch (flyoutTaskbarPlacement)
|
||||
{
|
||||
case NotificationFlyoutTaskbarPlacement.Left:
|
||||
desiredVerticalOffset = 0;
|
||||
break;
|
||||
case NotificationFlyoutTaskbarPlacement.Top:
|
||||
desiredHorizontalOffset -= width;
|
||||
break;
|
||||
case NotificationFlyoutTaskbarPlacement.Right:
|
||||
desiredHorizontalOffset -= width;
|
||||
desiredVerticalOffset -= height;
|
||||
break;
|
||||
case NotificationFlyoutTaskbarPlacement.Bottom:
|
||||
desiredHorizontalOffset -= width;
|
||||
desiredVerticalOffset -= height;
|
||||
break;
|
||||
}
|
||||
|
||||
_popup.HorizontalOffset = desiredHorizontalOffset;
|
||||
_popup.VerticalOffset = desiredVerticalOffset;
|
||||
}
|
||||
|
||||
internal void Show()
|
||||
{
|
||||
if (_popup == null)
|
||||
{
|
||||
PreparePopup();
|
||||
}
|
||||
|
||||
_popup.IsOpen = true;
|
||||
}
|
||||
|
||||
private static void OnContextMenuPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
var sender = dependencyObject as NotificationFlyout;
|
||||
@@ -138,5 +154,20 @@ namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
|
||||
private void OnIconPropertyChanged() => IconSourceChanged?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
private void OnPlacementPropertyChanged() => PlacementChanged?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
private void PreparePopup()
|
||||
{
|
||||
var f = new Grid { Background = new SolidColorBrush(Colors.Blue), Height = 100, Width = 100 };
|
||||
f.Children.Add(new Button { Content = "hefrefsef2" });
|
||||
|
||||
_popup = new Popup
|
||||
{
|
||||
XamlRoot = XamlRoot,
|
||||
ShouldConstrainToRootBounds = false,
|
||||
HorizontalOffset = -1,
|
||||
VerticalOffset = -1,
|
||||
Child = f
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -28,13 +28,13 @@
|
||||
FallbackColor="{ThemeResource SystemAccentColorDark1}"
|
||||
TintColor="{ThemeResource SystemAccentColorDark1}"
|
||||
TintOpacity="0.8" />
|
||||
<Style TargetType="controls:NotificationFlyoutPresenter">
|
||||
<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:NotificationFlyoutPresenter">
|
||||
<ControlTemplate TargetType="controls:NotificationFlyout">
|
||||
<Grid
|
||||
x:Name="Root"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
+1
-2
@@ -1,11 +1,10 @@
|
||||
namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
|
||||
{
|
||||
internal enum NotificationFlyoutPresenterPlacement
|
||||
internal enum NotificationFlyoutTaskbarPlacement
|
||||
{
|
||||
Left,
|
||||
Top,
|
||||
Right,
|
||||
Bottom,
|
||||
FullRight
|
||||
}
|
||||
}
|
||||
-26
@@ -1,26 +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 UpdateThemeVisualState(bool isColorPrevalence) => VisualStateManager.GoToState(this, isColorPrevalence ? "ColorPrevalenceTheme" : "DefaultTheme", true);
|
||||
}
|
||||
}
|
||||
-135
@@ -1,135 +0,0 @@
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Controls.Primitives;
|
||||
using Windows.UI.Xaml.Data;
|
||||
|
||||
namespace TheXamlGuy.NotificationFlyout.Uwp.UI.Controls
|
||||
{
|
||||
internal class NotificationFlyoutPresenterHost : Control
|
||||
{
|
||||
public static readonly DependencyProperty ContentProperty =
|
||||
DependencyProperty.Register(nameof(Content),
|
||||
typeof(UIElement), typeof(NotificationFlyoutPresenterHost),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
public static readonly DependencyProperty FlyoutPresenterStyleProperty =
|
||||
DependencyProperty.Register(nameof(FlyoutPresenterStyle),
|
||||
typeof(Style), typeof(NotificationFlyoutPresenterHost),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
private Flyout _flyout;
|
||||
private NotificationFlyout _notificationFlyout;
|
||||
private NotificationFlyoutPresenter _notificationFlyoutPresenter;
|
||||
private Grid _root;
|
||||
|
||||
public NotificationFlyoutPresenterHost() => DefaultStyleKey = typeof(NotificationFlyoutPresenterHost);
|
||||
|
||||
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 UpdatePlacement(NotificationFlyoutPresenterPlacement placement)
|
||||
{
|
||||
var state = placement.ToString();
|
||||
|
||||
VisualStateManager.GoToState(this, state, true);
|
||||
VisualStateManager.GoToState(_notificationFlyoutPresenter, state, true);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
-99
@@ -1,99 +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:NotificationFlyoutPresenterHost">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:NotificationFlyoutPresenterHost">
|
||||
<Grid x:Name="Root">
|
||||
<Grid.Resources>
|
||||
<Style x:Key="DefaultFlyoutPresenterStyle" TargetType="FlyoutPresenter">
|
||||
<Setter Property="IsDefaultShadowEnabled" Value="False" />
|
||||
<Setter Property="MaxWidth" Value="Auto" />
|
||||
<Setter Property="MaxHeight" Value="Auto" />
|
||||
<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}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Top">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Flyout.FlyoutPresenterStyle" Value="{StaticResource TopFlyoutPresenterStyle}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Left">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Flyout.FlyoutPresenterStyle" Value="{StaticResource LeftFlyoutPresenterStyle}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Right">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Flyout.FlyoutPresenterStyle" Value="{StaticResource RightFlyoutPresenterStyle}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="FullRight">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="Flyout.FlyoutPresenterStyle" Value="{StaticResource BottomFlyoutPresenterStyle}" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
+1
-5
@@ -18,11 +18,7 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="NotificationFlyoutPresenter\NotificationFlyoutPresenterHost.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="NotificationFlyoutPresenter\NotificationFlyoutPresenter.xaml">
|
||||
<Page Include="NotificationFlyout\NotificationFlyout.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="ms-appx:///TheXamlGuy.NotificationFlyout.Uwp.UI.Controls/NotificationFlyoutPresenter/NotificationFlyoutPresenter.xaml" />
|
||||
<ResourceDictionary Source="ms-appx:///TheXamlGuy.NotificationFlyout.Uwp.UI.Controls/NotificationFlyoutPresenter/NotificationFlyoutPresenterHost.xaml" />
|
||||
<ResourceDictionary Source="ms-appx:///TheXamlGuy.NotificationFlyout.Uwp.UI.Controls/NotificationFlyoutPresenter/NotificationFlyoutContextMenuFlyoutHost.xaml" />
|
||||
<ResourceDictionary Source="ms-appx:///TheXamlGuy.NotificationFlyout.Uwp.UI.Controls/NotificationFlyout/NotificationFlyout.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
+149
-23
@@ -1,62 +1,188 @@
|
||||
using TheXamlGuy.NotificationFlyout.Common.Helpers;
|
||||
using System.Windows;
|
||||
using System.Windows.Markup;
|
||||
using TheXamlGuy.NotificationFlyout.Shared.UI;
|
||||
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;
|
||||
|
||||
namespace TheXamlGuy.NotificationFlyout.Wpf.UI.Controls
|
||||
{
|
||||
[ContentProperty(nameof(Flyout))]
|
||||
public class NotificationFlyoutApplication : DependencyObject, INotificationFlyoutApplication
|
||||
public class NotificationFlyoutApplication : DependencyObject
|
||||
{
|
||||
public static DependencyProperty FlyoutProperty =
|
||||
DependencyProperty.Register(nameof(Flyout),
|
||||
typeof(Uwp.UI.Controls.NotificationFlyout), typeof(NotificationFlyoutApplication),
|
||||
new PropertyMetadata(null, OnFlyoutPropertyChanged));
|
||||
|
||||
private static NotificationFlyoutApplication _application;
|
||||
private NotificationFlyoutXamlHost _notificationFlyoutXamlHost;
|
||||
private const string ShellTrayHandleName = "Shell_TrayWnd";
|
||||
private TransparentXamlHost<ContentControl> _notificationFlyoutXamlHost;
|
||||
private NotificationIconHelper _notificationIconHelper;
|
||||
private SystemPersonalisationHelper _systemPersonalisationHelper;
|
||||
private TaskbarHelper _taskbarHelper;
|
||||
|
||||
public NotificationFlyoutApplication()
|
||||
{
|
||||
_application = this;
|
||||
Uwp.UI.Controls.NotificationFlyout.SetApplication(this);
|
||||
_notificationIconHelper = NotificationIconHelper.Create();
|
||||
_notificationIconHelper.IconInvoked += OnIconInvoked;
|
||||
|
||||
_taskbarHelper = TaskbarHelper.Create();
|
||||
_taskbarHelper.TaskbarChanged += OnTaskbarChanged;
|
||||
|
||||
_systemPersonalisationHelper = SystemPersonalisationHelper.Current;
|
||||
_systemPersonalisationHelper.ThemeChanged += OnThemeChanged;
|
||||
|
||||
WndProcListener.Current.Start();
|
||||
PrepareFlyoutHost();
|
||||
WndProcListener.Current.Start();
|
||||
}
|
||||
|
||||
public static INotificationFlyoutApplication Current => _application;
|
||||
|
||||
public Uwp.UI.Controls.NotificationFlyout Flyout
|
||||
{
|
||||
get => (Uwp.UI.Controls.NotificationFlyout)GetValue(FlyoutProperty);
|
||||
set => SetValue(FlyoutProperty, value);
|
||||
}
|
||||
|
||||
public void Exit() => _notificationFlyoutXamlHost.Close();
|
||||
|
||||
public void HideFlyout() => _notificationFlyoutXamlHost.HideFlyout();
|
||||
|
||||
public void OpenAsWindow<TUIElement>() where TUIElement : Windows.UI.Xaml.UIElement
|
||||
{
|
||||
var window = new XamlHost<TUIElement>();
|
||||
window.Show();
|
||||
}
|
||||
|
||||
public void ShowFlyout() => _notificationFlyoutXamlHost.ShowFlyout();
|
||||
|
||||
private static void OnFlyoutPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
|
||||
{
|
||||
var sender = dependencyObject as NotificationFlyoutApplication;
|
||||
sender?.OnFlyoutPropertyChanged();
|
||||
}
|
||||
|
||||
private void OnFlyoutPropertyChanged() => _notificationFlyoutXamlHost.SetOwningFlyout(Flyout);
|
||||
private void OnFlyoutPropertyChanged() => PrepareFlyout();
|
||||
|
||||
private void PrepareFlyout()
|
||||
{
|
||||
if (Flyout == null) return;
|
||||
Flyout.IconSourceChanged += OnIconSourceChanged;
|
||||
|
||||
var content = _notificationFlyoutXamlHost.GetHostContent();
|
||||
if (content != null)
|
||||
{
|
||||
content.Content = Flyout;
|
||||
}
|
||||
|
||||
UpdateIcons();
|
||||
}
|
||||
|
||||
private void OnIconInvoked(object sender, NotificationIconInvokedEventArgs args)
|
||||
{
|
||||
if (args.PointerButton == PointerButton.Left)
|
||||
{
|
||||
Flyout.Show();
|
||||
}
|
||||
|
||||
if (args.PointerButton == PointerButton.Right)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void OnIconSourceChanged(object sender, EventArgs args) => UpdateIcons();
|
||||
|
||||
private void OnNotificationFlyoutXamlHostClosed(object sender, EventArgs args)
|
||||
{
|
||||
_notificationIconHelper?.Dispose();
|
||||
}
|
||||
|
||||
private void OnTaskbarChanged(object sender, EventArgs args) => SetFlyoutPlacement();
|
||||
|
||||
private void OnThemeChanged(object sender, SystemPersonalisationChangedEventArgs args)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void PrepareFlyoutHost()
|
||||
{
|
||||
_notificationFlyoutXamlHost = new NotificationFlyoutXamlHost();
|
||||
_notificationFlyoutXamlHost = new TransparentXamlHost<ContentControl>();
|
||||
_notificationFlyoutXamlHost.Closed += OnNotificationFlyoutXamlHostClosed;
|
||||
|
||||
var taskbarState = _taskbarHelper.GetCurrentState();
|
||||
_notificationFlyoutXamlHost.Left = taskbarState.Screen.WorkingArea.Left;
|
||||
_notificationFlyoutXamlHost.Top = taskbarState.Screen.WorkingArea.Top;
|
||||
|
||||
_notificationFlyoutXamlHost.Show();
|
||||
}
|
||||
|
||||
private void SetFlyoutPlacement()
|
||||
{
|
||||
var taskbarState = _taskbarHelper.GetCurrentState();
|
||||
|
||||
_notificationFlyoutXamlHost.Left = 0;
|
||||
_notificationFlyoutXamlHost.Top = 0;
|
||||
|
||||
double left;
|
||||
double top;
|
||||
|
||||
var dpiX = _notificationFlyoutXamlHost.DpiX();
|
||||
var dpiY = _notificationFlyoutXamlHost.DpiY();
|
||||
|
||||
NotificationFlyoutTaskbarPlacement flyoutTaskBarPlacement;
|
||||
switch (taskbarState.Placement)
|
||||
{
|
||||
case TaskbarPlacement.Left:
|
||||
flyoutTaskBarPlacement = NotificationFlyoutTaskbarPlacement.Left;
|
||||
top = taskbarState.Rect.Bottom / dpiX;
|
||||
left = taskbarState.Rect.Right / dpiY;
|
||||
break;
|
||||
|
||||
case TaskbarPlacement.Top:
|
||||
flyoutTaskBarPlacement = NotificationFlyoutTaskbarPlacement.Top;
|
||||
top = taskbarState.Rect.Bottom / dpiX;
|
||||
left = (_notificationFlyoutXamlHost.FlowDirection == FlowDirection.RightToLeft ? taskbarState.Rect.Left : taskbarState.Rect.Right) / dpiY;
|
||||
break;
|
||||
|
||||
case TaskbarPlacement.Right:
|
||||
flyoutTaskBarPlacement = NotificationFlyoutTaskbarPlacement.Right;
|
||||
top = taskbarState.Rect.Bottom / dpiX;
|
||||
left = taskbarState.Rect.Left / dpiY;
|
||||
break;
|
||||
|
||||
case TaskbarPlacement.Bottom:
|
||||
flyoutTaskBarPlacement = NotificationFlyoutTaskbarPlacement.Bottom;
|
||||
top = taskbarState.Rect.Top / dpiX;
|
||||
left = (_notificationFlyoutXamlHost.FlowDirection == FlowDirection.RightToLeft ? taskbarState.Rect.Left : taskbarState.Rect.Right) / dpiY;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
|
||||
Flyout.SetPlacement(left, top, 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()
|
||||
{
|
||||
//var content = GetHostContent();
|
||||
//if (content != null)
|
||||
//{
|
||||
// content.UpdateTheme(_systemPersonalisationHelper.IsColorPrevalence);
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
-282
@@ -1,282 +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<NotificationFlyoutPresenterHost>
|
||||
{
|
||||
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.PlacementChanged -= OnPlacementChanged;
|
||||
}
|
||||
|
||||
_flyout = flyout;
|
||||
_flyout.IconSourceChanged += OnIconSourceChanged;
|
||||
_flyout.ContextMenuChanged += OnContextMenuChanged;
|
||||
_flyout.PlacementChanged += OnPlacementChanged;
|
||||
|
||||
var content = GetHostContent();
|
||||
if (content != null)
|
||||
{
|
||||
content.SetOwningFlyout(_flyout);
|
||||
}
|
||||
|
||||
UpdateIcons();
|
||||
UpdateContextMenu();
|
||||
}
|
||||
|
||||
internal void ShowFlyout()
|
||||
{
|
||||
var content = GetHostContent();
|
||||
if (content != null)
|
||||
{
|
||||
var taskbarState = _taskbarHelper.GetCurrentState();
|
||||
var flyoutPlacement = FlyoutPlacementMode.Top;
|
||||
|
||||
switch (_flyout.Placement)
|
||||
{
|
||||
case NotificationFlyoutPlacement.Auto:
|
||||
flyoutPlacement = taskbarState.Placement switch
|
||||
{
|
||||
TaskbarPlacement.Left => FlyoutPlacementMode.Right,
|
||||
TaskbarPlacement.Top => FlyoutPlacementMode.Bottom,
|
||||
TaskbarPlacement.Right => FlyoutPlacementMode.Left,
|
||||
TaskbarPlacement.Bottom => FlyoutPlacementMode.Top,
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
break;
|
||||
}
|
||||
|
||||
Activate();
|
||||
content.ShowFlyout(flyoutPlacement);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnClosed(EventArgs args)
|
||||
{
|
||||
_notificationIconHelper.Dispose();
|
||||
|
||||
if (_contextMenuXamlHost == null) return;
|
||||
_contextMenuXamlHost.Close();
|
||||
}
|
||||
|
||||
protected override void OnContentLoaded()
|
||||
{
|
||||
PrepareNotificationIcon();
|
||||
PrepareTaskbar();
|
||||
UpdatePlacement();
|
||||
UpdateTheme();
|
||||
}
|
||||
|
||||
protected override void OnDeactivated(EventArgs args) => HideFlyout();
|
||||
|
||||
private void OnContextMenuChanged(object sender, EventArgs args) => UpdateContextMenu();
|
||||
|
||||
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 OnPlacementChanged(object sender, EventArgs args) => UpdatePlacement();
|
||||
|
||||
private void OnTaskbarChanged(object sender, EventArgs args) => UpdatePlacement();
|
||||
|
||||
private void OnThemeChanged(object sender, SystemPersonalisationChangedEventArgs args)
|
||||
{
|
||||
UpdateTheme();
|
||||
UpdateIcons();
|
||||
}
|
||||
|
||||
private void UpdateContextMenu()
|
||||
{
|
||||
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 UpdatePlacement()
|
||||
{
|
||||
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 width = WindowSize * this.DpiX();
|
||||
var height = WindowSize * this.DpiY();
|
||||
|
||||
double top = 0, left = 0;
|
||||
|
||||
var taskbarRect = taskbarState.Rect;
|
||||
var taskBarPlacement = taskbarState.Placement;
|
||||
var presenterPlacement = NotificationFlyoutPresenterPlacement.Bottom;
|
||||
|
||||
switch (_flyout.Placement)
|
||||
{
|
||||
case NotificationFlyoutPlacement.Auto:
|
||||
switch (taskBarPlacement)
|
||||
{
|
||||
case TaskbarPlacement.Left:
|
||||
presenterPlacement = NotificationFlyoutPresenterPlacement.Left;
|
||||
top = taskbarRect.Bottom - height;
|
||||
left = taskbarRect.Right;
|
||||
break;
|
||||
|
||||
case TaskbarPlacement.Top:
|
||||
presenterPlacement = NotificationFlyoutPresenterPlacement.Top;
|
||||
top = taskbarRect.Bottom;
|
||||
left = FlowDirection == FlowDirection.RightToLeft ? taskbarRect.Left : taskbarRect.Right - width;
|
||||
break;
|
||||
|
||||
case TaskbarPlacement.Right:
|
||||
presenterPlacement = NotificationFlyoutPresenterPlacement.Right;
|
||||
top = taskbarRect.Bottom - height;
|
||||
left = taskbarRect.Left - width;
|
||||
break;
|
||||
|
||||
case TaskbarPlacement.Bottom:
|
||||
presenterPlacement = NotificationFlyoutPresenterPlacement.Bottom;
|
||||
top = taskbarRect.Top - height;
|
||||
left = FlowDirection == FlowDirection.RightToLeft ? taskbarRect.Left : taskbarRect.Right - width;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
break;
|
||||
case NotificationFlyoutPlacement.Right:
|
||||
presenterPlacement = NotificationFlyoutPresenterPlacement.FullRight;
|
||||
switch (taskBarPlacement)
|
||||
{
|
||||
case TaskbarPlacement.Left:
|
||||
case TaskbarPlacement.Top:
|
||||
case TaskbarPlacement.Right:
|
||||
left = taskbarState.Screen.Bounds.Width - width;
|
||||
top = taskbarState.Screen.Bounds.Height - height;
|
||||
break;
|
||||
|
||||
case TaskbarPlacement.Bottom:
|
||||
top = taskbarRect.Top - height;
|
||||
left = FlowDirection == FlowDirection.RightToLeft ? taskbarRect.Left : taskbarRect.Right - width;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
this.SetWindowPosition(top, left, height, width);
|
||||
flyoutHost.UpdatePlacement(presenterPlacement);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace TheXamlGuy.NotificationFlyout.Wpf.UI.Controls
|
||||
{
|
||||
internal class TransparentXamlHost<TXamlContent> : XamlHost<TXamlContent> where TXamlContent : Windows.UI.Xaml.UIElement
|
||||
{
|
||||
internal const double WindowSize = 5;
|
||||
internal const double WindowSize = 0;
|
||||
|
||||
public TransparentXamlHost()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user