自定义类事件触发后,表单不会更新 [英] Form is not updating, after custom class event is fired

查看:191
本文介绍了自定义类事件触发后,表单不会更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到一个问题,即我的主要表单不更新,即使我看到事件的火了。让我解释一下这个情况,并分享我的一些代码,我相信这将是可怕的,因为我是一个业余。



我创建了一个类来接受设置用于在后台运行进程。我在该类中添加了一些自定义事件,所以我可以在我的形式而不是一个计时器。



我把休息一下,我看到他们一开始安装就会被启动。



我看看数据,它遇到,没有异常抛出。



最初我认为这是因为datagridview有一些延迟问题。我设置为双缓冲通过一些技巧,我发现,但它没有关系。在数据显示在数据网格之前,仍然有大约10秒的延迟。



我想了一下,决定我真的不需要datagridview,与多行文本框,但它没有什么区别。仍然需要10秒或更长时间才能显示表单/文字框的更新。



我已经在下面加入了部分代码。

 公共共享WithEvents np As NewProcess 






  Private Sub Form1_Load(ByVal sender As Object,ByVal e As System.EventArgs)Handles Me.Load 
Try
np = New NewProcess
AddHandler np.InstallFinished,AddressOf np_InstallFinished
AddHandler np.InstallStarted,AddressOf np_InstallStarted
Catch ex As Exception

结束尝试

End Sub






 保护子np_InstallFinished(ByVal描述As String,ByVal ExitCode As Integer)
InstallInProcess = False

如果不是说明=没有然后
如果不是ExitCode =没有然后
AddLog(String.Format({0}({1})。,说明,ExitCode的完成安装))
Else
AddLog(String.Format({0} ,Description))
End If
End If
RefreshButtons()
UpdateListofApps()
np.Dispose()
End Sub






 受保护子np_InstallStarted描述As String)
InstallInProcess = True

如果不是描述=没有然后AddLog(String.Format(开始安装{0}。,说明))
End Sub






  public class NewProcess 
Dim ProcessName As String
Dim ProcessVisibile As Boolean
Dim Arguments As String
Dim WaitforExit As Boolean
Dim说明As String
Dim ShellExecute As布尔
Dim EC As Integer = Nothing'退出代码
私有IsBusy作为布尔值=无
Dim th As Threading.Thread

公共事件InstallFinished(ByVal描述As String ,ByVal ExitCode As Integer)

公共事件InstallStarted(ByVal描述As String)

公共函数Busy()As Boolean
如果IsBusy = Nothing then Return False
返回IsBusy
结束函数

公共函数ExitCode()As Integer
返回EC
结束函数

公共函数ProcessDescription )As String
返回说明
结束函数

'''< summary>
'''启动新的多线程进程。
'''< / summary>
'''< param name =path>要运行的文件的路径< / param>
'''< param name =Visible>应用程序是否可见?< / param&
'''< param name =Arg>参数< / param>
'''< param name =WaitforExit>等待应用程序退出?< / param>
'''< param name =Description>描述将显示在日志中< / param>
'''< remarks>开始一个新的多线程进程。< / remarks>
Public Sub StartProcess(ByVal path As String,ByVal Visible As Boolean,可选ByVal Arg As String = Nothing,可选ByVal WaitforExit As Boolean = False,可选ByVal描述As String = Nothing)

尝试
Me.ProcessName = path
Me.ProcessVisibile = Visible
如果Arguments = Nothing然后Me.Arguments = Arg
Me.Description =说明
Me.WaitforExit = WaitforExit

如果IsBusy和WaitforExit然后
MessageBox.Show(另一个安装已经在进行中,请等待上一次安装完成。,警告,MessageBoxButtons.OK,MessageBoxIcon。警告)
退出子
结束如果

如果不是fn_FileExists(ProcessName)然后
MessageBox.Show(找不到文件& ProcessName&。 ,Could not start process because file is missing。,MessageBoxButtons.OK,MessageBoxIcon.Error)
退出Sub
结束如果

th = New Threading.Thread(AddressOf NewThread)

使用th
.IsBackground = True
如果不是说明没有则说明.Name =说明
.Start()
End With
Catch ex As Exception

结束尝试
结束子

Private Sub NewThread()
Dim p作为进程

尝试
p =新进程

使用p
.EnableRaisingEvents = True
.StartInfo.Arguments = Arguments
.StartInfo.FileName = ProcessName
.StartInfo.CreateNoWindow = ProcessVisibile
使用
结束
如果ProcessVisibile则
p.StartInfo.WindowStyle = ProcessWindowStyle.Normal
Else
p.StartInfo。 WindowStyle = ProcessWindowStyle.Hidden
结束如果

p.Start()
IsBusy = True
RaiseEvent InstallStarted(说明)

如果WaitforExit然后
Do While p.HasExited = False
Threading.Thread.Sleep(500)
Loop
IsBusy = False
RaiseEvent InstallFinished(说明,p.ExitCode)
End If

EC = p.ExitCode

Catch ex As Exception

结束尝试
结束子

Public Sub Dispose()
ProcessName = Nothing
ProcessVisibile = Nothing
Arguments = Nothing
WaitforExit = Nothing
说明= Nothing
EC =没有
InstallInProcess =没有
th.Join()
MemoryManagement.FlushMemory()
结束子

结束类






  Sub AddLog(ByVal s As String)
Try

s = String.Format([{0}] {1},TimeOfDay.ToShortTimeString,s)

Form1.tbLogs.AppendText ; vbCrLf)

使用st As New StreamWriter(LogFilePath,True)
st.WriteLine(s)
st.Flush()
结束使用

Catch ex As Exception
结束尝试
结束子

?我完全失去了。



我试过添加application.doevents,me.refresh和很多其他事情:(

解决方案

  Form1.tbLogs.AppendText(s& vbCrLf)
/ pre>

标准VB.NET陷阱Form1是一个类名,而不是对表单的引用不幸的是,VB.NET从VB6中实现了一个时间错误当你使用线程时,它会崩溃,你会得到另一个自动创建的表单对象,因为它的Show()方法从未被调用而不可见。线程不是一个消息循环。



你需要传递一个引用到用户正在查看的工作类的实际表单对象。我在Form1代码中,你还必须使用Control.Invoke,因为它是不合法的更新控件从另一个线程。我建议你启动一个事件,而Form1可以订阅,所以你的工作类是' t感染UI的实现细节。


I'm having an issue where my main form isn't updating even though I see the event fire off. Let me explain the situation and share some of my code which I'm sure will be horrible since I'm an amateur.

I created a class to take in the settings for running a process in the background. I add some custom events in that class so I could use that in my form instead of a timer.

I put a break on the two subs for that handle those events and I see them get kicked off as soon as an install starts.

I look at the data and it's coming across and no exceptions are thrown.

At first I thought it was because the datagridview had some latency issues. I set that to be double buffered through some tricks I found but it didn't matter. There was still a roughly 10 second delay before the data showed up in the datagrid.

I thought about it and decided I really didn't need a datagridview and replaced the control with a multiline textbox, but it didn't make a difference. It's still taking 10 seconds or longer to show updates to the form/textbox.

I've included some of my code below.

Public Shared WithEvents np As NewProcess


Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Try
            np = New NewProcess
            AddHandler np.InstallFinished, AddressOf np_InstallFinished
            AddHandler np.InstallStarted, AddressOf np_InstallStarted
        Catch ex As Exception

        End Try

    End Sub


Protected Sub np_InstallFinished(ByVal Description As String, ByVal ExitCode As Integer)
    InstallInProcess = False

    If Not Description = Nothing Then
        If Not ExitCode = Nothing Then
            AddLog(String.Format("Completed install of {0} ({1}).", Description, ExitCode))
        Else
            AddLog(String.Format("Completed install of {0}.", Description))
        End If
    End If
    RefreshButtons()
    UpdateListofApps()
    np.Dispose()
End Sub


Protected Sub np_InstallStarted(ByVal Description As String)
    InstallInProcess = True

    If Not Description = Nothing Then AddLog(String.Format("Started the install of {0}.", Description))
End Sub


Public Class NewProcess
    Dim ProcessName As String
    Dim ProcessVisibile As Boolean
    Dim Arguments As String
    Dim WaitforExit As Boolean
    Dim Description As String
    Dim ShellExecute As Boolean
    Dim EC As Integer = Nothing 'Exit Code
    Private IsBusy As Boolean = Nothing
    Dim th As Threading.Thread

    Public Event InstallFinished(ByVal Description As String, ByVal ExitCode As Integer)

    Public Event InstallStarted(ByVal Description As String)

    Public Function Busy() As Boolean
        If IsBusy = Nothing Then Return False
        Return IsBusy
    End Function

    Public Function ExitCode() As Integer
        Return EC
    End Function

    Public Function ProcessDescription() As String
        Return Description
    End Function

    ''' <summary>
    ''' Starts a new multithreaded process.
    ''' </summary>
    ''' <param name="path">Path of the File to run</param>
    ''' <param name="Visible">Should application be visible?</param>
    ''' <param name="Arg">Arguments</param>
    ''' <param name="WaitforExit">Wait for application to exit?</param>
    ''' <param name="Description">Description that will show up in logs</param>
    ''' <remarks>Starts a new multithreaded process.</remarks>
    Public Sub StartProcess(ByVal path As String, ByVal Visible As Boolean, Optional ByVal Arg As String = Nothing, Optional ByVal WaitforExit As Boolean = False, Optional ByVal Description As String = Nothing)

        Try
            Me.ProcessName = path
            Me.ProcessVisibile = Visible
            If Arguments = Nothing Then Me.Arguments = Arg
            Me.Description = Description
            Me.WaitforExit = WaitforExit

            If IsBusy And WaitforExit Then
                MessageBox.Show("Another install is already in process, please wait for previous install to finish.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning)
                Exit Sub
            End If

            If Not fn_FileExists(ProcessName) Then
                MessageBox.Show("Could not find file " & ProcessName & ".", "Could not start process because file is missing.", MessageBoxButtons.OK, MessageBoxIcon.Error)
                Exit Sub
            End If

            th = New Threading.Thread(AddressOf NewThread)

            With th
                .IsBackground = True
                If Not Description Is Nothing Then .Name = Description
                .Start()
            End With
        Catch ex As Exception

        End Try
    End Sub

    Private Sub NewThread()
        Dim p As Process

        Try
            p = New Process

            With p
                .EnableRaisingEvents = True
                .StartInfo.Arguments = Arguments
                .StartInfo.FileName = ProcessName
                .StartInfo.CreateNoWindow = ProcessVisibile
            End With

            If ProcessVisibile Then
                p.StartInfo.WindowStyle = ProcessWindowStyle.Normal
            Else
                p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden
            End If

            p.Start()
            IsBusy = True
            RaiseEvent InstallStarted(Description)

            If WaitforExit Then
                Do While p.HasExited = False
                    Threading.Thread.Sleep(500)
                Loop
                IsBusy = False
                RaiseEvent InstallFinished(Description, p.ExitCode)
            End If

            EC = p.ExitCode  

        Catch ex As Exception

        End Try
    End Sub

    Public Sub Dispose()
        ProcessName = Nothing
        ProcessVisibile = Nothing
        Arguments = Nothing
        WaitforExit = Nothing
        Description = Nothing
        EC = Nothing
        InstallInProcess = Nothing
        th.Join()
        MemoryManagement.FlushMemory()
    End Sub

End Class


Sub AddLog(ByVal s As String)
    Try

        s = String.Format("[{0}] {1}", TimeOfDay.ToShortTimeString, s)

        Form1.tbLogs.AppendText(s & vbCrLf)

        Using st As New StreamWriter(LogFilePath, True)
            st.WriteLine(s)
            st.Flush()
        End Using

    Catch ex As Exception
    End Try
End Sub

Any idea's? I'm at a complete loss.

I've tried adding application.doevents, me.refresh and quite a few other things :(

解决方案

    Form1.tbLogs.AppendText(s & vbCrLf)

Standard VB.NET trap. Form1 is a class name, not a reference to the form. Unfortunately, VB.NET implemented an anachronism from VB6 where that was legal. It however falls apart when you use threads. You'll get another form object automatically created, one that isn't visible because its Show() method was never called. Otherwise dead as a doornail since the thread is not pumping a message loop.

You'll need to pass a reference to the actual form object that the user is looking at to the worker class. The value of Me in the Form1 code. You will also have to use Control.Invoke since it isn't legal to update controls from another thread. I recommend you fire an event instead, one that Form1 can subscribe to, so that your worker class isn't infected with implementation details of the UI.

这篇关于自定义类事件触发后,表单不会更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆