我正在寻找一种有效的方法来通知用户某个表单当前正在加载(或更新)它的UI,这将花费几秒钟。
这可能发生在初始加载或更新时。由于它是非常密集和修改ui控件,这必须在ui线程上完成,因此阻止用户。
我不想改变光标,我希望获得与ajax页面类似的效果,整个区域由半透明面板覆盖,中间有动画齿轮。
你有没有做过类似的事情?或者你知道我应该咨询的有趣网站吗?
非常感谢
答案 0 :(得分:12)
看看这篇文章的答案很好,模仿WinForms上的Ajax风格
Javascript就像WinForms的模态窗口一样 Javascript Like Modal Window for 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
}
答案 1 :(得分:4)
您可以通过继承S.W.F.Panel并覆盖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上,而不是其他控件上。加载结束时隐藏它。
答案 2 :(得分:4)
请注意,Winforms不允许子控件实际透明。正如其他人发布了一个单独的透明窗口是可能的 - 但管理起来很麻烦。
我会给你一个我写过的用户控件,并且已经在很多不同的程序中使用了你想要的东西。这是一个简单的消费者示例,您可以粘贴到表单的代码中(是的,它只是无缘无故地创建了一堆新按钮):
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
祝你好运!
答案 3 :(得分:3)
您可以通过将Enabled属性设置为False然后在完成该过程后将其更改回True来禁用表单上的所有控件。
此外,您可以使用隐藏标签,在禁用表单之前显示“正在加载”,并在重新启用表单时隐藏。
最后,我建议您将流程分为两部分。一部分是在没有修改可以在工作线程上运行的控件的情况下完成工作的部分,而是在工作线程完成后更改gui的部分,这部分工作在gui线程上。这样您就不会阻止整个应用程序,更容易对Gui进行更改。
答案 4 :(得分:1)
我推荐的解决方案是在初始化组件之前将窗体不透明度设置为接近不可见的0.01。然后创建一个具有相同大小和位置的表单,并在此表单上放置一个进度条或选取框。在初始化主窗体后,将其不透明度设置为full并处理选取框窗体。
答案 5 :(得分:0)
使用带有选框或块样式的ProgressBar。
http://msdn.microsoft.com/en-us/library/system.windows.forms.progressbar.aspx