![](/img/trans.png)
[英]All the controls in visual studio windows form invisible while loading it
[英]How to display a “loading” overlay on windows forms while the form is loading its controls (or updating them)?
我正在尋找一種有效的方法來通知用戶某個表單當前正在加載(或更新)它的UI,這將需要幾秒鍾。
這可能發生在初始加載或更新時。 由於它非常密集並且修改ui控件,因此必須在ui線程上完成,因此阻止用戶。
沒有改變光標,我希望獲得與ajax頁面相似的效果,整個區域由半透明面板覆蓋,中間有動畫齒輪。
你有沒有做過類似的事情? 或者你知道我應該咨詢的有趣網站嗎?
非常感謝
看看這篇文章的一個很好的答案,模仿WinForms上的Ajax風格
Javascript像WinForms的模態窗口。
Javascript像WinForms的模態窗口
這是一個自定義表格,可以做你想要的......改變你的口味:
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
}
您可以通過繼承SWFPanel並覆蓋CreateParams屬性來創建透明面板:
protected override CreateParams CreateParams
{
get
{
CreateParams createParams = base.CreateParams;
createParams.ExStyle |= 0x00000020; // WS_EX_TRANSPARENT
return createParams;
}
}
覆蓋OnPaint以添加半透明疊加層:
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.FillRectangle(new SolidBrush(Color.FromArgb(128, 0,0,0)), this.ClientRectangle);
}
將此面板設置在表單上的Dock.Fill上,而不是其他控件上。 加載結束時隱藏它。
請注意,Winforms不允許子控件實際上是透明的。 正如其他人發布了一個單獨的透明窗口是可能的 - 但管理起來很麻煩。
我會給你一個我寫過的Usercontrol,並且已經在許多不同的程序中使用,它們完全符合你的要求。 這是一個簡單的消費者示例,您可以粘貼到表單的代碼中(是的,它只是無緣無故地創建了一堆新按鈕):
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
這是班級。 “設計師”代碼是內嵌粘貼的,您可以將其留在那里。 該類在運行時禁用控件,因此您只能取消。 它在GUI線程上運行。 您可以禁用取消選項。 在使用者中是一個處理新添加的控件的示例,因此它們不會顯示啟用,但在進度結束時會啟用。
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
祝好運!
您可以通過將Enabled屬性設置為False然后在完成該過程后將其更改回True來禁用窗體上的所有控件。
此外,您可以使用隱藏標簽,在禁用表單之前顯示“正在加載”,並在重新啟用表單時隱藏。
最后,我建議你將過程分為兩部分。 一部分是在沒有修改可以在工作線程上運行的控件的情況下完成工作的部分,而是在工作線程完成后更改gui的部分,這部分工作在gui線程上。 這樣您就不會阻止整個應用程序,使Gui的更改更容易。
我推薦的解決方案是在初始化組件之前將窗體不透明度設置為接近不可見的0.01。 然后創建一個具有相同大小和位置的表單,並在此表單上放置進度條或選取框。在初始化主窗體后,將其不透明度設置為完全並處理選取框窗體。
使用帶有選框或塊樣式的ProgressBar。
http://msdn.microsoft.com/en-us/library/system.windows.forms.progressbar.aspx
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.