JANeets Ответов: 1

Как заставить этот код работать с многопоточностью


Я создаю оценочную доску KPI для нашего склада и столкнулся со следующей проблемой.
У меня есть пользовательский элемент управления под названием order tile, который имеет следующий код:

Public Class OrderTile



    Private _BorderBoxColor As Color
    Public Property BorderBoxColor() As Color
        Get
            Return _BorderBoxColor
        End Get
        Set
            _BorderBoxColor = Value
            ChangeBackColor_Threadsafe(_BorderBoxColor)
        End Set
    End Property
    Private _SaleOrder As String
    Public Property SalesOrder() As String
        Get
            Return _SaleOrder
        End Get
        Set
            _SaleOrder = Value
            UpdateText_Threadsafe(lblSODS, _SaleOrder)
        End Set
    End Property
    Private _Customer As String
    Public Property Customer() As String
        Get
            Return _Customer
        End Get
        Set
            _Customer = Value
            UpdateText_Threadsafe(lblCustomer, _Customer)
        End Set
    End Property
    Private _SalesValue As String
    Public Property SalesValue() As String
        Get
            Return _SalesValue
        End Get
        Set
            _SalesValue = Value
            UpdateText_Threadsafe(lblValue, _SalesValue)
        End Set
    End Property
    Private _CountdownTime As TimeSpan
    Public Property CountDownTime() As TimeSpan
        Get
            Return _CountdownTime
        End Get
        Set
            _CountdownTime = Value
            tmrCountdown.Interval = 500
            tmrCountdown.Start()

        End Set
    End Property
    Private _TargetDT As Date
    Public Property TargetDT() As Date
        Get
            Return _TargetDT
        End Get
        Set
            _TargetDT = Value

        End Set
    End Property
    Private _Flash As Boolean



    Public Property Flash() As Boolean
        Get
            Return _Flash
        End Get
        Set
            _Flash = Value
            If _Flash = False Then
                tmrFlashBorder.Stop()
                'Me.BackColor = _BorderBoxColor
                ChangeBackColor_Threadsafe(_BorderBoxColor)
            ElseIf _Flash = True Then
                tmrFlashBorder.Start()
            End If

        End Set
    End Property

    Private Sub tmrCountdown_Tick(sender As Object, e As EventArgs) Handles tmrCountdown.Tick
        Dim ts As TimeSpan = _TargetDT.Subtract(DateTime.Now)
        If ts.TotalMilliseconds > 0 Then
            'lblCountDownTimer.Text = ts.ToString("mm\:ss")
            UpdateText_Threadsafe(lblCountDownTimer, ts.ToString("mm\:ss"))
        Else
            'lblCountDownTimer.Text = "00:00"
            UpdateText_Threadsafe(lblCountDownTimer, "00:00")
            tmrCountdown.Stop()
        End If

    End Sub

    Private Sub tmrFlashBorder_Tick(sender As Object, e As EventArgs) Handles tmrFlashBorder.Tick
        If Me.BackColor = Color.White Then
            Me.BackColor = _BorderBoxColor

        ElseIf Me.BackColor = _BorderBoxColor Then
            Me.BackColor = Color.White

        End If

    End Sub
    Delegate Sub UpdateText_Delegate(ByVal Lable As DevExpress.XtraEditors.LabelControl, ByVal text As String)
    Private Sub UpdateText_Threadsafe(ByVal Lable As DevExpress.XtraEditors.LabelControl, ByVal text As String)
        If Lable.InvokeRequired Then
            Dim MyDelegate As New UpdateText_Delegate(AddressOf UpdateText_Threadsafe)
            Me.Invoke(MyDelegate, New Object() {Lable, text})
        Else
            Lable.Text = text
        End If
    End Sub

    Delegate Sub ChangeBackColor_Delegate(ByVal BackColor As Color)
    Private Sub ChangeBackColor_Threadsafe(ByVal BackColor As Color)
        If Me.InvokeRequired Then
            Dim MyDelegate As New ChangeBackColor_Delegate(AddressOf ChangeBackColor_Threadsafe)
            Me.Invoke(MyDelegate, New Object() {Me, BackColor})
        Else
            Me.BackColor = BackColor
        End If
    End Sub

End Class


и вот код, который использует этот элемент управления. этот код вызывается из фонового рабочего DoWork.

Private Sub DrawTiles()
     Dim XSpace = 368, YSpace = 120, XMax = 3, YMax = 4
     OrderTiles.DefaultView.Sort = "ID ASC"
     'grpOrderTiles.Controls.Clear()
     ClearTiles_Treadsafe(grpOrderTiles)
     Dim TC = 0
     Dim TileCount As Integer = OrderTiles.Rows.Count
     For i = 0 To TileCount - 1
             TC = i + 1


         Dim NewTile As New FDVICKPIScreenV4.OrderTile

             NewTile.Name = "OrderTile" & OrderTiles.Rows(i).Item(ColTileID).ToString
             NewTile.SalesOrder = OrderTiles.Rows(i).Item(ColTileSalesOrderNo).ToString
             NewTile.Customer = OrderTiles.Rows(i).Item(ColTileCustomer).ToString
             NewTile.SalesValue = OrderTiles.Rows(i).Item(ColTileSalesValue).ToString
             NewTile.BorderBoxColor = Color.FromName(OrderTiles.Rows(i).Item(ColTileBox).ToString)
             NewTile.CountDownTime = TimeSpan.FromMinutes(30)
             NewTile.Flash = OrderTiles.Rows(i).Item(ColTileFlash)
             NewTile.TargetDT = OrderTiles.Rows(i).Item(ColTileTargetDT)


             If TC = 1 Then
                 NewTile.Location = New Point(13, 34)
             ElseIf TC > 1 AndAlso TC <= 5 Then
                 NewTile.Location = New Point(13 + XSpace * i, 34) '34 + YSpace * i
             ElseIf TC > 5 AndAlso TC <= 10 Then
                 NewTile.Location = New Point(13 + XSpace * (i - 5), 154)
             ElseIf TC > 10 AndAlso TC <= 15 Then
                 NewTile.Location = New Point(13 + XSpace * (i - 10), 274)
             ElseIf TC > 15 AndAlso TC <= 20 Then
                 NewTile.Location = New Point(13 + XSpace * (i - 15), 394)
             End If

             AddTile_Treadsafe(grpOrderTiles, NewTile)

     Next

 End Sub


Код работает нормально, когда я вызываю его все в одном потоке, но когда я вызываю его из фонового рабочего, то есть когда я получаю "исключение User-Unhandled System.NullReferenceException: 'ссылка на объект не установлена на экземпляр объекта.'
Dim NewTile As FDVICKPIScreenV4.OrderTile
в подлодке DrawTiles.

Что я уже пробовал:

Я пытался реализовать SyncLock, но не смог заставить это работать. Я просто недостаточно знаю о многопоточности, чтобы решить эту проблему.

Вся помощь очень ценится.

CHill60

Вы не должны взаимодействовать с графическим интерфейсом из вашего рабочего потока. Ознакомьтесь с некоторыми статьями здесь о резьбе, там есть несколько хороших примеров, которые вы можете адаптировать

Ralf Meier

Как уже упоминалось ранее, графический интерфейс и Backgroundworker, задача или поток-это разные вещи.
Если вы сделаете свой рабочий поток безопасным, вы потеряете временные преимущества, которых вы пытаетесь достичь, потому что вы даете своему элементу управления (графическому интерфейсу) информацию, чтобы сделать что-то, когда рабочий уже приостановлен. Лучше всего провести эксперименты с нарезанием резьбы сначала в очень легком варианте ...

1 Ответов

Рейтинг:
2

Gerry Schmitz

Вы неправильно использовали возможности BackgroundWorker "UI reporting"; вы должны использовать метод "ReportProgress" и связанный с ним обработчик событий:

BackgroundWorker.Метод ReportProgress (System.ComponentModel)[^]