.net Winforms ProgressBar需要时间进行渲染

.net Winforms ProgressBar需要时间进行渲染,.net,vb.net,visual-studio-2010,.net-4.0,progress-bar,.net,Vb.net,Visual Studio 2010,.net 4.0,Progress Bar,我注意到在使用PorgressBar时。如果我将该值设置为x,则显示的值不会立即更新,当条形图从其当前值设置为新值时,绘制该值需要少量时间 这在以下代码中很容易看到: Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click Label1.Text = "" Dim progressHandler = New Progress(Of Integer)(Sub(va

我注意到在使用PorgressBar时。如果我将该值设置为x,则显示的值不会立即更新,当条形图从其当前值设置为新值时,绘制该值需要少量时间

这在以下代码中很容易看到:

Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Label1.Text = ""
    Dim progressHandler = New Progress(Of Integer)(Sub(value) ProgressBar1.Value = value)
    Dim progress = CType(progressHandler, IProgress(Of Integer))
    Await Task.Run(Sub()
                       For i = 1 To 100
                           progress.Report(i)
                           Thread.Sleep(10)
                       Next
                   End Sub)
    Label1.Text = "Value Now at 100%"
    Await Task.Delay(650) 'it takes this long for the bar to be rendered
    Label1.Text += " - Finished drawing"
End Sub
您会注意到,运行此代码时,
值现在为100%
在实际达到100%之前很长一段时间才会出现


是否有任何方法可以检测到条形图何时完成渲染?

问题在于您处于单线程程序中,线程需要时间来更新显示

添加行

Application.DoEvents()
关闭
UpdateProgress
sub之前


您可以取消最后两次刷新。

问题是您在一个单线程程序中,线程需要时间来更新显示

添加行

Application.DoEvents()
关闭
UpdateProgress
sub之前


你可以去掉最后两次刷新。

我刚刚试过,完全明白你的意思。不幸的是,在花了一点时间看看进度条上的DrawToBitmap函数是否有帮助之后,我发现了不足

下一步是创建自定义进度条,该进度条在渲染完成时公开事件

有关如何创建自定义进度条的合理示例,请尝试以下操作:

对代码的快速扫描看起来应该能够在调用“DrawHorizontalChunks”(或“DrawVerticalChunks”)时插入“OnRendered”事件或类似事件

也许不是你想要的答案,但如果你追求它,至少会给你所需要的控制

注意:我自己没有试过,所以如果你花了一整天的时间在这上面,却发现你得到了同样的结果,请不要给我发仇恨邮件

祝你好运

编辑:

对我的回答不满意,似乎有点懒。。。下面使用了我所描述的自定义进度条。它有两个基本属性,用于设置最大/最小值、执行步骤和直接设置值。我通过将睡眠时间间隔更改为各种数量来测试这一点,在所有情况下,表单在关闭前都会将进度条显示为已满。请注意新的OnRendered事件

Imports System
Imports System.Drawing
Imports System.Windows.Forms
Imports System.Windows.Forms.VisualStyles

Public Class Form1
    Inherits Form
    Private WithEvents bar1 As ProgressBarWithRender = New ProgressBarWithRender()


    Public Sub New()
        InitializeComponent()
        Me.Size = New Size(500, 500)
        bar1.Location = New Point(100, 100)
        bar1.Width = 300
        bar1.Height = 50
        bar1.Maximum = 30
        bar1.Step = 1
        Controls.Add(bar1)
    End Sub

    Public Sub OnRendered(ByVal valueRendered As Integer) Handles bar1.OnRendered
        If valueRendered = bar1.Maximum Then
            ' We know everything has been drawn
            Me.Close()
        End If
    End Sub


    <STAThread()> _
    Public Shared Sub Main()
        ' The call to EnableVisualStyles below does not affect
        ' whether ProgressBarRenderer.IsSupported is true; as 
        ' long as visual styles are enabled by the operating system, 
        ' IsSupported is true.
        Application.EnableVisualStyles()
        Application.Run(New Form1())

    End Sub 'Main

    Private Sub Form1_Click(sender As Object, e As System.EventArgs) Handles Me.Click
        For i = 1 To 30
            bar1.PerformStep()
            Threading.Thread.Sleep(10)
        Next
    End Sub

End Class 'Form1

Public Class ProgressBarWithRender
    Inherits Control

    Public Delegate Sub RenderedEventArgs(ByVal valueRendered As Integer)
    Public Event OnRendered As RenderedEventArgs

    Private ProgressBarRectangles() As Rectangle

    Public Property [Step] As Integer

    Public Property InnerPadding As Integer = 3

    Private _Maximum As Integer
    Public Property Maximum As Integer
        Get
            Return _Maximum
        End Get
        Set(value As Integer)
            _Maximum = value
            CalculateTickSizes()
        End Set
    End Property

    Private _Minimum As Integer
    Public Property Minimum As Integer
        Get
            Return _Minimum
        End Get
        Set(value As Integer)
            _Minimum = value
            CalculateTickSizes()
        End Set
    End Property

    Private _Value As Integer
    Public Property Value As Integer
        Get
            Return _Value
        End Get
        Set(newValue As Integer)
            If newValue < Me.Value AndAlso newValue > 0 Then
                Throw New NotImplementedException("ProgressBarWithRender does not support decrementing the value")
            End If
            Me._Value = newValue
        End Set
    End Property

    Public Sub PerformStep()
        ' Ensure step doesn't exceed boundaries
        If Value + [Step] > Maximum Then
            Value = Maximum
        ElseIf Value + [Step] < Minimum Then
            Value = Minimum
        Else
            Value += [Step]
        End If

        ' We are limited by the Renderers Chunk Width, so we possibly can't draw every step if there is a high maximum
        Dim g As Graphics = Me.CreateGraphics
        ProgressBarRenderer.DrawHorizontalChunks(g, ProgressBarRectangles(Value - Minimum))
        RaiseEvent OnRendered(Value)

    End Sub

    Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)
        If Not ProgressBarRenderer.IsSupported Then
            Throw New NotImplementedException("Progress Bar Rendering is not supported")
        End If
        ProgressBarRenderer.DrawHorizontalBar(e.Graphics, ClientRectangle)
    End Sub

    Private Sub CalculateTickSizes()
        ' Changing the Maximum will change the tick rectangle size
        ProgressBarRectangles = New Rectangle(Maximum) {}
        Dim chunkThickness As Integer = ProgressBarRenderer.ChunkThickness + (ProgressBarRenderer.ChunkSpaceThickness * 2)
        Dim tickThickness As Double = ((ClientRectangle.Width - (InnerPadding * 2)) - (ProgressBarRenderer.ChunkSpaceThickness * 2)) / (Maximum - Minimum)
        If tickThickness < chunkThickness Then
            Debug.Print("This will go wrong because we can't draw small enough chunks...")
        End If
        For i As Integer = 0 To Maximum
            Dim filledRectangle As Integer = CInt(tickThickness * i)
            ProgressBarRectangles(i) = New Rectangle(ClientRectangle.X + InnerPadding,
                                                     ClientRectangle.Y + InnerPadding,
                                                     filledRectangle,
                                                     ClientRectangle.Height - (InnerPadding * 2))
        Next
    End Sub

End Class
导入系统
导入系统。绘图
导入System.Windows.Forms
导入System.Windows.Forms.VisualStyles
公开课表格1
继承形式
Private WithEvents bar1作为ProgressBarWithRender=New ProgressBarWithRender()
公共分新()
初始化组件()
Me.Size=新尺寸(500500)
bar1.位置=新点(100100)
bar1.宽度=300
bar1.高度=50
bar1.最大值=30
bar1.步骤=1
控件。添加(bar1)
端接头
Public Sub OnRendered(ByVal valueRendered为整数)处理bar1.OnRendered
如果valueRendered=bar1.最大值,则
“我们知道一切都已经画好了
我
如果结束
端接头
_
公共共享子主目录()
'下面对EnableVisualStyles的调用不影响
'progressr.IsSupported是否为真;像
'只要操作系统启用视觉样式,
“IsSupported是真的。
Application.EnableVisualStyles()
Application.Run(新Form1())
端接头“主
Private Sub Form1\u Click(发件人作为对象,e作为System.EventArgs)处理我。单击
对于i=1到30
bar1.PerformStep()
线程。线程。睡眠(10)
下一个
端接头
“最终类别”表格1
公共类ProgressBarWithRender
继承控制权
公共委托子呈现DevenTargs(ByVal值呈现为整数)
公共事件OnRenderEventArgs呈现为RenderEventArgs
Private ProgressBarRectangles()作为矩形
公共属性[步骤]为整数
公共属性InnerPadding为整数=3
Private\u最大值为整数
公共属性最大值为整数
收到
返回最大值
结束
设置(值为整数)
_最大值=最大值
CalculateTickSizes()
端集
端属性
私有_最小值为整数
公共属性最小值为整数
收到
返回最小值
结束
设置(值为整数)
_最小值=最小值
CalculateTickSizes()
端集
端属性
私有_值为整数
作为整数的公共属性值
收到
返回值
结束
设置(新值为整数)
如果newValue0,则
抛出新的NotImplementedException(“ProgressBarWithRender不支持递减值”)
如果结束
Me.\u Value=newValue
端集
端属性
公共子性能步骤()
'确保步骤不超过边界
如果值+[Step]>最大值,则
值=最大值
ElseIf值+[步进]<最小值
值=最小值
其他的
值+=[步进]
如果结束
我们受到渲染器块宽度的限制,因此如果最大值较高,我们可能无法绘制每个步骤
尺寸g为Graphics=Me.CreateGraphics
ProgressBarRectangles.DrawHorizontalChunks(g,ProgressBarRectangles(值-最小))
RaiseEvent OnRendered(值)
端接头
受保护的覆盖子OnPaint(如System.Windows.Forms.PaintEventArgs)
MyBase.OnPaint(e)
如果不支持Derrer.issupport,则
抛出新的NotImplementedException(“不支持进度条呈现”)
如果结束
ProgressDerrer.DrawHorizontalBar(如图形、ClientRectangle)
端接头
私有子计算
'更改最大值将更改勾号矩形大小
ProgressBarRectangles=新矩形(最大值){}
将chunkThickness设置为整数=progressBylder.Chunk
Private Sub SetProgressNoAnimation(ByVal value As Integer)
    ' To get around the progressive animation, we need to move the 
    ' progress bar backwards.
    If (value = progressBarCarga.Maximum) Then
        ' Special case as value can't be set greater than Maximum.
        progressBarCarga.Maximum = (value + 1)
        ' Temporarily Increase Maximum
        progressBarCarga.Value = (value + 1)
        ' Move past
        progressBarCarga.Maximum = value
        ' Reset maximum
    Else
        progressBarCarga.Value = (value + 1)
        ' Move past
    End If
    progressBarCarga.Value = value
    ' Move to correct value
End Sub