Table of Contents
C# Popup Base Class
In a previous post i created a splash screen for WPF, i later needed to create a Popup Window, Splash Screen and Toast Window. Each of these has essentially the same base requirements, show a window for sometime.
So I created a base class, that I can then use to create each of these types.
Base Class
The base class allows, the popup to be positioned in accordance to a specific screen location, so in the case of a toast window we need it to display in the bottom right-hand corner of the screen.
using System.ComponentModel; using System.Threading; using System.Windows; using System.Windows.Input; namespace UI_Samples.PopUps.Base { public interface IPopupBase { double ScreenWidth { get; } double ScreenHeight { get; } Point MousePosition { get; } Point MainWindowPosition { get; } Point InAppMousePosition { get; } Window? parentWindow { get; set; } Window? splashWindow { get; } string Title { get; set; } string Description { get; set; } string ImagePath { get; set; } int ImageWidth { get; set; } int ImageHeight { get; set; } int Delay { get; set; } int Sleep { get; set; } void Show(); void Hide(); } public class PopupBase : INotifyPropertyChanged, IPopupBase { private BackgroundWorker _worker = new BackgroundWorker(); public double ScreenHeight { get { return SystemParameters.PrimaryScreenHeight; } } public double ScreenWidth { get { return SystemParameters.PrimaryScreenWidth; } } public Point MousePosition { get { return Mouse.GetPosition(Application.Current.MainWindow); } } public Point MainWindowPosition { get { return new Point(Application.Current.MainWindow.Left, Application.Current.MainWindow.Top); } } public Point InAppMousePosition { get { return new Point( this.MousePosition.X + this.MainWindowPosition.X, this.MousePosition.Y + this.MainWindowPosition.Y); } } public Window? parentWindow { get; set; } = null; public Window? splashWindow { get; } = null; public string Title { get; set; } = "PopupTitle"; public string Description { get; set; } = "PopupDescription"; public string ImagePath { get; set; } = ""; public int ImageWidth { get; set; } = 100; public int ImageHeight { get; set; } = 50; public int Delay { get; set; } = 20; public int Sleep { get; set; } = 80; public event PropertyChangedEventHandler? PropertyChanged; public PopupBase() { } public PopupBase(Window window) { splashWindow = window; } public void Show() { try { _worker.WorkerReportsProgress = true; _worker.WorkerSupportsCancellation = true; _worker.DoWork += worker_DoWork; _worker.ProgressChanged += worker_ProgressChanged; _worker.RunWorkerAsync(); parentWindow?.Show(); } catch { _worker.CancelAsync(); } } public void Hide() { _worker.CancelAsync(); parentWindow?.Close(); } protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } private void worker_DoWork(object? sender, DoWorkEventArgs e) { for (int i = 0; i <= this.Delay; i++) { if (_worker.CancellationPending == true) { e.Cancel = true; return; } _worker.ReportProgress(i); Thread.Sleep(this.Sleep); } } public virtual void worker_ProgressChanged(object? sender, ProgressChangedEventArgs e) { if (e.ProgressPercentage == this.Delay) { parentWindow?.Close(); if (splashWindow != null) { splashWindow.ShowDialog(); } } } } }
Splash Screen
Below is shown an example of the splash screen window that was created in WPF.
Splash Screen XAML
Below is the XAML code used to create the splash screen
<Window x:Class="UI_Samples.Windows.SplashScreen" 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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" mc:Ignorable="d" Title="SplashScreen" Topmost="True" Height="300" Width="450" WindowStyle="None" WindowStartupLocation="CenterScreen" AllowsTransparency="True" Background="{x:Null}" ContentRendered="Window_ContentRendered"> <materialDesign:Card UniformCornerRadius="50" Background="Black" materialDesign:ElevationAssist.Elevation="Dp4" Margin="25"> <Grid> <Image Source="../Assets/SplashScreen/SplashScreen.png" HorizontalAlignment="Center" Height="200"/> <ProgressBar Name="progressBar" Value="0" Height="1" Width="200" IsIndeterminate="True" VerticalAlignment="Bottom" Margin="0,0,0,47"/> </Grid> </materialDesign:Card> </Window>
Splash Screen Window XAML.CS
Since the splash screen needs to be launch before everything else.
using System; using System.Windows; using UI_Samples.PopUps; namespace UI_Samples.Windows { public partial class SplashScreen : Window { private readonly ISplashPopup _splashScreen; public SplashScreen() { InitializeComponent(); _splashScreen = new SplashPopup(new MainWindow()); DataContext = _splashScreen; _splashScreen.parentWindow = this; } private void Window_ContentRendered(object sender, EventArgs e) { _splashScreen.Show(); } } }
ISplashPopUp
Below is the class into which we will pass the XAML window into. This class implements IPopupBase and PopupBase previously created.
using System.Windows; using UI_Samples.PopUps.Base; namespace UI_Samples.PopUps { public interface ISplashPopup : IPopupBase { } public class SplashPopup : PopupBase, ISplashPopup { private Window _window; public SplashPopup(Window window) : base(window) { _window = window; this.Delay = 100; } } }
In this section we will look at a simple implementation of the toast window utilizing the base class IPopupBase
Toast Window
Below is shown an example of the toast window that was created in WPF.
Toast Window XAML
Below is the XAML code that was used to create the user interface UI.
<Window x:Class="UI_Samples.Windows.ToastWindow" 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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" mc:Ignorable="d" Title="ToastWindow" WindowStyle="None" Topmost="True" AllowsTransparency="True" Background="{x:Null}" Width="150" Height="220"> <Window.Resources> <Storyboard x:Key="FadeInAnimation"> <DoubleAnimation From="0" To="1" Duration="0:0:1" Storyboard.TargetProperty="Opacity"/> </Storyboard> <Storyboard x:Key="FadeOutAnimation"> <DoubleAnimation From="1" To="0" Duration="0:0:1" Storyboard.TargetProperty="Opacity"/> </Storyboard> </Window.Resources> <Window.Triggers> <EventTrigger RoutedEvent="Window.Loaded"> <BeginStoryboard Storyboard="{StaticResource FadeInAnimation}"/> </EventTrigger> <EventTrigger RoutedEvent="Window.Unloaded"> <BeginStoryboard Storyboard="{StaticResource FadeOutAnimation}"/> </EventTrigger> </Window.Triggers> <materialDesign:Card UniformCornerRadius="10" Background="{Binding Color,FallbackValue=White}" materialDesign:ElevationAssist.Elevation="Dp4"> <StackPanel Orientation="Vertical"> <TextBlock Text="{Binding Title,FallbackValue=Sample}" HorizontalAlignment="Center" FontFamily="Times Roman" FontWeight="Black" Margin="0,5,0,0"/> <Image Source="../Assets/SampleImages/Sample1.png" Width="150" Height="150" Margin="0,5,0,0"/> <TextBlock Text="Hello World this is a description." HorizontalAlignment="Center" FontFamily="Times Roman" FontWeight="Regular" TextWrapping="Wrap" Margin="0,5,0,0"/> </StackPanel> </materialDesign:Card> </Window>
Toast Window XAML.CS
When the UI is shown we need to pass in the interface IToastPopup and set the DataContext and in return set the interfaces parent window property.
using System.Windows; using UI_Samples.PopUps; namespace UI_Samples.Windows { public partial class ToastWindow : Window { public ToastWindow(IToastPopup toastWindow) { InitializeComponent(); DataContext = toastWindow; toastWindow.parentWindow = this; } } }
IToastPopup
In the ToastPopup class we will add a new interface IToastPopup and inherit into this the IPopupBase interface, and then add two additional property’s that must be implemented; ToastWindowLeft and ToastWindowTop.These additional attributes are for the calculated position of the Toast Window, relative to the screen size. This will help when creating the WPF view model.
using UI_Samples.PopUps.Base; namespace UI_Samples.PopUps { public interface IToastPopup : IPopupBase { double ToastWindowLeft { get; } double ToastWindowTop { get; } } public class ToastPopup : PopupBase, IToastPopup { public double ToastWindowLeft { get { if (this.parentWindow != null) { return this.ScreenWidth - this.parentWindow.Width; } return 0; } } public double ToastWindowTop { get { if (this.parentWindow != null) { return this.ScreenHeight - this.parentWindow.Height; } return 0; } } public ToastPopup() { this.Delay = 100; } } }
Toast Popup in Code Implementation
Within the View Model, we can now create a new instance of the Toast Window and pass in an instance of the IToastPopup.
ToastWindow toastWindow = new ToastWindow(ToastPopup); if (ToastPopup.parentWindow != null) { toastWindow.Left = ToastPopup.ToastWindowLeft; toastWindow.Top = ToastPopup.ToastWindowTop; ToastPopup.Show(); }
Popup Window
For this example we will use the same Xaml and Xaml.cs
IHelpPopup
In this implementation we will again add a new interface IHelpPopup and inherit into this the IPopupBase interface, and add an additional property Color, this will be used to drive the color of the UI background. In addition within the constructor we will set the delay of how long the window must remain shown.
using System.Windows.Media; using System; using System.Linq; using UI_Samples.PopUps.Base; namespace UI_Samples.PopUps { public interface IHelpPopup: IPopupBase { Brush Color { get; set; } } public class HelpPopup : PopupBase, IHelpPopup { Brush _color = getRandomBrush(); public Brush Color { get{return _color;} set{ _color = value; OnPropertyChanged(nameof(Color));} } public HelpPopup() { this.Delay = 100; } private static Brush getRandomBrush() { string[] brushArray = typeof(Brushes).GetProperties(). Select(c => c.Name).ToArray(); Random randomGen = new Random(); string randomColorName = brushArray[randomGen.Next(brushArray.Length)]; SolidColorBrush color = (SolidColorBrush)new BrushConverter().ConvertFromString(randomColorName); return color; } } }