Comment afficher une superposition "chargement" sur les formulaires windows pendant que le formulaire est en train de charger ses commandes (ou de les mettre à jour)?
je suis à la recherche d'un moyen efficace pour notifier à l'utilisateur qu'un formulaire donné est en train de charger (ou de mettre à jour) il est UI et cela prendra quelques secondes.
cela peut se produire à la charge initiale ou à la mise à jour. Comme c'est très intensif et modifiant les contrôles de l'interface utilisateur, cela doit être fait sur le thread de l'interface utilisateur, ce qui bloque l'utilisateur.
changer le curseur n'est pas suffisant, je veux obtenir un effet similaire que sur les pages ajax, avec toute la zone qui est recouvert d'un panneau semi-transparent avec un engrenage animé au centre.
avez-vous déjà fait quelque chose comme ça? Ou connaissez-vous des sites intéressants que je devrais consulter?
Merci beaucoup
6 réponses
jetez un oeil à ce post avec une grande réponse qui imite le style Ajax sur WinForms
Javascript comme fenêtre modale pour WinForms.
Javascript Comme Fenêtre Modale pour WinForms
voici un formulaire personnalisé qui fera ce que vous voulez... modifier à votre goût:
public partial class ModalLoadingUI : Form
{
#region Constants
private readonly Color BackgroundFadeColor = Color.FromArgb(50, Color.Black);
#endregion
#region Constructors
public ModalLoadingUI()
{
InitializeComponent();
}
#endregion
#region Properties
/// <summary>
/// Gets or Sets the main form that will be used as a background canvas for the loading form.
/// </summary>
public Form BackgroundForm { get; set; }
/// <summary>
/// Gets or Sets the text to displayed as the progress text.
/// </summary>
public string Title
{
get
{
return label1.Text;
}
set
{
label1.Text = value;
}
}
/// <summary>
/// Gets or Sets the value of the progress bar.
/// </summary>
public int? Progress
{
get
{
if (progressBar1.Style == ProgressBarStyle.Marquee)
{
return null;
}
else
{
return progressBar1.Value;
}
}
set
{
if (value == null)
{
progressBar1.Style = ProgressBarStyle.Marquee;
progressBar1.Value = 100;
label2.Visible = false;
}
else
{
progressBar1.Style = ProgressBarStyle.Continuous;
progressBar1.Value = value.Value;
label2.Text = string.Format("{0}%", value);
label2.Visible = true;
}
}
}
/// <summary>
/// Gets or Sets a value to indicate if the background form should be faded out.
/// </summary>
public bool UseFadedBackground { get; set; }
/// <summary>
/// Gets or Sets a value to indicate if the splash box is to be displayed.
/// </summary>
public bool UseSplashBox
{
get
{
return picShadow.Visible;
}
set
{
if (value == true)
{
picShadow.Visible = true;
panel1.Visible = true;
}
else
{
picShadow.Visible = false;
panel1.Visible = false;
}
}
}
#endregion
#region Base Events
private void ModalLoadingUI_Load(object sender, EventArgs e)
{
if (this.BackgroundForm != null)
{
this.Location = this.BackgroundForm.Location;
}
}
private void ModalLoadingUI_VisibleChanged(object sender, EventArgs e)
{
if (this.Visible == true)
{
if (this.BackgroundForm != null)
{
this.Location = this.BackgroundForm.Location;
}
}
if (System.Diagnostics.Debugger.IsAttached == true)
{
this.TopMost = false;
}
else
{
this.TopMost = true;
}
}
private void ModalLoadingUI_Shown(object sender, EventArgs e)
{
}
#endregion
#region Public Methods
/// <summary>
/// Paints the background form as the background of this form, if one is defined.
/// </summary>
public void CaptureBackgroundForm()
{
if (this.InvokeRequired)
{
this.BeginInvoke(new MethodInvoker(CaptureBackgroundForm));
return;
}
if (this.BackgroundForm == null)
{
return;
}
var bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(bmpScreenshot);
try
{
// COPY BACKGROUND
int x = this.BackgroundForm.Left;
int y = this.BackgroundForm.Top;
var size = this.BackgroundForm.Size;
g.CopyFromScreen(x, y, 0, 0, size, CopyPixelOperation.SourceCopy);
// FADE IF DESIRED
if (this.UseFadedBackground == true)
{
var rect = new Rectangle(0, 0, size.Width, size.Height);
g.FillRectangle(new SolidBrush(BackgroundFadeColor), rect);
}
// PAINT SPLASH BOX SHADOW IF DESIRED
if(this.UseSplashBox == true)
{
PaintPanelShadow(g);
}
}
catch (Exception e)
{
g.Clear(Color.White);
}
this.BackgroundImage = bmpScreenshot;
}
/// <summary>
/// Paints a shadow around the panel, if one is defined.
/// </summary>
/// <param name="g">The graphics object to paint into</param>
private void PaintPanelShadow(Graphics g)
{
var shadowImage = picShadow.Image;
var x = panel1.Left + (panel1.Width / 2) - (shadowImage.Width / 2);
var y = panel1.Top + (panel1.Height / 2) - (shadowImage.Height / 2);
g.DrawImage(shadowImage, x, y, shadowImage.Width, shadowImage.Height);
}
#endregion
}
vous pouvez créer un panneau transparent en sous-classant le Panneau S. W. F. et en outrepassant la propriété CreateParams:
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT
return createParams;
}
}
outrepasser l'OnPaint pour ajouter un recouvrement semi-transparent:
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(128, 0,0,0)), this.ClientRectangle);
}
mettez ce panneau sur le quai.Remplir un formulaire sur les autres contrôles. Cachez-le à la fin du chargement.
notez que Winforms ne permet pas aux commandes enfants d'être réellement transparentes. Comme d'autres ont posté une fenêtre transparente séparée est possible - mais salissant à gérer.
pas Cher
- faites glisser toutes les commandes dans un panneau et faites-le de la taille de la fenêtre (changement facile)
- en fonctionnement: Masquer ce panneau. Utilisez les panneaux .Méthode de DrawToBitmap pour définir l'image de fond de forme.
- afficher barre de progression, travaillez avec "doevents", cachez-le.
- image de fond claire, panneau de rediffusion.
Une Meilleure façon:
Les Progrès De La Classe Des Consommateurs
je vais vous donner un Usercontrol j'ai écrit et utilisé dans de nombreux programmes différents qui fait exactement ce que vous voulez. Voici un exemple de consommateur trivial, vous pouvez coller dans le code d'un formulaire (oui, il fait juste un tas de nouveaux boutons pour aucune raison):
Public Class Form1
Private Sub Form1_FormClosed(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
End ''// use a flag if you would like a more graceful way to handle this.
End Sub
WithEvents ucProgress As New Progress ''// just doing it this way so I don''//t have to paste designer code.
Private Sub Form1_Shown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shown
Controls.Clear()
Controls.Add(ucProgress)
Me.ucProgress.pb.Visible = False
ucProgress.StartProgress()
Try
ucProgress.Message = "Starting up..."
Application.DoEvents()
Me.ucProgress.pb.Visible = True
Me.ucProgress.pb.Maximum = 21
Me.ucProgress.pb.Value = 0
For i As Integer = 0 To 20
Dim btn As New Button
btn.Top = +i * 3
btn.Left = i * 8
btn.Text = CStr(i)
btn.Enabled = False ''// ONLY HAVE TO DO FOR CTLS RIGHT ON MAIN FORM
ucProgress.EnabledStates.Add(btn, True) ''// ONLY HAVE TO DO FOR CTLS RIGHT ON MAIN FORM
Controls.Add(btn)
btn.BringToFront()
System.Threading.Thread.Sleep(200)
Application.DoEvents()
ucProgress.pb.Value += 1
ucProgress.Message = "Processing item# " & i.ToString
If Me.ucProgress.Cancel Then
MsgBox("Cancelled - not all loaded.")
Me.ucProgress.Cancel = False
Exit For
End If
Next
Catch ex As Exception
MsgBox(ex.ToString, , "Error loading something")
Finally
ucProgress.EndProgress()
End Try
End Sub
End Class
Les Progrès De La Classe - Définition
et voici la classe. Le créateur de code est collé en ligne, vous pouvez le laisser là. La classe désactive les contrôles lors de l'exécution de sorte que vous pouvez faire est de l'annuler. Il fonctionne sur le fil GUI. Vous pouvez désactiver l'option annuler. Le consommateur est un exemple de traiter avec de nouveaux contrôles supplémentaires afin qu'ils ne se présentent pas activé, mais activé lorsque la progression est plus.
Option Explicit On
Option Strict On
Public Class Progress
Inherits System.Windows.Forms.UserControl
#Region "Code for the Designer.vb class"
Sub New()
InitializeComponent()
End Sub
''//Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()> _
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
If disposing AndAlso components IsNot Nothing Then
components.Dispose()
End If
MyBase.Dispose(disposing)
End Sub
''//Required by the Windows Form Designer
Private components As System.ComponentModel.IContainer
''//NOTE: The following procedure is required by the Windows Form Designer
''//It can be modified using the Windows Form Designer.
''//Do not modify it using the code editor.
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.components = New System.ComponentModel.Container
Me.btnCancel = New System.Windows.Forms.Button
Me.lblPlaceholder = New System.Windows.Forms.Label
Me.pb = New System.Windows.Forms.ProgressBar
Me.SuspendLayout()
''//
''//btnCancel
''//
Me.btnCancel.Anchor = System.Windows.Forms.AnchorStyles.Top
Me.btnCancel.Location = New System.Drawing.Point(73, 33)
Me.btnCancel.Name = "btnCancel"
Me.btnCancel.Size = New System.Drawing.Size(91, 21)
Me.btnCancel.TabIndex = 0
Me.btnCancel.Text = "Cancel"
Me.btnCancel.UseVisualStyleBackColor = True
''//
''//
''//lblPlaceholder
''//
Me.lblPlaceholder.Anchor = CType(((System.Windows.Forms.AnchorStyles.Top Or System.Windows.Forms.AnchorStyles.Left) _
Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
Me.lblPlaceholder.BackColor = System.Drawing.Color.Transparent
Me.lblPlaceholder.Font = New System.Drawing.Font("Arial Narrow", 8.25!, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, CType(0, Byte))
Me.lblPlaceholder.Location = New System.Drawing.Point(12, 3)
Me.lblPlaceholder.Name = "lblPlaceholder"
Me.lblPlaceholder.Size = New System.Drawing.Size(221, 29)
Me.lblPlaceholder.TabIndex = 1
Me.lblPlaceholder.Text = "Placeholder label for text drawing"
Me.lblPlaceholder.Visible = False
''//
''//pb
''//
Me.pb.Anchor = CType(((System.Windows.Forms.AnchorStyles.Bottom Or System.Windows.Forms.AnchorStyles.Left) _
Or System.Windows.Forms.AnchorStyles.Right), System.Windows.Forms.AnchorStyles)
Me.pb.Location = New System.Drawing.Point(6, 60)
Me.pb.Name = "pb"
Me.pb.Size = New System.Drawing.Size(225, 10)
Me.pb.Style = System.Windows.Forms.ProgressBarStyle.Continuous
Me.pb.TabIndex = 2
''//
''//ucProgress
''//
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.BackColor = System.Drawing.Color.LightSteelBlue
Me.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle
Me.Controls.Add(Me.pb)
Me.Controls.Add(Me.lblPlaceholder)
Me.Controls.Add(Me.btnCancel)
Me.Name = "ucProgress"
Me.Size = New System.Drawing.Size(236, 77)
Me.ResumeLayout(False)
End Sub
Friend WithEvents btnCancel As System.Windows.Forms.Button
Friend WithEvents lblPlaceholder As System.Windows.Forms.Label
Public WithEvents pb As System.Windows.Forms.ProgressBar
#End Region
Dim _mymessage As String
Public Event WorkerPart()
Public Cancel As Boolean
Public EnabledStates As New Dictionary(Of Control, Boolean)
Dim oldfocus As Control
Dim OldMinBox As Boolean
Public Sub StartProgress()
Cancel = False
Me.Parent = Me.ParentForm
oldfocus = Me.ParentForm.ActiveControl
Parent_SizeChanged(Nothing, Nothing)
AddHandler Me.ParentForm.SizeChanged, AddressOf Parent_SizeChanged
Me.Visible = True
Me.Enabled = True
Me.btnCancel.Focus()
EnabledStates.Clear()
For Each ctl As Control In Me.Parent.Controls
If ctl IsNot Me Then
EnabledStates.Add(ctl, ctl.Enabled)
ctl.Enabled = False
End If
Next
Me.BringToFront()
Me.pb.Value = 0
OldMinBox = Me.ParentForm.MinimizeBox
Me.ParentForm.MinimizeBox = True
End Sub
Public Sub EndProgress()
RemoveHandler Me.ParentForm.SizeChanged, AddressOf Parent_SizeChanged
For Each ctl As Control In Me.Parent.Controls
If ctl IsNot Me And EnabledStates.ContainsKey(ctl) Then
ctl.Enabled = EnabledStates(ctl)
End If
Next
If oldfocus IsNot Nothing Then
oldfocus.Focus()
End If
Me.ParentForm.MinimizeBox = OldMinBox
Me.Visible = False
End Sub
Public Property Message() As String
Get
Return _mymessage
End Get
Set(ByVal value As String)
_mymessage = value
Dim g As Graphics = Me.CreateGraphics()
DrawString(g)
g.Dispose()
''//lblMessage.Text = value
Application.DoEvents()
End Set
End Property
Private Sub DrawString(ByVal g As Graphics)
''//g.TextRenderingHint = Drawing.Text.TextRenderingHint.SingleBitPerPixel
Dim rct As New Rectangle(Me.lblPlaceholder.Left, Me.lblPlaceholder.Top, _
Me.lblPlaceholder.Width, Me.lblPlaceholder.Height)
g.SetClip(rct)
Dim b As New SolidBrush(Me.BackColor)
If Me.BackgroundImage Is Nothing Then
g.FillRectangle(b, rct)
Else
g.DrawImage(Me.BackgroundImage, 0, 0)
End If
''//
With lblPlaceholder
g.DrawString(_mymessage, .Font, Brushes.DarkBlue, .Left, _
.Top + CInt(IIf(InStr(_mymessage, vbCrLf) <> 0, 0, .Height \ 4)))
End With
End Sub
Private Sub frmProgress_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
DrawString(e.Graphics)
End Sub
Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click
Cancel = True
End Sub
Private Sub Parent_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs)
Me.Left = (Me.Parent.Width - Me.Width) \ 2
Me.Top = (Me.Parent.Height - Me.Height) \ 2
End Sub
End Class
bonne chance!
vous pouvez désactiver tous les contrôles sur le formulaire en définissant la propriété Enabled à False puis en la changeant de nouveau à True après le processus est fait.
en outre, vous pouvez avoir une étiquette cachée qui dit" Chargement " que vous affichez avant de désactiver le formulaire et de se cacher lors de sa réactivation.
enfin, je suggère que vous divisiez le processus en deux parties. Une partie qui fait le travail sans modifier les commandes que vous pouvez exécuter sur un travailleur le fil et la partie qui change l'interface graphique qui le fait fonctionner sur le fil graphique après que le fil ouvrier est fait. De cette façon, vous ne bloquerez pas toute l'application, rendant les modifications à L'interface graphique plus faciles à faire.
ma solution recommandée est de régler l'opacité des formes à presque invisible say 0,01 avant d'initialiser les composants. Ensuite, créez un formulaire avec la même taille et la position et une barre de progression, ou de sélection sur ce formulaire.. Après l'initialisation de la forme principale, définissez son opacité à remplir et disposez de la forme marquee.
utilisez une barre de progression de style marquee ou blocks.
http://msdn.microsoft.com/en-us/library/system.windows.forms.progressbar.aspx