aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/StubsUtils/Notifications.Wpf
diff options
context:
space:
mode:
authorRoy Ben Shabat <Roy.mail.net@gmail.com>2020-12-18 06:05:35 +0200
committerRoy Ben Shabat <Roy.mail.net@gmail.com>2020-12-18 06:05:35 +0200
commit54ebb63d6bfca47737abd6766cf82245472a6aef (patch)
tree42e5e7d64aa191916d4e40a32f646cb958f5812b /Software/Visual_Studio/StubsUtils/Notifications.Wpf
parent86bbaee1a545f08dc7bfb4efe5f4696d6e4dccdd (diff)
downloadTango-54ebb63d6bfca47737abd6766cf82245472a6aef.tar.gz
Tango-54ebb63d6bfca47737abd6766cf82245472a6aef.zip
StubsUtils Win10 notification.
Diffstat (limited to 'Software/Visual_Studio/StubsUtils/Notifications.Wpf')
-rw-r--r--Software/Visual_Studio/StubsUtils/Notifications.Wpf/Controls/Notification.cs113
-rw-r--r--Software/Visual_Studio/StubsUtils/Notifications.Wpf/Controls/NotificationArea.cs150
-rw-r--r--Software/Visual_Studio/StubsUtils/Notifications.Wpf/Controls/ReversibleStackPanel.cs50
-rw-r--r--Software/Visual_Studio/StubsUtils/Notifications.Wpf/INotificationManager.cs9
-rw-r--r--Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationContent.cs24
-rw-r--r--Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationManager.cs64
-rw-r--r--Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationTemplateSelector.cs44
-rw-r--r--Software/Visual_Studio/StubsUtils/Notifications.Wpf/Notifications.Wpf.csproj104
-rw-r--r--Software/Visual_Studio/StubsUtils/Notifications.Wpf/Notifications.Wpf.nuspec21
-rw-r--r--Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationsOverlayWindow.xaml18
-rw-r--r--Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationsOverlayWindow.xaml.cs16
-rw-r--r--Software/Visual_Studio/StubsUtils/Notifications.Wpf/Properties/AssemblyInfo.cs39
-rw-r--r--Software/Visual_Studio/StubsUtils/Notifications.Wpf/Themes/Generic.xaml156
-rw-r--r--Software/Visual_Studio/StubsUtils/Notifications.Wpf/Utils/VisualTreeHelperExtensions.cs28
-rw-r--r--Software/Visual_Studio/StubsUtils/Notifications.Wpf/pack.bat3
15 files changed, 839 insertions, 0 deletions
diff --git a/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Controls/Notification.cs b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Controls/Notification.cs
new file mode 100644
index 000000000..58ab8aaa1
--- /dev/null
+++ b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Controls/Notification.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using Notifications.Wpf.Utils;
+
+namespace Notifications.Wpf.Controls
+{
+ [TemplatePart(Name = "PART_CloseButton", Type = typeof(Button))]
+ public class Notification : ContentControl
+ {
+ private TimeSpan _closingAnimationTime = TimeSpan.Zero;
+
+ public bool IsClosing { get; set; }
+
+ public static readonly RoutedEvent NotificationCloseInvokedEvent = EventManager.RegisterRoutedEvent(
+ "NotificationCloseInvoked", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Notification));
+
+ public static readonly RoutedEvent NotificationClosedEvent = EventManager.RegisterRoutedEvent(
+ "NotificationClosed", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(Notification));
+
+ static Notification()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(Notification),
+ new FrameworkPropertyMetadata(typeof(Notification)));
+ }
+
+ public event RoutedEventHandler NotificationCloseInvoked
+ {
+ add { AddHandler(NotificationCloseInvokedEvent, value); }
+ remove { RemoveHandler(NotificationCloseInvokedEvent, value); }
+ }
+
+ public event RoutedEventHandler NotificationClosed
+ {
+ add { AddHandler(NotificationClosedEvent, value); }
+ remove { RemoveHandler(NotificationClosedEvent, value); }
+ }
+
+ public static bool GetCloseOnClick(DependencyObject obj)
+ {
+ return (bool)obj.GetValue(CloseOnClickProperty);
+ }
+
+ public static void SetCloseOnClick(DependencyObject obj, bool value)
+ {
+ obj.SetValue(CloseOnClickProperty, value);
+ }
+
+ public static readonly DependencyProperty CloseOnClickProperty =
+ DependencyProperty.RegisterAttached("CloseOnClick", typeof(bool), typeof(Notification), new FrameworkPropertyMetadata(false,CloseOnClickChanged));
+
+ private static void CloseOnClickChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
+ {
+ var button = dependencyObject as Button;
+ if (button == null)
+ {
+ return;
+ }
+
+ var value = (bool)dependencyPropertyChangedEventArgs.NewValue;
+
+ if (value)
+ {
+ button.Click += (sender, args) =>
+ {
+ var notification = VisualTreeHelperExtensions.GetParent<Notification>(button);
+ notification?.Close();
+ };
+ }
+ }
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+ var closeButton = GetTemplateChild("PART_CloseButton") as Button;
+ if (closeButton != null)
+ closeButton.Click += OnCloseButtonOnClick;
+
+ var storyboards = Template.Triggers.OfType<EventTrigger>().FirstOrDefault(t => t.RoutedEvent == NotificationCloseInvokedEvent)?.Actions.OfType<BeginStoryboard>().Select(a => a.Storyboard);
+ _closingAnimationTime = new TimeSpan(storyboards?.Max(s => Math.Min((s.Duration.HasTimeSpan ? s.Duration.TimeSpan + (s.BeginTime ?? TimeSpan.Zero) : TimeSpan.MaxValue).Ticks, s.Children.Select(ch => ch.Duration.TimeSpan + (s.BeginTime ?? TimeSpan.Zero)).Max().Ticks)) ?? 0);
+
+ }
+
+ private void OnCloseButtonOnClick(object sender, RoutedEventArgs args)
+ {
+ var button = sender as Button;
+ if (button == null) return;
+
+ button.Click -= OnCloseButtonOnClick;
+ Close();
+ }
+
+ //TODO: .NET40
+ public async void Close()
+ {
+ if (IsClosing)
+ {
+ return;
+ }
+
+ IsClosing = true;
+
+ RaiseEvent(new RoutedEventArgs(NotificationCloseInvokedEvent));
+ await Task.Delay(_closingAnimationTime);
+ RaiseEvent(new RoutedEventArgs(NotificationClosedEvent));
+ }
+ }
+}
diff --git a/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Controls/NotificationArea.cs b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Controls/NotificationArea.cs
new file mode 100644
index 000000000..7163e46f4
--- /dev/null
+++ b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Controls/NotificationArea.cs
@@ -0,0 +1,150 @@
+using System;
+using System.Collections;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+using System.Windows.Threading;
+
+namespace Notifications.Wpf.Controls
+{
+ public class NotificationArea : Control
+ {
+
+
+
+ public NotificationPosition Position
+ {
+ get { return (NotificationPosition)GetValue(PositionProperty); }
+ set { SetValue(PositionProperty, value); }
+ }
+
+ // Using a DependencyProperty as the backing store for Position. This enables animation, styling, binding, etc...
+ public static readonly DependencyProperty PositionProperty =
+ DependencyProperty.Register("Position", typeof(NotificationPosition), typeof(NotificationArea), new PropertyMetadata(NotificationPosition.BottomRight));
+
+
+ public int MaxItems
+ {
+ get { return (int)GetValue(MaxItemsProperty); }
+ set { SetValue(MaxItemsProperty, value); }
+ }
+
+ public static readonly DependencyProperty MaxItemsProperty =
+ DependencyProperty.Register("MaxItems", typeof(int), typeof(NotificationArea), new PropertyMetadata(int.MaxValue));
+
+ private IList _items;
+
+ public NotificationArea()
+ {
+ NotificationManager.AddArea(this);
+ }
+
+ static NotificationArea()
+ {
+ DefaultStyleKeyProperty.OverrideMetadata(typeof(NotificationArea),
+ new FrameworkPropertyMetadata(typeof(NotificationArea)));
+ }
+
+ public override void OnApplyTemplate()
+ {
+ base.OnApplyTemplate();
+ var itemsControl = GetTemplateChild("PART_Items") as Panel;
+ _items = itemsControl?.Children;
+ }
+
+#if NET40
+ public void Show(object content, TimeSpan expirationTime, Action onClick, Action onClose)
+#else
+ public async void Show(object content, TimeSpan expirationTime, Action onClick, Action onClose)
+#endif
+ {
+ var notification = new Notification
+ {
+ Content = content
+ };
+
+ notification.MouseLeftButtonDown += (sender, args) =>
+ {
+ if (onClick != null)
+ {
+ onClick.Invoke();
+ (sender as Notification)?.Close();
+ }
+ };
+ notification.NotificationClosed += (sender, args) => onClose?.Invoke();
+ notification.NotificationClosed += OnNotificationClosed;
+
+ if (!IsLoaded)
+ {
+ return;
+ }
+
+ var w = Window.GetWindow(this);
+ var x = PresentationSource.FromVisual(w);
+ if (x == null)
+ {
+ return;
+ }
+
+ lock (_items)
+ {
+ _items.Add(notification);
+
+ if (_items.OfType<Notification>().Count(i => !i.IsClosing) > MaxItems)
+ {
+ _items.OfType<Notification>().First(i => !i.IsClosing).Close();
+ }
+ }
+
+#if NET40
+ DelayExecute(expirationTime, () =>
+ {
+#else
+ if (expirationTime == TimeSpan.MaxValue)
+ {
+ return;
+ }
+ await Task.Delay(expirationTime);
+#endif
+ notification.Close();
+#if NET40
+ });
+#endif
+ }
+
+ private void OnNotificationClosed(object sender, RoutedEventArgs routedEventArgs)
+ {
+ var notification = sender as Notification;
+ _items.Remove(notification);
+ }
+
+#if NET40
+ private static void DelayExecute(TimeSpan delay, Action actionToExecute)
+ {
+ if (actionToExecute != null)
+ {
+ var timer = new DispatcherTimer
+ {
+ Interval = delay
+ };
+ timer.Tick += (sender, args) =>
+ {
+ timer.Stop();
+ actionToExecute();
+ };
+ timer.Start();
+ }
+ }
+#endif
+ }
+
+ public enum NotificationPosition
+ {
+ TopLeft,
+ TopRight,
+ BottomLeft,
+ BottomRight
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Controls/ReversibleStackPanel.cs b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Controls/ReversibleStackPanel.cs
new file mode 100644
index 000000000..f13126a29
--- /dev/null
+++ b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Controls/ReversibleStackPanel.cs
@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace Notifications.Wpf.Controls
+{
+ public class ReversibleStackPanel : StackPanel
+ {
+
+
+ public bool ReverseOrder
+ {
+ get { return (bool)GetValue(ReverseOrderProperty); }
+ set { SetValue(ReverseOrderProperty, value); }
+ }
+
+ public static readonly DependencyProperty ReverseOrderProperty =
+ DependencyProperty.Register("ReverseOrder", typeof(bool), typeof(ReversibleStackPanel), new PropertyMetadata(false));
+
+
+ protected override Size ArrangeOverride(Size arrangeSize)
+ {
+ double x = 0;
+ double y = 0;
+
+ IEnumerable<UIElement> children = ReverseOrder ? InternalChildren.Cast<UIElement>().Reverse() : InternalChildren.Cast<UIElement>();
+ foreach (UIElement child in children)
+ {
+ Size size;
+
+ if (Orientation == Orientation.Horizontal)
+ {
+ size = new Size(child.DesiredSize.Width, Math.Max(arrangeSize.Height, child.DesiredSize.Height));
+ child.Arrange(new Rect(new Point(x, y), size));
+ x += size.Width;
+ }
+ else
+ {
+ size = new Size(Math.Max(arrangeSize.Width, child.DesiredSize.Width), child.DesiredSize.Height);
+ child.Arrange(new Rect(new Point(x, y), size));
+ y += size.Height;
+ }
+ }
+
+ return Orientation == Orientation.Horizontal ? new Size(x, arrangeSize.Height) : new Size(arrangeSize.Width, y);
+ }
+ }
+}
diff --git a/Software/Visual_Studio/StubsUtils/Notifications.Wpf/INotificationManager.cs b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/INotificationManager.cs
new file mode 100644
index 000000000..736a46e2b
--- /dev/null
+++ b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/INotificationManager.cs
@@ -0,0 +1,9 @@
+using System;
+
+namespace Notifications.Wpf
+{
+ public interface INotificationManager
+ {
+ void Show(object content, string areaName = "", TimeSpan? expirationTime = null, Action onClick = null, Action onClose = null);
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationContent.cs b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationContent.cs
new file mode 100644
index 000000000..3b942374b
--- /dev/null
+++ b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationContent.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Notifications.Wpf
+{
+ public class NotificationContent
+ {
+ public string Title { get; set; }
+ public string Message { get; set; }
+
+ public NotificationType Type { get; set; }
+ }
+
+ public enum NotificationType
+ {
+ Information,
+ Success,
+ Warning,
+ Error
+ }
+}
diff --git a/Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationManager.cs b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationManager.cs
new file mode 100644
index 000000000..0e8091e8a
--- /dev/null
+++ b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationManager.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
+using System.Windows.Threading;
+using Notifications.Wpf.Controls;
+
+namespace Notifications.Wpf
+{
+ public class NotificationManager : INotificationManager
+ {
+ private readonly Dispatcher _dispatcher;
+ private static readonly List<NotificationArea> Areas = new List<NotificationArea>();
+ private static NotificationsOverlayWindow _window;
+
+ public NotificationManager(Dispatcher dispatcher = null)
+ {
+ if (dispatcher == null)
+ {
+ dispatcher = Application.Current?.Dispatcher ?? Dispatcher.CurrentDispatcher;
+ }
+
+ _dispatcher = dispatcher;
+ }
+
+ public void Show(object content, string areaName = "", TimeSpan? expirationTime = null, Action onClick = null,
+ Action onClose = null)
+ {
+ if (!_dispatcher.CheckAccess())
+ {
+ _dispatcher.BeginInvoke(
+ new Action(() => Show(content, areaName, expirationTime, onClick, onClose)));
+ return;
+ }
+
+ if (expirationTime == null) expirationTime = TimeSpan.FromSeconds(5);
+
+ if (areaName == string.Empty && _window == null)
+ {
+ var workArea = SystemParameters.WorkArea;
+
+ _window = new NotificationsOverlayWindow
+ {
+ Left = workArea.Left,
+ Top = workArea.Top,
+ Width = workArea.Width,
+ Height = workArea.Height
+ };
+
+ _window.Show();
+ }
+
+ foreach (var area in Areas.Where(a => a.Name == areaName))
+ {
+ area.Show(content, (TimeSpan) expirationTime, onClick, onClose);
+ }
+ }
+
+ internal static void AddArea(NotificationArea area)
+ {
+ Areas.Add(area);
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationTemplateSelector.cs b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationTemplateSelector.cs
new file mode 100644
index 000000000..aab11a7fa
--- /dev/null
+++ b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationTemplateSelector.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+
+namespace Notifications.Wpf
+{
+ public class NotificationTemplateSelector : DataTemplateSelector
+ {
+ private DataTemplate _defaultStringTemplate;
+ private DataTemplate _defaultNotificationTemplate;
+
+ private void GetTemplatesFromResources(FrameworkElement container)
+ {
+ _defaultStringTemplate =
+ container?.FindResource("DefaultStringTemplate") as DataTemplate;
+ _defaultNotificationTemplate =
+ container?.FindResource("DefaultNotificationTemplate") as DataTemplate;
+ }
+
+ public override DataTemplate SelectTemplate(object item, DependencyObject container)
+ {
+ if (_defaultStringTemplate == null && _defaultNotificationTemplate == null)
+ {
+ GetTemplatesFromResources((FrameworkElement)container);
+ }
+
+ if (item is string)
+ {
+ return _defaultStringTemplate;
+ }
+ if (item is NotificationContent)
+ {
+ return _defaultNotificationTemplate;
+ }
+
+ return base.SelectTemplate(item, container);
+
+ }
+ }
+} \ No newline at end of file
diff --git a/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Notifications.Wpf.csproj b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Notifications.Wpf.csproj
new file mode 100644
index 000000000..0e5db5694
--- /dev/null
+++ b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Notifications.Wpf.csproj
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProjectGuid>{5C9A4F46-263D-4C23-B361-F09E14BB109E}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Notifications.Wpf</RootNamespace>
+ <AssemblyName>Notifications.Wpf</AssemblyName>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ <PlatformTarget>AnyCPU</PlatformTarget>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.0|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <DefineConstants>TRACE;NET40</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <OutputPath>bin\Release\net40\</OutputPath>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <DefineConstants>TRACE;NET45</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <OutputPath>bin\Release\net45\</OutputPath>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.6.1|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <DefineConstants>TRACE;NET461</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <OutputPath>bin\Release\net461\</OutputPath>
+ <TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Xaml" />
+ <Reference Include="System.Xml" />
+ <Reference Include="WindowsBase" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Controls\Notification.cs" />
+ <Compile Include="Controls\NotificationArea.cs" />
+ <Compile Include="Controls\ReversibleStackPanel.cs" />
+ <Compile Include="INotificationManager.cs" />
+ <Compile Include="NotificationContent.cs" />
+ <Compile Include="NotificationManager.cs" />
+ <Compile Include="NotificationTemplateSelector.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="NotificationsOverlayWindow.xaml.cs">
+ <DependentUpon>NotificationsOverlayWindow.xaml</DependentUpon>
+ </Compile>
+ <Compile Include="Utils\VisualTreeHelperExtensions.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Page Include="Themes\Generic.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="NotificationsOverlayWindow.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="Notifications.Wpf.nuspec" />
+ <None Include="pack.bat" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>-->
+ <Target Name="AfterBuild">
+ <GetAssemblyIdentity AssemblyFiles="$(OutputPath)$(AssemblyName).dll">
+ <Output TaskParameter="Assemblies" ItemName="OutputAssemblyInfo" />
+ </GetAssemblyIdentity>
+ <Message Text="Info: %(OutputAssemblyInfo.Version)" />
+ </Target>
+ <Target Name="Package">
+ <!-- Ensure the Package directory exists for this project -->
+ <RemoveDir Directories="NuGet" />
+ <MakeDir Directories="NuGet" />
+ <!-- Package the project -->
+ <Exec WorkingDirectory="$(BuildDir)" Command="NuGet.exe pack -OutputDir &quot;NuGet&quot; -Properties &quot;Configuration=$(Configuration)&quot;" />
+ </Target>
+</Project> \ No newline at end of file
diff --git a/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Notifications.Wpf.nuspec b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Notifications.Wpf.nuspec
new file mode 100644
index 000000000..c4f36a497
--- /dev/null
+++ b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Notifications.Wpf.nuspec
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<package >
+ <metadata>
+ <id>$id$</id>
+ <version>$version$</version>
+ <title>$title$</title>
+ <authors>$author$</authors>
+ <owners>$author$</owners>
+ <projectUrl>https://github.com/Federerer/Notifications.Wpf</projectUrl>
+ <requireLicenseAcceptance>false</requireLicenseAcceptance>
+ <description>$description$</description>
+ <releaseNotes>First release.</releaseNotes>
+ <copyright>Copyright 2017</copyright>
+ <tags>Toast Notifications WPF</tags>
+ </metadata>
+ <files>
+ <file src="bin\Release\net40\$id$.dll" target="lib\net40\" />
+ <file src="bin\Release\net45\$id$.dll" target="lib\net45\" />
+ <file src="bin\Release\net461\$id$.dll" target="lib\net461\" />
+ </files>
+</package> \ No newline at end of file
diff --git a/Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationsOverlayWindow.xaml b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationsOverlayWindow.xaml
new file mode 100644
index 000000000..1c80f11ec
--- /dev/null
+++ b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationsOverlayWindow.xaml
@@ -0,0 +1,18 @@
+<Window x:Class="Notifications.Wpf.NotificationsOverlayWindow"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ xmlns:controls1="clr-namespace:Notifications.Wpf.Controls"
+ mc:Ignorable="d"
+ Title="ToastWindow"
+ Background="Transparent"
+ ShowInTaskbar="False"
+ WindowStyle="None"
+ AllowsTransparency="True"
+ Topmost="True"
+ ShowActivated="False"
+ d:DesignWidth="900"
+ d:DesignHeight="600">
+ <controls1:NotificationArea Position="BottomRight" Margin="8"/>
+</Window>
diff --git a/Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationsOverlayWindow.xaml.cs b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationsOverlayWindow.xaml.cs
new file mode 100644
index 000000000..ecb595694
--- /dev/null
+++ b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/NotificationsOverlayWindow.xaml.cs
@@ -0,0 +1,16 @@
+using System.Windows;
+
+namespace Notifications.Wpf
+{
+ /// <summary>
+ /// Interaction logic for ToastWindow.xaml
+ /// </summary>
+ public partial class NotificationsOverlayWindow : Window
+ {
+ public NotificationsOverlayWindow()
+ {
+ InitializeComponent();
+ }
+
+ }
+}
diff --git a/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Properties/AssemblyInfo.cs b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Properties/AssemblyInfo.cs
new file mode 100644
index 000000000..d0022abe6
--- /dev/null
+++ b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Properties/AssemblyInfo.cs
@@ -0,0 +1,39 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Notifications.Wpf")]
+[assembly: AssemblyDescription("Toast notifications for WPF")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Adrian Gaś")]
+[assembly: AssemblyProduct("Notifications.Wpf")]
+[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("5c9a4f46-263d-4c23-b361-f09e14bb109e")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyInformationalVersion("0.1.0")]
+[assembly: AssemblyVersion("0.1.0")]
+[assembly: AssemblyFileVersion("0.1.0")] \ No newline at end of file
diff --git a/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Themes/Generic.xaml b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Themes/Generic.xaml
new file mode 100644
index 000000000..76de0e6d7
--- /dev/null
+++ b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Themes/Generic.xaml
@@ -0,0 +1,156 @@
+<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:controls="clr-namespace:Notifications.Wpf.Controls"
+ xmlns:system="clr-namespace:System;assembly=mscorlib"
+ xmlns:wpf="clr-namespace:Notifications.Wpf">
+
+ <Path x:Key="ErrorIcon" Data="M 2.6874995 2.8246546e-7 -4.7683716e-7 2.6855503 5.3007795 7.9863303 -4.7683716e-7 13.28516 2.6874995 15.97266 l 5.29883 -5.30079 5.3007805 5.30079 2.68554 -2.6875 -5.29882 -5.2988297 5.29882 -5.30078 L 13.28711 2.8246546e-7 7.9863295 5.2988303 2.6874995 2.8246546e-7 Z" Fill="White" x:Shared="False"/>
+ <Path x:Key="SuccessIcon" Data="M 15.56055 5.9323048e-7 7.53125 10.197261 2.73242 5.2304706 0 7.8710906 7.82422 15.968751 18.54492 2.3515606 15.56055 5.9323048e-7 Z" Fill="White" x:Shared="False"/>
+ <Path x:Key="InfoIcon" Data="M 10.968748 8.9809305e-8 C 4.9320181 8.9809305e-8 -1.9073487e-6 4.9320201 -1.9073487e-6 10.96875 c 0 6.03672 4.9322600073487 10.9668 10.9687499073487 10.9668 6.03648 0 10.96875 -4.93008 10.96875 -10.9668 C 21.937498 4.9320201 17.005458 8.9809305e-8 10.968748 8.9809305e-8 Z m 0 2.000000010190695 c 4.95043 0 8.96875 4.0183 8.96875 8.9687499 0 4.95044 -4.01809 8.9668 -8.96875 8.9668 -4.9506899 0 -8.9687499 -4.01636 -8.9687499 -8.9668 0 -4.9504499 4.0183 -8.9687499 8.9687499 -8.9687499 z m -1.4999999 2.49805 0 3 2.9999999 0 0 -3 -2.9999999 0 z m 0 4.4707 0 8.9101599 2.9999999 0 0 -8.9101599 -2.9999999 0 z" Fill="White" x:Shared="False"/>
+ <Path x:Key="WarningIcon" Data="M 12.414089 4.6396565e-7 C 12.128679 -9.5360343e-6 11.832699 0.06810046 11.574249 0.19726046 c -0.29252 0.14627 -0.55012 0.39584 -0.70899 0.67383 l -0.002 0.002 L 0.22067905 19.77348 l -0.0117 0.0234 C 0.08326905 20.04831 -9.5367432e-7 20.33976 -9.5367432e-7 20.64844 c 0 0.30629 0.0851000036743 0.62597 0.23633000367432 0.89063 0.13469 0.2357 0.31957 0.44504 0.5332 0.60937 l 0.0137 0.0117 0.0156 0.01 C 1.076789 22.36867 1.440719 22.48654 1.785149 22.48654 l 21.28516 0 c 0.3398 0 0.70907 -0.12364 0.98828 -0.33398 0.2208 -0.16158 0.42089 -0.3689 0.56055 -0.61328 0.15122 -0.26466 0.23633 -0.58434 0.23633 -0.89063 0 -0.30868 -0.0852 -0.60013 -0.21094 -0.85156 l -0.01 -0.0234 -10.66992 -18.90038954 -0.002 -0.002 c -0.15887 -0.27808 -0.41633 -0.52756 -0.70899 -0.67383 -0.25845 -0.12918 -0.55443 -0.19726999603 -0.83984 -0.19725999603 z m 0 2.19531003603435 10.32617 18.2910095 -20.625 0 10.29883 -18.2910095 z m -1.48633 3.84765 0 8.9121095 3 0 0 -8.9121095 -3 0 z m 0 10.3808595 0 3 3 0 0 -3 -3 0 z" Fill="White" x:Shared="False"/>
+
+ <Style TargetType="Button" x:Key="CloseButtonStyle">
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="Button">
+ <TextBlock Text="&#9932;" FontSize="12" />
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ <Setter Property="HorizontalAlignment" Value="Right"/>
+ <Setter Property="VerticalAlignment" Value="Top"/>
+ </Style>
+
+ <wpf:NotificationTemplateSelector x:Key="NotificationTemplateSelector"/>
+
+ <ControlTemplate x:Key="NotificationTemplate" TargetType="{x:Type controls:Notification}">
+ <ControlTemplate.Resources>
+ <DataTemplate DataType="{x:Type system:String}" x:Key="DefaultStringTemplate">
+ <Border Background="{Binding RelativeSource={RelativeSource AncestorType=controls:Notification}, Path=Background}" MinHeight="80">
+ <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding}"/>
+ </Border>
+ </DataTemplate>
+ <DataTemplate DataType="{x:Type wpf:NotificationContent}" x:Key="DefaultNotificationTemplate">
+ <Border x:Name="Border" Padding="12" MinHeight="80">
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="Auto"/>
+ <ColumnDefinition Width="*"/>
+ </Grid.ColumnDefinitions>
+ <ContentControl Margin="0,0,12,0" Width="25" Height="25" VerticalAlignment="Top">
+ <ContentControl x:Name="Icon" HorizontalAlignment="Center" VerticalAlignment="Center"/>
+ </ContentControl>
+ <DockPanel Grid.Column="1">
+ <TextBlock DockPanel.Dock="Top" Text="{Binding Title}" FontWeight="Medium" TextTrimming="CharacterEllipsis" />
+ <TextBlock Text="{Binding Message}" TextWrapping="Wrap" Opacity=".8" Margin="0,0,12,0"/>
+ </DockPanel>
+ </Grid>
+ </Border>
+ <DataTemplate.Triggers>
+ <DataTrigger Binding="{Binding Type}" Value="Information">
+ <Setter TargetName="Icon" Property="Content" Value="{StaticResource InfoIcon}"/>
+ <Setter TargetName="Border" Property="Background" Value="CornflowerBlue"/>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Type}" Value="Success">
+ <Setter TargetName="Icon" Property="Content" Value="{StaticResource SuccessIcon}"/>
+ <Setter TargetName="Border" Property="Background" Value="#353535"/>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Type}" Value="Warning">
+ <Setter TargetName="Icon" Property="Content" Value="{StaticResource WarningIcon}"/>
+ <Setter TargetName="Border" Property="Background" Value="Orange"/>
+ </DataTrigger>
+ <DataTrigger Binding="{Binding Type}" Value="Error">
+ <Setter TargetName="Icon" Property="Content" Value="{StaticResource ErrorIcon}"/>
+ <Setter TargetName="Border" Property="Background" Value="OrangeRed"/>
+ </DataTrigger>
+ </DataTemplate.Triggers>
+ </DataTemplate>
+ </ControlTemplate.Resources>
+ <Border Background="{TemplateBinding Background}"
+ BorderBrush="{TemplateBinding BorderBrush}"
+ BorderThickness="{TemplateBinding BorderThickness}"
+ Margin="8,8,0,0">
+ <Grid>
+ <ContentPresenter/>
+ <Button x:Name="PART_CloseButton" Style="{StaticResource CloseButtonStyle}" Margin="12" Foreground="{TemplateBinding Foreground}" Opacity=".8"/>
+ </Grid>
+ </Border>
+ <ControlTemplate.Triggers>
+ <EventTrigger RoutedEvent="Loaded">
+ <BeginStoryboard>
+ <Storyboard>
+ <DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1" Duration="0:0:.5" />
+ <DoubleAnimation Storyboard.TargetProperty="LayoutTransform.ScaleX" From="0" To="1" Duration="0:0:.2"/>
+ <DoubleAnimation Storyboard.TargetProperty="LayoutTransform.ScaleY" From="0" To="1" Duration="0:0:.2"/>
+ </Storyboard>
+ </BeginStoryboard>
+ </EventTrigger>
+ <EventTrigger RoutedEvent="controls:Notification.NotificationCloseInvoked" >
+ <BeginStoryboard>
+ <Storyboard Duration="0:0:.1">
+ <DoubleAnimation Storyboard.TargetProperty="LayoutTransform.ScaleX" From="1" To="0.1" Duration="0:0:.2"/>
+ </Storyboard>
+ </BeginStoryboard>
+ <BeginStoryboard>
+ <Storyboard BeginTime="0:0:.2">
+ <DoubleAnimation Storyboard.TargetProperty="LayoutTransform.ScaleY" From="1" To="0" Duration="0:0:.2"/>
+ </Storyboard>
+ </BeginStoryboard>
+ </EventTrigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+
+ <Style TargetType="{x:Type controls:Notification}">
+ <!--<Setter Property="Height" Value="100"/>-->
+ <Setter Property="UseLayoutRounding" Value="True"/>
+ <Setter Property="SnapsToDevicePixels" Value="True"/>
+ <Setter Property="Width" Value="350"/>
+ <Setter Property="FontSize" Value="14"></Setter>
+ <Setter Property="Background" Value="#444444"/>
+ <Setter Property="Foreground" Value="White"/>
+ <Setter Property="Template" Value="{StaticResource NotificationTemplate}"/>
+ <Setter Property="ContentTemplateSelector" Value="{StaticResource NotificationTemplateSelector}"/>
+ <Setter Property="LayoutTransform">
+ <Setter.Value>
+ <ScaleTransform />
+ </Setter.Value>
+ </Setter>
+ <Setter Property="Effect">
+ <Setter.Value>
+ <DropShadowEffect BlurRadius="5" Direction="0" ShadowDepth="0" Opacity=".25"/>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+ <Style TargetType="{x:Type controls:NotificationArea}">
+ <Setter Property="Margin" Value="0,0,8,8"/>
+ <Setter Property="Template">
+ <Setter.Value>
+ <ControlTemplate TargetType="{x:Type controls:NotificationArea}">
+ <controls:ReversibleStackPanel x:Name="PART_Items"/>
+ <ControlTemplate.Triggers>
+ <Trigger Property="Position" Value="TopLeft">
+ <Setter TargetName="PART_Items" Property="VerticalAlignment" Value="Top"/>
+ <Setter TargetName="PART_Items" Property="HorizontalAlignment" Value="Left"/>
+ </Trigger>
+ <Trigger Property="Position" Value="TopRight">
+ <Setter TargetName="PART_Items" Property="VerticalAlignment" Value="Top"/>
+ <Setter TargetName="PART_Items" Property="HorizontalAlignment" Value="Right"/>
+ </Trigger>
+ <Trigger Property="Position" Value="BottomLeft">
+ <Setter TargetName="PART_Items" Property="ReverseOrder" Value="True"/>
+ <Setter TargetName="PART_Items" Property="VerticalAlignment" Value="Bottom"/>
+ <Setter TargetName="PART_Items" Property="HorizontalAlignment" Value="Left"/>
+ </Trigger>
+ <Trigger Property="Position" Value="BottomRight">
+ <Setter TargetName="PART_Items" Property="ReverseOrder" Value="True"/>
+ <Setter TargetName="PART_Items" Property="VerticalAlignment" Value="Bottom"/>
+ <Setter TargetName="PART_Items" Property="HorizontalAlignment" Value="Right"/>
+ </Trigger>
+ </ControlTemplate.Triggers>
+ </ControlTemplate>
+ </Setter.Value>
+ </Setter>
+ </Style>
+
+</ResourceDictionary> \ No newline at end of file
diff --git a/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Utils/VisualTreeHelperExtensions.cs b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Utils/VisualTreeHelperExtensions.cs
new file mode 100644
index 000000000..e930e92da
--- /dev/null
+++ b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/Utils/VisualTreeHelperExtensions.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Media;
+
+namespace Notifications.Wpf.Utils
+{
+ internal class VisualTreeHelperExtensions
+ {
+ public static T GetParent<T>(DependencyObject child) where T : DependencyObject
+ {
+ var parent = VisualTreeHelper.GetParent(child);
+
+ if (parent == null) return null;
+
+ var tParent = parent as T;
+ if (tParent != null)
+ {
+ return tParent;
+ }
+
+ return GetParent<T>(parent);
+ }
+ }
+}
diff --git a/Software/Visual_Studio/StubsUtils/Notifications.Wpf/pack.bat b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/pack.bat
new file mode 100644
index 000000000..59c6be7d2
--- /dev/null
+++ b/Software/Visual_Studio/StubsUtils/Notifications.Wpf/pack.bat
@@ -0,0 +1,3 @@
+msbuild /p:Configuration="Release 4.0"
+msbuild /p:Configuration="Release 4.5"
+msbuild /t:Build;Package /p:Configuration="Release 4.6.1" \ No newline at end of file