0

我的 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
4

2 回答 2

0

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

于 2012-11-30T15:22:10.773 回答
0

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

你在正确的轨道上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.
}
于 2012-11-30T15:22:17.573 回答