Enabled flyout transition to work at each taskbar placement, bottom, top, left, right

This commit is contained in:
Daniel Clark
2021-02-05 15:11:59 +00:00
parent 7e05f5ed75
commit a5d1d567a3
5 changed files with 147 additions and 57 deletions
@@ -121,6 +121,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="NotificationFlyoutPresenter\NotificationFlyoutPresenter.cs" /> <Compile Include="NotificationFlyoutPresenter\NotificationFlyoutPresenter.cs" />
<Compile Include="NotificationFlyoutPresenter\NotificationFlyoutPresenterTemplateSettings.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Properties\NotificationFlyout.Uwp.UI.Controls.rd.xml" /> <EmbeddedResource Include="Properties\NotificationFlyout.Uwp.UI.Controls.rd.xml" />
</ItemGroup> </ItemGroup>
@@ -1,21 +1,44 @@
using Windows.UI.Xaml.Controls; using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Controls.Primitives;
namespace NotificationFlyout.Uwp.UI.Controls namespace NotificationFlyout.Uwp.UI.Controls
{ {
public class NotificationFlyoutPresenter : ContentControl public class NotificationFlyoutPresenter : ContentControl
{ {
public static readonly DependencyProperty TemplateSettingsProperty =
DependencyProperty.Register(nameof(TemplateSettings),
typeof(NotificationFlyoutPresenterTemplateSettings), typeof(NotificationFlyoutPresenter),
new PropertyMetadata(0d));
private Grid _root; private Grid _root;
private NotificationFlyoutPresenterTemplateSettings _templateSettings;
public NotificationFlyoutPresenter() public NotificationFlyoutPresenter()
{ {
DefaultStyleKey = typeof(NotificationFlyoutPresenter); DefaultStyleKey = typeof(NotificationFlyoutPresenter);
_templateSettings = new NotificationFlyoutPresenterTemplateSettings();
SetValue(TemplateSettingsProperty, _templateSettings);
}
public NotificationFlyoutPresenterTemplateSettings TemplateSettings
{
get => (NotificationFlyoutPresenterTemplateSettings)GetValue(TemplateSettingsProperty);
set => SetValue(TemplateSettingsProperty, value);
}
public void SetOffset(double verticalOffset, double horizontalOffset)
{
if (_templateSettings == null) return;
_templateSettings.FromVerticalOffset = verticalOffset;
_templateSettings.FromHorizontalOffset = horizontalOffset;
} }
public void HideFlyout() public void HideFlyout()
{ {
if (_root == null) return; if (_root == null) return;
var flyout = FlyoutBase.GetAttachedFlyout(_root); FlyoutBase flyout = FlyoutBase.GetAttachedFlyout(_root);
flyout.Hide(); flyout.Hide();
} }
@@ -23,7 +46,11 @@ namespace NotificationFlyout.Uwp.UI.Controls
{ {
if (_root == null) return; if (_root == null) return;
var flyout = FlyoutBase.GetAttachedFlyout(_root); var flyout = FlyoutBase.GetAttachedFlyout(_root);
flyout.ShowAt(_root, new FlyoutShowOptions { Placement = placementMode, ShowMode = FlyoutShowMode.Standard }); flyout.ShowAt(_root, new FlyoutShowOptions
{
Placement = placementMode,
ShowMode = FlyoutShowMode.Standard
});
} }
protected override void OnApplyTemplate() protected override void OnApplyTemplate()
@@ -2,7 +2,19 @@
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">
<ResourceDictionary.ThemeDictionaries>
<ResourceDictionary x:Key="Default">
<StaticResource x:Key="NotificationFlyoutPresenterBackground" ResourceKey="AcrylicBackgroundFillColorDefaultBrush" />
</ResourceDictionary>
<ResourceDictionary x:Key="HighContrast">
<StaticResource x:Key="NotificationFlyoutPresenterBackground" ResourceKey="SystemControlPageBackgroundChromeMediumLowBrush" />
</ResourceDictionary>
<ResourceDictionary x:Key="Light">
<StaticResource x:Key="NotificationFlyoutPresenterBackground" ResourceKey="AcrylicBackgroundFillColorDefaultBrush" />
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
<Style TargetType="controls:NotificationFlyoutPresenter"> <Style TargetType="controls:NotificationFlyoutPresenter">
<Setter Property="Background" Value="{StaticResource NotificationFlyoutPresenterBackground}" />
<Setter Property="Template"> <Setter Property="Template">
<Setter.Value> <Setter.Value>
<ControlTemplate TargetType="controls:NotificationFlyoutPresenter"> <ControlTemplate TargetType="controls:NotificationFlyoutPresenter">
@@ -12,43 +24,41 @@
<Flyout.FlyoutPresenterStyle> <Flyout.FlyoutPresenterStyle>
<Style TargetType="FlyoutPresenter"> <Style TargetType="FlyoutPresenter">
<Setter Property="BorderThickness" Value="0" /> <Setter Property="BorderThickness" Value="0" />
<Setter Property="Template"> <Setter Property="Background" Value="Transparent" />
<Setter.Value> <Setter Property="IsDefaultShadowEnabled" Value="False" />
<ControlTemplate TargetType="FlyoutPresenter"> <Setter Property="Padding" Value="0" />
<Border <Setter Property="Margin" Value="0" />
Background="{TemplateBinding Background}"
BackgroundSizing="InnerBorderEdge"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Border.Transitions>
<TransitionCollection>
<EntranceThemeTransition FromHorizontalOffset="200" FromVerticalOffset="0" />
</TransitionCollection>
</Border.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}">
<ContentPresenter
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style> </Style>
</Flyout.FlyoutPresenterStyle> </Flyout.FlyoutPresenterStyle>
<ContentControl Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" /> <Border
Padding="{TemplateBinding Padding}"
Background="{TemplateBinding Background}"
BackgroundSizing="OuterBorderEdge"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<Border.Transitions>
<TransitionCollection>
<EntranceThemeTransition FromHorizontalOffset="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.FromHorizontalOffset, Mode=TwoWay}" FromVerticalOffset="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.FromVerticalOffset, Mode=TwoWay}" />
</TransitionCollection>
</Border.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}">
<ContentPresenter
Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
ContentTransitions="{TemplateBinding ContentTransitions}" />
</ScrollViewer>
</Border>
</Flyout> </Flyout>
</FlyoutBase.AttachedFlyout> </FlyoutBase.AttachedFlyout>
</Grid> </Grid>
@@ -0,0 +1,29 @@
using Windows.UI.Xaml;
namespace NotificationFlyout.Uwp.UI.Controls
{
public class NotificationFlyoutPresenterTemplateSettings : DependencyObject
{
public static readonly DependencyProperty FromHorizontalOffsetProperty =
DependencyProperty.Register(nameof(FromHorizontalOffset),
typeof(double), typeof(NotificationFlyoutPresenterTemplateSettings),
new PropertyMetadata(0d));
public static readonly DependencyProperty FromVerticalOffsetProperty =
DependencyProperty.Register(nameof(FromVerticalOffset),
typeof(double), typeof(NotificationFlyoutPresenterTemplateSettings),
new PropertyMetadata(0d));
public double FromHorizontalOffset
{
get => (double)GetValue(FromHorizontalOffsetProperty);
set => SetValue(FromHorizontalOffsetProperty, value);
}
public double FromVerticalOffset
{
get => (double)GetValue(FromVerticalOffsetProperty);
set => SetValue(FromVerticalOffsetProperty, value);
}
}
}
@@ -3,7 +3,9 @@ using NotificationFlyout.Uwp.UI.Controls;
using NotificationFlyout.Wpf.UI.Extensions; using NotificationFlyout.Wpf.UI.Extensions;
using NotificationFlyout.Wpf.UI.Helpers; using NotificationFlyout.Wpf.UI.Helpers;
using System; using System;
using System.Drawing;
using System.Windows; using System.Windows;
using System.Windows.Media;
using Windows.UI.Xaml.Controls.Primitives; using Windows.UI.Xaml.Controls.Primitives;
namespace NotificationFlyout.Wpf.UI.Controls namespace NotificationFlyout.Wpf.UI.Controls
@@ -18,7 +20,6 @@ namespace NotificationFlyout.Wpf.UI.Controls
private WindowsXamlHost _host; private WindowsXamlHost _host;
private NotificationIconHelper _notificationIconHelper; private NotificationIconHelper _notificationIconHelper;
private bool _taskbarChanged;
private TaskbarHelper _taskbarHelper; private TaskbarHelper _taskbarHelper;
public NotificationFlyoutXamlHost() public NotificationFlyoutXamlHost()
@@ -49,10 +50,12 @@ namespace NotificationFlyout.Wpf.UI.Controls
_notificationIconHelper.SetIcon(handle); _notificationIconHelper.SetIcon(handle);
} }
private const double MaximumOffset = 80;
internal void ShowFlyout() internal void ShowFlyout()
{ {
var notificationFlyoutPresenter = GetNotificationFlyoutPresenter(); var flyoutPresenter = GetNotificationFlyoutPresenter();
if (notificationFlyoutPresenter != null) if (flyoutPresenter != null)
{ {
var taskbarState = _taskbarHelper.GetCurrentState(); var taskbarState = _taskbarHelper.GetCurrentState();
var flyoutPlacement = taskbarState.Position switch var flyoutPlacement = taskbarState.Position switch
@@ -65,15 +68,10 @@ namespace NotificationFlyout.Wpf.UI.Controls
}; };
Activate(); Activate();
notificationFlyoutPresenter.ShowFlyout(flyoutPlacement); flyoutPresenter.ShowFlyout(flyoutPlacement);
} }
} }
private void SetFlyoutPlacement(FlyoutPlacementMode placementMode)
{
var notificationFlyoutPresenter = GetNotificationFlyoutPresenter();
}
private static void OnFlyoutContentPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs) private static void OnFlyoutContentPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{ {
var sender = dependencyObject as NotificationFlyoutXamlHost; var sender = dependencyObject as NotificationFlyoutXamlHost;
@@ -87,10 +85,10 @@ namespace NotificationFlyout.Wpf.UI.Controls
private void OnFlyoutContentPropertyChanged() private void OnFlyoutContentPropertyChanged()
{ {
var flyoutContentControl = GetNotificationFlyoutPresenter(); var flyoutPresenter = GetNotificationFlyoutPresenter();
if (flyoutContentControl != null) if (flyoutPresenter != null)
{ {
flyoutContentControl.Content = FlyoutContent; flyoutPresenter.Content = FlyoutContent;
} }
} }
@@ -109,8 +107,6 @@ namespace NotificationFlyout.Wpf.UI.Controls
private void OnTaskbarChanged(object sender, EventArgs args) private void OnTaskbarChanged(object sender, EventArgs args)
{ {
_taskbarChanged = true;
var taskbarState = _taskbarHelper.GetCurrentState(); var taskbarState = _taskbarHelper.GetCurrentState();
Left = taskbarState.Screen.WorkingArea.Left; Left = taskbarState.Screen.WorkingArea.Left;
Top = taskbarState.Screen.WorkingArea.Top; Top = taskbarState.Screen.WorkingArea.Top;
@@ -125,6 +121,7 @@ namespace NotificationFlyout.Wpf.UI.Controls
WindowStyle = WindowStyle.None; WindowStyle = WindowStyle.None;
ResizeMode = ResizeMode.NoResize; ResizeMode = ResizeMode.NoResize;
AllowsTransparency = true; AllowsTransparency = true;
Background = new SolidColorBrush(Colors.Transparent);
Height = 0; Height = 0;
Width = 0; Width = 0;
} }
@@ -156,6 +153,7 @@ namespace NotificationFlyout.Wpf.UI.Controls
private void UpdateWindow() private void UpdateWindow()
{ {
var flyoutPresenter = GetNotificationFlyoutPresenter();
var taskbarState = _taskbarHelper.GetCurrentState(); var taskbarState = _taskbarHelper.GetCurrentState();
var screen = Screen.FromHandle(this.GetHandle()); var screen = Screen.FromHandle(this.GetHandle());
@@ -164,25 +162,50 @@ namespace NotificationFlyout.Wpf.UI.Controls
var windowWidth = DesiredSize.Width * this.DpiX(); var windowWidth = DesiredSize.Width * this.DpiX();
var windowHeight = DesiredSize.Height * this.DpiY(); var windowHeight = DesiredSize.Height * this.DpiY();
double top;
double left;
double height;
double width;
double verticalOffset = 0;
double horizontalOffset = 0;
var taskbarRect = taskbarState.Rect; var taskbarRect = taskbarState.Rect;
var flyoutPlacement = FlyoutPlacementMode.Auto;
switch (taskbarState.Position) switch (taskbarState.Position)
{ {
case TaskbarPosition.Left: case TaskbarPosition.Left:
this.SetWindowPosition(taskbarRect.Bottom - windowHeight, taskbarRect.Right, windowHeight, windowWidth); top = taskbarRect.Bottom - windowHeight;
left = taskbarRect.Right;
height = windowHeight;
width = windowWidth;
horizontalOffset = -MaximumOffset;
break; break;
case TaskbarPosition.Top: case TaskbarPosition.Top:
this.SetWindowPosition(taskbarRect.Bottom, FlowDirection == FlowDirection.RightToLeft ? taskbarRect.Left : taskbarRect.Right - windowWidth, windowHeight, windowWidth); top = taskbarRect.Bottom;
left = FlowDirection == FlowDirection.RightToLeft ? taskbarRect.Left : taskbarRect.Right - windowWidth;
height = windowHeight;
width = windowWidth;
verticalOffset = -MaximumOffset;
break; break;
case TaskbarPosition.Right: case TaskbarPosition.Right:
this.SetWindowPosition(taskbarRect.Bottom - windowHeight, taskbarRect.Left - windowWidth, windowHeight, windowWidth); top = taskbarRect.Bottom - windowHeight;
left = taskbarRect.Left - windowWidth;
height = windowHeight;
width = windowWidth;
horizontalOffset = MaximumOffset;
break; break;
case TaskbarPosition.Bottom: case TaskbarPosition.Bottom:
this.SetWindowPosition(taskbarRect.Top - windowHeight, FlowDirection == FlowDirection.RightToLeft ? taskbarRect.Left : taskbarRect.Right - windowWidth, windowHeight, windowWidth); top = taskbarRect.Top - windowHeight;
left = FlowDirection == FlowDirection.RightToLeft ? taskbarRect.Left : taskbarRect.Right - windowWidth;
height = windowHeight;
width = windowWidth;
verticalOffset = MaximumOffset;
break; break;
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
this.SetWindowPosition(top, left, height, width);
flyoutPresenter.SetOffset(verticalOffset, horizontalOffset);
} }
} }
} }