【问题标题】:Is it correct to raise custom events from Timer/ BackgroundWorker Completed that go on and update UI从 Timer/BackgroundWorker Completed 引发自定义事件是否正确并继续更新 UI
【发布时间】:2012-11-30 15:05:15
【问题描述】:

我的 winforms 应用程序需要与硬件设备交互。 显示是一种工作流程……在步骤 1 .. 完成之后.. 转到步骤 2 .. 等等。 显示是动态的,控件在运行时可见并启动活动(这些用户控件中的每一个都使用计时器/ BGWorker)。

我正在从 timer/BGWorker_Completed 引发自定义事件。这将有助于进行下一步并更新 UI。我做的对吗?

我是 winforms 的新手,只是无法弄清楚显示失败的原因。

我没有发现任何异常...但是在特定步骤之后我看不到控件!我不知道在哪里以及如何调试这种情况。如果我单独执行主窗体..我也可以看到显示。 但是,如果我从登录页面导航/更改主表单中的选项卡并返回。我看不到显示。

我尝试在 UI 上调用更新之前进行检查,并按以下相同顺序进行。 Thread.Current.IsBackground 返回 false,control.IsHandleCreated 返回 true,否则我使用 dim x=Control.handle()) 创建它 Me.InvokeRequired/ Control.invokeRequired 返回 false(我想要的方式)。但是我没有看到 userControl 正在显示...可见性/颜色/一切都在设置中(在程序中)..我能够看到硬件交互!!!..但是没有显示:-((第 4 步及以后)

我在登录页面...或 tabChanged 事件中没有做任何花哨的事情。 (在选项卡更改事件上......我只清理打开的连接/关闭 bg 工作人员(如果有的话)......将在需要时重新连接)

如果我需要做任何事情,请告诉我......以及如何解决这个问题。 我还在初始化每个用户控件/主窗体的组件后不久调用 EnsureHandleIsCreated(control) 子例程。

'Code in Login Form
    Dim myForm as new MainForm()
    myForm.ShowDialog(Me) ' here i also tried with show/showDialog.. with/without ownerForm 
    Me.Hide() ' Hide login page

'Code for checking if handle is created or not
    Public Sub CheckForInvalidThread()
        frmMain.CheckForIllegalCrossThreadCalls() = True
        If Thread.CurrentThread.IsBackground Or Not Thread.CurrentThread.Name Is THREAD_MAIN_NAME Then
            Throw New InvalidOperationException(THREAD_IS_INVALID)
        End If
        If Not Me.IsHandleCreated Then
            Dim x = Me.Handle()
            Thread.Sleep(20)
        End If
    End Sub

    Public Sub EnsureHandleIsCreated(ByRef c As Control)
        Try
            If Not c.IsHandleCreated Then
                Dim h As System.IntPtr = c.Handle()
            End If
        If c.HasChildren Then
                For Each child As Control In c.Controls
                    Try
                        EnsureHandleIsCreated(child)
                    Catch ex As Exception
                        DAL.LogException(ex.Message, ex.StackTrace, "EnsureHandleIsCreated: " & c.Name, 0)
                    End Try

                Next
            End If
        Catch ex As Exception
            DAL.LogException(ex.Message, ex.StackTrace, "EnsureHandleIsCreated: " & c.Name, 0)
        End Try
    End Sub 

    Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        lbRole.Text = RoleName
        lbName.Text = UserName
        Try
            Me.Activate()

            If Thread.CurrentThread.IsBackground Then
                Throw New ApplicationException(THREAD_IS_INVALID)
            End If
            Thread.CurrentThread.Name = THREAD_MAIN_NAME

            CheckForInvalidThread()
            clGlobals.frmMain = Me

            If RoleName Is Nothing Or String.IsNullOrEmpty(RoleName) Or RoleName.Equals("OPERATOR", StringComparison.InvariantCultureIgnoreCase) Then
                tcEtch.TabPages("tbMaintenance").Hide()
                tcEtch.TabPages("tbAdmin").Hide()
            End If
        Catch ex As Exception
             MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
    Exit Sub
        Finally

        End Try
        Initiate()
    End Sub 

    Public Sub GoToNextStep() Handles Me.GoToNextStepEvent
        Try
           CheckForInvalidThread()
           CurrentStep = CurrentStep + 1

            Select Case CurrentStep
                Case 0 To 2
                    If Me.InvokeRequired Then
                        _delegateDisplayInitiate = AddressOf DisplayStep2
                        Me.Invoke(_delegateDisplayInitiate)
                    Else
                        DisplayStep2()
                    End If

                Case 3
                    If ucCycleStart.InvokeRequired Then
                        _delegateDisplayInitiate = AddressOf DisplayStep3
                        ucCycleStart.Invoke(_delegateDisplayInitiate)
                    Else
                        DisplayStep3()
                    End If
                Case 4
                    If Me.InvokeRequired Or ucPartCountVerification.InvokeRequired Or Thread.CurrentThread.IsBackground Then
                        Throw New Exception("Check out")
                    End If

                    EnsureHandleIsCreated(ucPartCountVerification)
                    If ucPartCountVerification.InvokeRequired Then
                        _delegateDisplayInitiate = AddressOf DisplayStep4
                        ucPartCountVerification.Invoke(_delegateDisplayInitiate)
                    Else
                        DisplayStep4()
                    End If

             End Select
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub


     Private Sub DisplayStep4() Handles Me.DisplayStep4Event
        ucPartCountVerification.Visible = True
        ucPartCountVerification.Show()
        ucPartCountVerification.Initiate()
    End Sub

     Public Sub Initiate()
            frmMain.CheckForInvalidThread()

            'Just to verify if things are fine.. i put in this check below
        If Me.InvokeRequired Or pnStep4.InvokeRequired Or Not (Me.IsHandleCreated And pnStep4.IsHandleCreated ) Then
                MessageBox.Show("cHECK OUT")
            Else
                Me.Visible = True
                pnStep4.Visible = True

                Me.BackColor = Color.Red
                pnStep4.BackColor = Color.Gray

                Dim height = Me.Size.Height
                Dim width = Me.Size.Width
                MessageBox.Show(height.ToString() + Me.InvokeRequired.ToString())
            End If

    end Sub

【问题讨论】:

  • 这给了我一些希望。谢谢你。明天将在代码中发布。您的意见肯定会对我有很大帮助。感谢 P6345uk,感谢 Jon。
  • 是否可以提供您的电子邮件 ID?可以通过 findMadan@gmail.com 联系到我

标签: vb.net winforms multithreading events invoke


【解决方案1】:

您当然可以从BackgroundWorkerTimer 引发事件。您已经在检查InvokeRequired,这是正确的做法。然后,您需要调用 BeginInvoke(或 Invoke,如果需要同步)来更新您的 UI。

【讨论】:

  • 这给了我一些希望。谢谢你。明天将在代码中发布。感谢 P6345uk,感谢 Jon。
【解决方案2】:

你在正确的轨道上。在处理来自某些库的事件时,您无法确定它们是在哪个线程上传递的。这是令人失望的,因为 Windows 窗体具有从 GUI 线程进行调用调用的限制。 This MSDN article 解释了问题。

您与InvokeRequired 走在正确的轨道上。它可以让您查看您是否在正确的线程上,但您需要一种方法来处理这种情况并在正确的线程上重新调用事件。

这是我在 C# 中的操作方式...

public delegate void uiEventHandler();

void uiEvent(object sender, EventArgs e)
{
    if (InvokeRequired)
    {
        // We are not on the correct thread. We'd better get there.
        var eh = new uiEventHandler(uiEvent);
        Invoke(eh, new object[] { sender, e });
        return; //This thread has no more work to do.
    }

    // Do your work here that requires being performed on the GUI thread.
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-15
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    • 1970-01-01
    • 2014-05-27
    • 1970-01-01
    • 2013-07-29
    相关资源
    最近更新 更多