BeepWait
Loading and progress display form with spinner animation and real-time message updates
?? Table of Contents
Overview
BeepWait is a sophisticated loading and progress display form designed to provide visual feedback during long-running operations. It features an animated spinner, customizable title and messages, logo display, and real-time progress updates with thread-safe operation.
Built as a standalone form, BeepWait provides a professional loading experience with theme support, safe cross-thread updates, and comprehensive customization options. Perfect for file operations, data loading, network requests, and any operation that requires user patience.
Key Features
?? Animated Spinner
Smooth rotating spinner animation with customizable speed and appearance
?? Real-time Updates
Thread-safe progress updates with scrolling message display
??? Logo Integration
Company logo display with image path customization
?? Theme Support
Complete theming integration with automatic color application
?? Thread Safety
Safe cross-thread operations with proper invoke patterns
? Async Operations
Full async/await support for modern C# applications
Visual Preview
Loading Data...
BeepWait dialog showing animated spinner and progress messages
Basic Usage
Simple Wait Dialog
// Show a simple wait dialog
var waitForm = new BeepWait();
var args = new PassedArgs
{
Title = "Processing...",
Messege = "Please wait while we process your request.",
ImagePath = "company-logo.png"
};
await waitForm.ShowAsync(args);
// Perform your long-running operation
await SomeTimeConsumingOperation();
// Close the wait dialog
await waitForm.CloseAsync();
With Progress Updates
// Create and show wait form with progress updates
var waitForm = new BeepWait();
var args = new PassedArgs
{
Title = "Loading Data",
Messege = "Initializing...",
ImagePath = "app-icon.png"
};
// Show the form
await waitForm.ShowAsync(args);
try
{
// Simulate a multi-step operation with progress updates
for (int i = 0; i < 100; i++)
{
// Update progress with new message
waitForm.UpdateProgress(i, $"Processing item {i + 1} of 100...");
// Simulate work
await Task.Delay(50);
}
waitForm.UpdateProgress(100, "Operation completed successfully!");
await Task.Delay(1000); // Show completion message briefly
}
finally
{
// Always close the wait form
await waitForm.CloseAsync();
}
File Processing Example
public async Task ProcessLargeFile(string filePath)
{
var waitForm = new BeepWait();
var args = new PassedArgs
{
Title = "File Processing",
Messege = "Reading file...",
ImagePath = "file-icon.png"
};
await waitForm.ShowAsync(args);
try
{
waitForm.UpdateProgress(0, "Opening file...");
var lines = await File.ReadAllLinesAsync(filePath);
waitForm.UpdateProgress(10, $"Processing {lines.Length} lines...");
for (int i = 0; i < lines.Length; i++)
{
// Process each line
ProcessLine(lines[i]);
// Update progress every 100 lines
if (i % 100 == 0)
{
int percentage = (i * 90) / lines.Length + 10; // 10-100%
waitForm.UpdateProgress(percentage,
$"Processed {i + 1} of {lines.Length} lines...");
}
}
waitForm.UpdateProgress(100, "File processing completed!");
await Task.Delay(500);
}
catch (Exception ex)
{
waitForm.UpdateProgress(0, $"Error: {ex.Message}");
await Task.Delay(2000);
}
finally
{
await waitForm.CloseAsync();
}
}
Properties
Core Properties
| Property | Type | Description |
|---|---|---|
Passedarguments |
PassedArgs | Configuration object containing title, message, and image path |
Title |
BeepLabel | Main title label displayed at the top |
messege |
RichTextBox | Scrollable message area for progress updates |
LogopictureBox |
BeepImage | Logo/image display control |
Animation Properties
| Property | Type | Description |
|---|---|---|
_spinnerImage |
BeepImage | Spinner animation control |
_rotationAngle |
float | Current rotation angle of the spinner |
_spinnerTimer |
Timer | Timer controlling spinner animation speed |
PassedArgs Structure
| Property | Type | Description |
|---|---|---|
Title |
string | Dialog title text |
Messege |
string | Initial message text |
ImagePath |
string | Path to logo/icon image file |
Methods
Main Operations
| Method | Parameters | Returns | Description |
|---|---|---|---|
ShowAsync |
PassedArgs args | Task<IErrorsInfo> | Shows the wait form with specified configuration |
CloseAsync |
- | Task<IErrorsInfo> | Closes the wait form after optional delay |
UpdateProgress |
int progress, string text | void | Updates progress with new message (thread-safe) |
Configuration Methods
| Method | Parameters | Description |
|---|---|---|
SetTitle |
string title | Sets the dialog title text |
SetText |
string text | Sets the main message text |
SetImage |
string imagePath | Sets the logo/icon image |
Animation Methods
| Method | Description |
|---|---|
StartSpinner |
Starts the spinner animation |
StopSpinner |
Stops the spinner animation |
ApplyTheme |
Applies current theme to all child controls |
Examples
Database Operation with Progress
public async Task> LoadCustomersAsync()
{
var waitForm = new BeepWait();
var args = new PassedArgs
{
Title = "Loading Customers",
Messege = "Connecting to database...",
ImagePath = "database-icon.png"
};
await waitForm.ShowAsync(args);
var customers = new List();
try
{
waitForm.UpdateProgress(10, "Establishing database connection...");
using var connection = new SqlConnection(connectionString);
await connection.OpenAsync();
waitForm.UpdateProgress(25, "Executing customer query...");
var command = new SqlCommand("SELECT * FROM Customers", connection);
using var reader = await command.ExecuteReaderAsync();
waitForm.UpdateProgress(50, "Reading customer data...");
int customerCount = 0;
while (await reader.ReadAsync())
{
customers.Add(new Customer
{
Id = reader.GetInt32("Id"),
Name = reader.GetString("Name"),
Email = reader.GetString("Email"),
Phone = reader.GetString("Phone")
});
customerCount++;
if (customerCount % 50 == 0)
{
waitForm.UpdateProgress(
50 + (customerCount * 40 / 1000), // Estimate progress
$"Loaded {customerCount} customers...");
}
}
waitForm.UpdateProgress(95, "Finalizing data...");
await Task.Delay(500); // Simulate final processing
waitForm.UpdateProgress(100, $"Successfully loaded {customers.Count} customers!");
await Task.Delay(1000);
}
catch (Exception ex)
{
waitForm.UpdateProgress(0, $"Error loading customers: {ex.Message}");
await Task.Delay(3000);
throw;
}
finally
{
await waitForm.CloseAsync();
}
return customers;
}
File Upload with Progress
public async Task UploadFileAsync(string filePath, string uploadUrl)
{
var waitForm = new BeepWait();
var fileInfo = new FileInfo(filePath);
var args = new PassedArgs
{
Title = "File Upload",
Messege = $"Preparing to upload {fileInfo.Name}...",
ImagePath = "upload-icon.png"
};
await waitForm.ShowAsync(args);
try
{
waitForm.UpdateProgress(5, "Validating file...");
if (!fileInfo.Exists)
{
waitForm.UpdateProgress(0, "Error: File not found!");
await Task.Delay(2000);
return false;
}
waitForm.UpdateProgress(10, "Preparing upload request...");
using var httpClient = new HttpClient();
using var content = new MultipartFormDataContent();
waitForm.UpdateProgress(20, "Reading file content...");
var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
var streamContent = new StreamContent(fileStream);
content.Add(streamContent, "file", fileInfo.Name);
waitForm.UpdateProgress(30, "Starting upload...");
// Create progress tracking
var progress = new Progress(bytesUploaded =>
{
var percentage = (int)((bytesUploaded * 60.0) / fileInfo.Length) + 30; // 30-90%
waitForm.UpdateProgress(percentage,
$"Uploaded {FormatBytes(bytesUploaded)} of {FormatBytes(fileInfo.Length)}...");
});
var response = await httpClient.PostAsync(uploadUrl, content);
waitForm.UpdateProgress(95, "Verifying upload...");
response.EnsureSuccessStatusCode();
waitForm.UpdateProgress(100, "Upload completed successfully!");
await Task.Delay(1000);
return true;
}
catch (Exception ex)
{
waitForm.UpdateProgress(0, $"Upload failed: {ex.Message}");
await Task.Delay(3000);
return false;
}
finally
{
await waitForm.CloseAsync();
}
}
private string FormatBytes(long bytes)
{
string[] sizes = { "B", "KB", "MB", "GB" };
double len = bytes;
int order = 0;
while (len >= 1024 && order < sizes.Length - 1)
{
order++;
len = len / 1024;
}
return $"{len:0.##} {sizes[order]}";
}
Batch Processing with Status Updates
public async Task ProcessOrdersAsync(List orders)
{
var waitForm = new BeepWait();
var args = new PassedArgs
{
Title = "Processing Orders",
Messege = "Initializing batch processing...",
ImagePath = "process-icon.png"
};
await waitForm.ShowAsync(args);
try
{
var totalOrders = orders.Count;
var processedOrders = 0;
var errorCount = 0;
waitForm.UpdateProgress(5, $"Starting batch processing for {totalOrders} orders...");
foreach (var order in orders)
{
try
{
waitForm.UpdateProgress(
(processedOrders * 90) / totalOrders + 5, // 5-95%
$"Processing order {order.OrderNumber} ({processedOrders + 1} of {totalOrders})...");
// Simulate order processing steps
await ValidateOrder(order);
waitForm.UpdateProgress(
(processedOrders * 90) / totalOrders + 5,
$"Validating payment for order {order.OrderNumber}...");
await ProcessPayment(order);
waitForm.UpdateProgress(
(processedOrders * 90) / totalOrders + 5,
$"Updating inventory for order {order.OrderNumber}...");
await UpdateInventory(order);
waitForm.UpdateProgress(
(processedOrders * 90) / totalOrders + 5,
$"Sending confirmation for order {order.OrderNumber}...");
await SendConfirmation(order);
processedOrders++;
}
catch (Exception ex)
{
errorCount++;
waitForm.UpdateProgress(
(processedOrders * 90) / totalOrders + 5,
$"Error processing order {order.OrderNumber}: {ex.Message}");
await Task.Delay(1000); // Brief pause to show error
}
}
waitForm.UpdateProgress(100,
$"Batch processing completed! Processed: {processedOrders}, Errors: {errorCount}");
await Task.Delay(2000);
}
catch (Exception ex)
{
waitForm.UpdateProgress(0, $"Batch processing failed: {ex.Message}");
await Task.Delay(3000);
throw;
}
finally
{
await waitForm.CloseAsync();
}
}
Theming
BeepWait provides comprehensive theming with automatic application of theme colors and fonts to all child controls:
Theme Application
var waitForm = new BeepWait
{
Theme = "DarkTheme"
};
// Theme automatically applies to:
// - Form background color
// - Title label styling
// - Message area colors
// - Spinner colors
// - Logo control theming
// Manual theme application
waitForm.ApplyTheme();
Theme Properties Applied
- BackColor - Form background from theme
- ForeColor - Text color from theme
- Title theming - Title label uses theme fonts and colors
- Message area - RichTextBox uses theme colors
- Spinner colors - Animation colors match theme
- Logo theming - BeepImage control theme application
Custom Theme Colors
// Create wait form with custom theme
var waitForm = new BeepWait();
// Apply theme before showing
waitForm.Theme = "CustomTheme";
waitForm.ApplyTheme();
// Or customize individual controls after theme application
waitForm.Title.ForeColor = Color.White;
waitForm.messege.BackColor = Color.FromArgb(30, 30, 30);
waitForm.messege.ForeColor = Color.LightGray;
Best Practices
?? Thread Safety
- Use UpdateProgress: Always use UpdateProgress method for thread-safe message updates
- Async operations: Use async/await pattern for all long-running operations
- Proper disposal: Always call CloseAsync in finally blocks
- UI thread: Ensure ShowAsync is called from the UI thread
?? Progress Updates
- Meaningful messages: Provide clear, specific progress messages
- Regular updates: Update progress frequently enough to show activity
- Percentage tracking: Use the progress parameter for completion percentage
- Error handling: Show clear error messages when operations fail
?? User Experience
- Clear titles: Use descriptive titles that explain the operation
- Appropriate imagery: Choose relevant icons/logos for the operation context
- Reasonable delays: Don't show wait dialogs for very quick operations (<1 second)
- Completion feedback: Show success/completion messages before closing
? Performance
- Minimal updates: Don't update progress too frequently (avoid spam)
- Batch operations: Group related operations for better user experience
- Resource cleanup: Properly dispose of resources in finally blocks
- Cancellation support: Consider adding cancellation tokens for long operations
Keep progress messages specific and informative. Instead of "Processing...", use "Processing order 5 of 20..." or "Uploading file (2.1 MB of 5.3 MB)..."
Always use try-catch-finally blocks with CloseAsync in the finally block to ensure the wait dialog is properly closed even if errors occur.
Never update UI controls directly from background threads. Always use the UpdateProgress method which handles cross-thread operations safely.