Siticone Expressive Panel
The SiticoneExpressivePanel is a specialized container control designed to enhance perceived performance during data loading.
Instead of displaying a blank screen or a simple spinner, it overlays a sophisticated Skeleton Loading animation (Shimmer or Pulse) over its child controls.
It automatically generates "bones" based on the size and location of existing controls, creating a high-fidelity placeholder that matches your layout perfectly.
Loading Configuration
Properties that control the activation and style of the skeleton loading effect.
| Property | Type | Description & Usage Example |
|---|---|---|
IsLoading |
bool | panel.IsLoading = true; The master switch for the control. When set to true, the skeleton overlay appears and the animation begins. When false, the overlay disappears, revealing the actual child controls. |
AnimationMode |
ExpressivePanelAnimationMode |
panel.AnimationMode = ExpressivePanelAnimationMode.Shimmer;
Determines the visual style of the loading effect.
|
AnimationInterval |
int | panel.AnimationInterval = 20; The speed of the animation frame updates in milliseconds. Lower values create smoother but faster animations. |
Appearance & Visuals
Customize the colors and geometry of the skeleton bones to match your application's theme.
| Property | Type | Description & Usage Example |
|---|---|---|
SkeletonColor |
Color | panel.SkeletonColor = Color.FromArgb(224, 224, 224); The base background color of the skeleton bones (the inactive part). |
HighlightColor |
Color |
panel.HighlightColor = Color.White;
For Shimmer: The color of the moving gradient wipe. For Pulse: The color the bones fade towards during the animation cycle. |
BorderRadius |
int | panel.BorderRadius = 4; The roundness of the bone corners in pixels. Set to 1 for sharp rectangles. |
AutoCirclePictureBoxes |
bool |
panel.AutoCirclePictureBoxes = true;
When true, automatically renders PictureBox and SiticonePictureBox controls as perfect circles (avatars), overriding the BorderRadius.
|
Virtual Mode
Virtual Mode allows the panel to display a loading animation even when there are no actual controls inside it. This is ideal for "List" or "Grid" scenarios where content is loaded dynamically and hasn't been created yet.
| Property | Type | Description & Usage Example |
|---|---|---|
UseVirtualMode |
bool | panel.UseVirtualMode = true; If true, ignores child controls and instead draws a simulated list based on the properties below. |
VirtualItemCount |
int | panel.VirtualItemCount = 5; The number of fake rows/items to simulate drawing. |
VirtualItemHeight |
int | panel.VirtualItemHeight = 60; The vertical height allocated to each virtual row. |
Public Methods
// Marks a specific control to be ignored by the skeleton renderer.
// This control will not have a "bone" drawn over it, effectively making it invisible
// during the loading state.
public void SetupPanel()
{
// Ignore the background label or divider
expressivePanel1.AddIgnoredControl(lblTitleSeparator);
}
Events
// 1. StateChanged Event
// Fires whenever IsLoading is toggled. Useful for syncing UI status bars.
panel.StateChanged += (s, e) =>
{
lblStatus.Text = e.IsLoading ? "Fetching Data..." : "Ready";
};
// 2. DrawBone Event
// Advanced: Fires before every single bone is drawn.
// Allows you to customize the geometry or color of specific items.
panel.DrawBone += (s, e) =>
{
// Check which control is being drawn
if (e.SourceControl == btnSubmit)
{
// Draw a custom oval for the submit button instead of a rounded rect
e.Graphics.FillEllipse(Brushes.LightGray, e.Bounds);
// Tell the panel we handled the drawing, so it doesn't draw the default bone
e.Handled = true;
}
};
// 3. AnimationTick Event
// Fires on every timer tick (frame). Use sparingly for complex logic.
panel.AnimationTick += (s, e) =>
{
// Custom logic per frame
};
Detailed Usage Examples
Example 1: Basic Data Loading
The most common use case: covering a form while fetching data asynchronously.
private async void LoadUserProfile_Click(object sender, EventArgs e)
{
// 1. Start the Skeleton Loading Effect
userProfilePanel.AnimationMode = ExpressivePanelAnimationMode.Shimmer;
userProfilePanel.IsLoading = true;
try
{
// 2. Simulate heavy network task (2 seconds)
var userData = await UserRepository.GetByIdAsync(currentUserId);
// 3. Populate the UI controls (which are currently hidden by the skeleton)
lblUsername.Text = userData.Name;
lblEmail.Text = userData.Email;
picAvatar.Image = userData.ProfileImage;
}
finally
{
// 4. Turn off loading to reveal the populated controls
userProfilePanel.IsLoading = false;
}
}
Example 2: Virtual Mode (Simulating Lists)
Use this when the panel is empty at start-up, but you want to imply that a list of items is about to appear. Virtual Mode draws a standardized "Avatar + Title + Subtitle" layout repeatedly.
public void InitializeListLoader()
{
// Configure Virtual Mode settings
expressivePanel1.UseVirtualMode = true;
expressivePanel1.VirtualItemCount = 6; // Draw 6 fake rows
expressivePanel1.VirtualItemHeight = 70; // Each row is 70px tall
// Styling
expressivePanel1.SkeletonColor = Color.FromArgb(240, 240, 240);
expressivePanel1.HighlightColor = Color.White;
// Start loading immediately
expressivePanel1.IsLoading = true;
// Fetch data...
LoadDataAsync();
}
private async void LoadDataAsync()
{
await Task.Delay(1500);
// Important: Disable Virtual Mode when real controls are added
expressivePanel1.UseVirtualMode = false;
expressivePanel1.IsLoading = false;
// Add real controls to the panel here...
}
Example 3: Dark Mode Configuration
Skeleton loading looks different in dark mode. The bones need to be lighter than the background, but not too bright.
private void ApplyDarkTheme()
{
// Panel background is dark
expressivePanel1.BackColor = Color.FromArgb(30, 30, 30);
// Bones should be slightly lighter than background
expressivePanel1.SkeletonColor = Color.FromArgb(45, 45, 45);
// Shimmer highlight should be even lighter to stand out
expressivePanel1.HighlightColor = Color.FromArgb(60, 60, 60);
// Use Pulse animation for a more subtle effect in dark mode
expressivePanel1.AnimationMode = ExpressivePanelAnimationMode.Pulse;
expressivePanel1.AnimationInterval = 25;
}
Enumerations
public enum ExpressivePanelAnimationMode
{
// A linear gradient wipe effect (classic "Shimmer").
// Best for high-contrast loading states.
Shimmer,
// Opacity fading in and out.
// Best for subtle, less distracting loading states.
Pulse
}