-
Notifications
You must be signed in to change notification settings - Fork 1
splash screen
The splash screen is a professional loading window that displays during application startup while the Blazor server initializes in the background. It provides immediate visual feedback to users that the application is launching, creating a more polished experience compared to a blank window.
Modern desktop applications benefit from splash screens because:
- User Confidence: Users see the application is responsive during startup
- Professional Appearance: Matches expectations of enterprise applications
- Customization: Opportunity to brand your application during launch
- Zero Performance Overhead: Automatically transitions to hidden mode after startup
- Enabled by Default: Works out of the box with sensible defaults
- Fully Customizable: Colors, text, size, fonts, and custom content
- Zero Configuration Needed: Intelligent defaults require no setup
- Zero Performance Overhead: Window becomes hidden provider after Blazor loads
- Professional Theme: Visual Studio-inspired dark theme by default
The splash screen is enabled by default with zero configuration needed:
var builder = new HostBuilder()
.WithTitle("My Desktop App")
.WithSize(1200, 800)
.AddMudBlazor();
builder.RunApp(args); // Splash screen shows automatically!The default splash will display with:
- 400x250 pixel window centered on screen
- Application title (from
WithTitle()) - "Loading..." message
- Dark theme (#2D2D30 background, white text)
- Animated loading indicator (dots)
Change the title and loading message in one call:
var builder = new HostBuilder()
.WithTitle("My Desktop App")
.WithSize(1200, 800)
.WithSplashScreen("My Desktop App", "Initializing workspace...")
.AddMudBlazor();
builder.RunApp(args);Configure multiple splash properties at once:
var builder = new HostBuilder()
.WithTitle("My Desktop App")
.WithSize(1200, 800)
.ConfigureSplashScreen(splash =>
{
splash.Width = 500;
splash.Height = 300;
splash.Title = "Enterprise Suite";
splash.LoadingMessage = "Loading modules...";
splash.BackgroundColor = "#1E1E1E"; // Darker background
splash.ForegroundColor = "#00D9FF"; // Cyan accent
splash.TitleFontSize = 28;
splash.MessageFontSize = 16;
splash.ShowLoadingIndicator = true;
})
.AddMudBlazor();
builder.RunApp(args);Replace the default splash with custom Avalonia controls:
var builder = new HostBuilder()
.WithTitle("My Desktop App")
.WithSize(1200, 800)
.WithCustomSplashScreen(() =>
{
var panel = new StackPanel
{
Background = Brushes.DarkSlateGray,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Spacing = 20
};
panel.Children.Add(new TextBlock
{
Text = "🚀 My Amazing App",
FontSize = 32,
Foreground = Brushes.White,
TextAlignment = TextAlignment.Center
});
panel.Children.Add(new ProgressBar
{
IsIndeterminate = true,
Width = 300
});
return new Border
{
Background = Brushes.DarkSlateGray,
Child = panel
};
})
.AddMudBlazor();
builder.RunApp(args);Hide the splash screen entirely:
var builder = new HostBuilder()
.WithTitle("My Desktop App")
.WithSize(1200, 800)
.WithSplashScreen(false) // Disable splash screen
.AddMudBlazor();
builder.RunApp(args);All splash screen properties are contained in the SplashScreenConfig class. Configure them using ConfigureSplashScreen():
| Property | Type | Default | Description |
|---|---|---|---|
Enabled |
bool |
true |
Whether to show splash screen during startup |
Title |
string |
"Blazor Desktop App" |
Main title text displayed on splash |
LoadingMessage |
string |
"Loading..." |
Status message below title |
Width |
int |
400 |
Splash window width in pixels |
Height |
int |
250 |
Splash window height in pixels |
BackgroundColor |
string |
"#2D2D30" |
Background color (hex format) |
ForegroundColor |
string |
"#FFFFFF" |
Text color (hex format) |
TitleFontSize |
double |
24.0 |
Title text font size in points |
MessageFontSize |
double |
14.0 |
Message text font size in points |
ShowLoadingIndicator |
bool |
true |
Whether to show animated dots indicator |
CustomContentFactory |
Func<Control>? |
null |
Custom control factory (overrides default UI) |
The default constants are defined in Constants.Defaults:
// Splash Screen Defaults
SplashLoadingMessage = "Loading..."
SplashWindowWidth = 400
SplashWindowHeight = 250
SplashBackgroundColor = "#2D2D30" // Dark theme
SplashForegroundColor = "#FFFFFF" // White text
SplashTitleFontSize = 24.0
SplashMessageFontSize = 14.0Enable or disable the splash screen entirely.
// Disable splash screen
.WithSplashScreen(false)
// Enable splash screen (default)
.WithSplashScreen(true)Returns: HostBuilder for method chaining
Set the splash title and loading message text.
.WithSplashScreen("My App", "Initializing...")This method automatically enables the splash screen.
Parameters:
-
title- Splash screen title text -
loadingMessage- Loading status message (optional, defaults to "Loading...")
Returns: HostBuilder for method chaining
Configure multiple splash properties at once.
.ConfigureSplashScreen(splash =>
{
splash.BackgroundColor = "#000000";
splash.ForegroundColor = "#00FF00";
splash.Width = 600;
splash.Height = 400;
})Parameters:
-
configure- Action to configure theSplashScreenConfiginstance
Returns: HostBuilder for method chaining
Provide a custom Avalonia control factory to replace the default splash UI.
.WithCustomSplashScreen(() =>
{
var control = new MyCustomSplashControl();
return control;
})This method automatically enables the splash screen and ignores all standard configuration properties.
Parameters:
-
contentFactory- Function that creates and returns the splash content control
Returns: HostBuilder for method chaining
Note: Custom content completely overrides the default splash UI. Standard properties like Title, BackgroundColor, etc. are ignored.
var builder = new HostBuilder()
.WithTitle("Enterprise Application")
.WithSize(1400, 900)
.ConfigureSplashScreen(splash =>
{
splash.Title = "Enterprise Application Suite";
splash.LoadingMessage = "Loading your workspace...";
splash.Width = 600;
splash.Height = 350;
splash.BackgroundColor = "#1A1A1A"; // Very dark background
splash.ForegroundColor = "#FFFFFF"; // White text
splash.TitleFontSize = 32;
splash.MessageFontSize = 16;
splash.ShowLoadingIndicator = true;
})
.AddMudBlazor()
.ConfigureServices(services =>
{
// Add application services
});
builder.RunApp(args);var builder = new HostBuilder()
.WithTitle("Developer Tools")
.WithSize(1200, 800)
.ConfigureSplashScreen(splash =>
{
splash.Title = "Developer Tools";
splash.LoadingMessage = "Initializing toolchain...";
splash.BackgroundColor = "#2D2D30"; // VS dark theme
splash.ForegroundColor = "#007ACC"; // VS blue accent
splash.TitleFontSize = 28;
splash.MessageFontSize = 14;
})
.AddMudBlazor();
builder.RunApp(args);Custom splash with progress bar (note: this won't actually track progress, just show animated indicator):
var builder = new HostBuilder()
.WithTitle("My App")
.WithSize(1200, 800)
.WithCustomSplashScreen(() =>
{
var container = new StackPanel
{
Background = Brushes.White,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Spacing = 20,
Width = 400,
Height = 300
};
// Logo/Title
container.Children.Add(new TextBlock
{
Text = "Loading Application",
FontSize = 24,
FontWeight = FontWeight.Bold,
Foreground = Brushes.Black,
HorizontalAlignment = HorizontalAlignment.Center
});
// Subtitle
container.Children.Add(new TextBlock
{
Text = "Please wait...",
FontSize = 14,
Foreground = new SolidColorBrush(Colors.Gray),
HorizontalAlignment = HorizontalAlignment.Center
});
// Indeterminate progress bar
container.Children.Add(new ProgressBar
{
IsIndeterminate = true,
Height = 4,
Width = 300
});
return new Border
{
Background = Brushes.White,
Child = container
};
})
.AddMudBlazor();
builder.RunApp(args);var builder = new HostBuilder()
.WithTitle("Simple App")
.WithSize(1200, 800)
.WithSplashScreen("Simple App", "Starting...")
.AddMudBlazor();
builder.RunApp(args);var builder = new HostBuilder()
.WithTitle("No Splash App")
.WithSize(1200, 800)
.WithSplashScreen(false) // No splash screen
.AddMudBlazor();
builder.RunApp(args);The splash screen integrates with the Avalonia window lifecycle:
-
Initialization Phase: When
InitializeWindow()runs, it checks if the splash is enabled - Splash Display Phase: If enabled, the Avalonia window displays as the splash screen
- Blazor Startup Phase: While splash is visible, the Blazor server starts in the background
- Server Ready Phase: HTTP requests are made to verify the Blazor server is ready
- Transition Phase: Once the server responds successfully, the splash window transitions to hidden mode
-
Hidden Provider Phase: The Avalonia window becomes a hidden provider for Avalonia's
StorageProviderAPI - Photino Display Phase: The actual application UI displays in a Photino window
Avalonia Window (BlazorHostWindow):
- Initially displays as the splash screen
- Hides itself after Blazor server is ready
- Remains in memory as a hidden window (off-screen, transparent)
- Provides the
StorageProviderimplementation for file dialogs
Photino Window:
- The actual application window
- Created and displayed after splash transitions to hidden mode
- Hosts the Blazor content
- Handles actual user interaction
The splash content is generated by SplashScreenConfig.CreateDefaultContent():
internal Control CreateDefaultContent()
{
// Creates a centered StackPanel with:
// 1. Bold title text
// 2. Loading message (slightly transparent)
// 3. Animated dots indicator (if enabled)
var mainPanel = new StackPanel
{
Background = backgroundColor,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Spacing = 20
};
// Add children based on configuration...
return new Border { Background = backgroundColor, Child = mainPanel };
}By keeping the Avalonia window alive in hidden mode, the framework maintains a single StorageProvider instance throughout the application lifecycle. This ensures:
- File dialogs work consistently
- No provider state is lost during transitions
- Single source of truth for platform interactions
Long text may not fit or look professional:
// Good - concise
splash.LoadingMessage = "Loading...";
splash.LoadingMessage = "Initializing workspace...";
// Avoid - too long
splash.LoadingMessage = "Loading all resources and configurations for your workspace";Ensure text is readable against the background:
// Good - high contrast
splash.BackgroundColor = "#2D2D30";
splash.ForegroundColor = "#FFFFFF";
// Avoid - low contrast
splash.BackgroundColor = "#F0F0F0";
splash.ForegroundColor = "#ECECEC";The splash should feel like part of your application:
// If your app uses a professional dark theme
.ConfigureSplashScreen(splash =>
{
splash.BackgroundColor = "#1E1E1E";
splash.ForegroundColor = "#FFFFFF";
splash.TitleFontSize = 28;
})Balance readability with splash size:
// For 400x250 splash
splash.TitleFontSize = 24;
splash.MessageFontSize = 14;
// For 600x400 splash (larger)
splash.TitleFontSize = 32;
splash.MessageFontSize = 18;Too large or too small looks unprofessional:
// Good sizes
400 x 250 // Default, balanced
500 x 300 // Slightly larger
600 x 350 // For detailed graphics
// Avoid
200 x 150 // Too small, cramped
1200 x 800 // Same as main window, confusingColors must be valid hex format:
// Good
splash.BackgroundColor = "#2D2D30";
splash.BackgroundColor = "#000000";
splash.BackgroundColor = "#FFFFFF";
// Avoid
splash.BackgroundColor = "2D2D30"; // Missing #
splash.BackgroundColor = "#2D2D"; // Too short
splash.BackgroundColor = "DarkGray"; // Not hex formatIf your application starts very quickly, consider disabling the splash:
#if DEBUG
.WithSplashScreen(false)
#else
.WithSplashScreen(true)
#endifWhen using custom content:
.WithCustomSplashScreen(() =>
{
// ✓ Return a complete Control hierarchy
var container = new Border { ... };
return container;
// ✗ Don't return null
return null; // This will cause issues
// ✗ Don't rely on external state that might change
var config = GetCurrentConfig(); // Don't do this
return BuildSplash(config);
})Problem: The splash screen doesn't show during startup.
Causes & Solutions:
- Check if splash is enabled:
// Verify splash is enabled
.ConfigureSplashScreen(splash =>
{
Console.WriteLine($"Splash enabled: {splash.Enabled}"); // Should be true
})- Verify
WithSplashScreen(false)wasn't called:
// This disables it
.WithSplashScreen(false)- Check window size - if size is 0 or negative, window won't display:
.ConfigureSplashScreen(splash =>
{
splash.Width = 400; // Ensure > 0
splash.Height = 250; // Ensure > 0
})Problem: Text appears on splash but isn't readable.
Solutions:
- Check color contrast:
// If background and foreground are too similar
.ConfigureSplashScreen(splash =>
{
splash.BackgroundColor = "#FFFFFF"; // White background
splash.ForegroundColor = "#000000"; // Black text
})- Verify hex color format:
// Invalid format
splash.BackgroundColor = "2D2D30"; // Missing #
// Valid format
splash.BackgroundColor = "#2D2D30";- Check font sizes aren't too small:
.ConfigureSplashScreen(splash =>
{
splash.TitleFontSize = 24; // Minimum 20
splash.MessageFontSize = 14; // Minimum 12
})Problem: Custom splash content doesn't appear or throws errors.
Solutions:
- Ensure factory returns a valid Control:
.WithCustomSplashScreen(() =>
{
if (someCondition)
{
// ✓ Always return a Control
return new TextBlock { Text = "Loading..." };
}
// ✗ Don't return null
return null; // Will cause issues
})- Don't use stateful external data:
// ✗ Bad - relies on external state
var globalConfig = GetConfig();
.WithCustomSplashScreen(() => CreateSplash(globalConfig))
// ✓ Good - self-contained
.WithCustomSplashScreen(() =>
{
return new Border { Background = Brushes.DarkGray };
})- Keep content creation simple:
// ✗ Avoid complex logic
.WithCustomSplashScreen(() =>
{
try
{
var service = GetService();
var data = service.GetDataAsync().Result; // Blocking
return CreateSplashFromData(data);
}
catch { return null; }
})
// ✓ Keep it simple
.WithCustomSplashScreen(() =>
{
return new Border
{
Background = Brushes.White,
Child = new TextBlock { Text = "Loading..." }
};
})Problem: Splash shows briefly then closes immediately.
Cause: Blazor server is starting very fast.
Solutions:
- This is normal behavior - the splash is working correctly
- If you want to see it longer, consider adding a minimum display time (not recommended in production)
- Verify with diagnostics:
.EnableDiagnostics() // Shows timing informationProblem: Splash appears in wrong location or has wrong size.
Solutions:
- Verify dimensions in configuration:
.ConfigureSplashScreen(splash =>
{
Debug.WriteLine($"Size: {splash.Width}x{splash.Height}");
// Should show something like: Size: 400x250
})- Check for negative or zero values:
splash.Width = 400; // Must be > 0
splash.Height = 250; // Must be > 0- Window is centered automatically, no manual positioning needed
Problem: Configuration changes don't appear to take effect.
Solutions:
- Ensure configuration is called before
RunApp():
var builder = new HostBuilder()
// ✓ Configure splash here
.ConfigureSplashScreen(...)
// ✗ Not here
;
// Must call before RunApp()
builder.RunApp(args);- Verify you're configuring the right builder:
var builder = new HostBuilder();
builder.ConfigureSplashScreen(...); // ✓ Correct
builder.RunApp(args);- Check property names are correct:
// ✓ Correct property names
splash.BackgroundColor
splash.ForegroundColor
splash.TitleFontSize
splash.MessageFontSize
splash.ShowLoadingIndicator
// ✗ Won't work
splash.BgColor // Wrong name
splash.TextColor // Wrong name
splash.FontSize // Wrong nameProblem: Splash never transitions to hidden mode.
Causes:
- Blazor server failed to start - check logs:
.EnableDiagnostics() // Shows detailed startup information-
HTTP connectivity issue - server started but not responding:
- Check
Constants.Defaults.ServerReadinessMaxAttempts - Verify Blazor server is actually listening on the configured port
- Check
-
Network issues preventing localhost connection:
- Verify firewall isn't blocking localhost
- Check port isn't already in use
Solution:
- Check console output for error messages
- Enable diagnostics for detailed information
- Verify Blazor server is actually starting by checking port