影响指定集合的​​父集合的引用

时间:2013-09-27 15:23:28

标签: .net vb.net multithreading winforms

任务: 我有一个要求(用户可以一个接一个地连续保存而无需等待)所以我选择了多线程,我即将用Queue概念完成它。但我在一个场景中陷入困境。

关于代码的任务: 应用程序中有许多集合和对象,我为此创建了一个Queue类,并在其中创建了一个单独的集合和对象,并将所有这些集合和对象分配给队列类对象。每当用户保存更改时,所有这些集合和对象都被填充并分配给队列集合和对象并添加到队列中,因此后台工作者获取集合和对象并执行该过程。这样做是为了确保保存的值是正确的,因为有连续保存。

情境: 应用程序有一个网格,用户在其中选择一行并使用其中的唯一ID将值加载到集合中并绑定到表单。因此,用户将更新值并单击“保存”。然后他点击下一行,一旦加载了值,他再次进行更改并保存。这就是出现问题的地方。

由于我已将所有先前的集合分配给队列集合,当用户进行更改并单击“保存”并进入下一行并单击该集合时,应用程序中已存在的集合将重置(从为每个行选择重置集合以加载所选值)并加载新值。这使得更改反映了我在队列中的集合。因此,保存功能会受到影响。

现在我需要的是,即使收集现在已经重置,队列中的收集也不会受到影响。

我如何实现?

//代码:

的MainForm:

Public Class Form1

''Queue collection of a class
'Dim oQueueCollection As New Queue(Of MyItem)
''Backgroundworker instance
'Dim bw As BackgroundWorker = New BackgroundWorker()


'Backgroundworker instance
Dim m_oBackgroundWorker As BackgroundWorker = Nothing

'Queue collection of a class
Dim m_cQueueCollection As New Queue(Of BackgroundworkerController)

Dim m_cBackgroundworkerController As New BackgroundworkerController


Private Property Item As New Item

''' <summary>
''' Get or set the Item Pricing collection.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property ItemPricingCollection() As Collection(Of ItemPricing) = New Collection(Of ItemPricing)


Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    'Initialize the backgroud worker
    m_oBackgroundWorker = New BackgroundWorker()

    'Call the completed method once the thread completes it work
    m_oBackgroundWorker.WorkerReportsProgress = True


    'Create thread and continue with the process
    AddHandler m_oBackgroundWorker.DoWork, AddressOf bw_DoWork

    'Method called after the thread work completes
    AddHandler m_oBackgroundWorker.RunWorkerCompleted, AddressOf bw_RunWorkerCompleted

End Sub

Private Sub SaveItem()
    'Shows the item that starts the save.
    MsgBox(m_cQueueCollection.First().Item.ItemNo)

    'Makes the thread to sleep for the delay(In between we can make the next save)--- Testing purpose only
    System.Threading.Thread.Sleep(13000)
End Sub

Private Sub bw_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs)

    'Calls the save method
    SaveItem()

    'Shows the saved/Completed item's No
    'This Id will be assinged to all the places in which the application needs the current itemno(PK).
    e.Result = m_cQueueCollection.First().Item.ItemNo & " is Completed"

    'Removes the Completed item in queue
    m_cQueueCollection.Dequeue()
End Sub

Private Sub bw_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
    'shows the result
    MsgBox(e.Result)

    'Check the collection and disable the timer in order not to run un necessarily
    If (m_cQueueCollection.Count = 0) Then
        Timer1.Enabled = False
        Timer1.Stop()
    End If
End Sub


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    'ThreadPoolTest()

    'Sets the class to a property
    'this is done in order to have multiple class/collections inside the queue for processing
    m_cBackgroundworkerController.Item = Me.Item
    m_cBackgroundworkerController.ItemPricingCollection = Me.ItemPricingCollection

    'I have trided
    'm_cBackgroundworkerController.Item = DirectCast(Me.Item.clone(), Item)


    'Adds the collection to the queue
    m_cQueueCollection.Enqueue(m_cBackgroundworkerController)

    'enables the timer
    Timer1.Enabled = True

End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    Me.Item = Nothing
    Me.ItemPricingCollection.Clear()
End Sub

'Checks the collection and background worker and start the thread process for every 1 second.
'If the thread is running it just exits.

Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    If (m_cQueueCollection.Count > 0 AndAlso Not m_oBackgroundWorker.IsBusy) Then
        m_oBackgroundWorker.RunWorkerAsync()
    End If
End Sub

End Class

// BackgroundWorkerClass:

Public Class BackgroundworkerController

Implements IDisposable



Private Shared s_bDisposed As Boolean
''' <summary>
''' Get or set the item.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>  
Public Property Item() As Item = New Item



''' <summary>
''' Get or set the Item Pricing collection.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property ItemPricingCollection() As Collection(Of ItemPricing) = New Collection(Of ItemPricing)

End class

//其中一个课程:

<Serializable()> _
Public Class Item
    Implements IDisposable

    Private m_sItemNo As String = ""
   Private sEnvironmentCode sItemNo As String = ""
    Private m_bIsChanged As Boolean
    Private m_bIsInDatabase As Boolean



'jw10 end new collections added

''' <summary>
''' Get or set the Item Number.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property ItemNo() As String

    Get
        Return Me.m_sItemNo
    End Get

    Set(ByVal value As String)
        If Not Me.IsLoading Then Me.IsChanged = True
        Me.m_sItemNo = value
    End Set

End Property

''' <summary>
''' Get or set the environment code.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property EnvironmentCode() As String

    Get
        Return Me.m_sEnvironmentCode
    End Get

    Set(ByVal value As String)
        If Me.m_sEnvironmentCode <> value Then Me.m_bIsChanged = True
        Me.m_sEnvironmentCode = value
    End Set

End Property



''' <summary>
''' Get or set the changed flag.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property IsChanged() As Boolean

    Get
        Return Me.m_bIsChanged
    End Get

    Set(ByVal Value As Boolean)
        Me.m_bIsChanged = Value
    End Set

End Property



''' <summary>
''' Get or set the is in database flag.
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Property IsInDatabase() As Boolean

    Get
        Return Me.m_bIsInDatabase
    End Get

    Set(ByVal Value As Boolean)
        Me.m_bIsInDatabase = Value
    End Set

End Property

Public Overloads Sub Dispose() Implements IDisposable.Dispose

    'Check to see if dispose has already been called
    If Not s_bDisposed Then

        'Call the dispose method 
        Me.Dispose(True)

        'Tell the garbage collector that the object doesn't require cleanup 
        GC.SuppressFinalize(Me)

    End If

End Sub

Protected Overridable Overloads Sub Dispose(ByVal disposing As Boolean)

    'Flag class as disposed 
    s_bDisposed = True

End Sub

End Class

2 个答案:

答案 0 :(得分:1)

我遇到了同样的问题。我从下面的链接中得到了这个想法。

VB.Net Copy a list to store original values to be used later

尝试以下代码

'Sets the class to a property
'this is done in order to have multiple class/collections inside the queue for processing
m_cBackgroundworkerController.Item = CType(DeepCopy(Me.Item), Item)
m_cBackgroundworkerController.ItemPricingCollection = CType(DeepCopy(Me.ItemPricingCollection), Collection(Of ItemPricing))


'Adds the collection to the queue
m_cQueueCollection.Enqueue(m_cBackgroundworkerController)

'enables the timer
Timer1.Enabled = True




Public Function DeepCopy(ByVal ObjectToCopy As Object) As Object

    Using mem as New MemoryStream

        Dim bf As New BinaryFormatter
        bf.Serialize(mem, ObjectToCopy)

        mem.Seek(0, SeekOrigin.Begin)

        Return bf.Deserialize(mem)

    End Using

End Function

答案 1 :(得分:0)

首先,您的“Item”类应实现“System.ComponentModel.INotifyPropertyChanged”接口。这基本上是对类的更改将反映在您的网格中,而不必“重置”集合/网格。

其次,只发送需要保存到队列中的内容,而不是所有记录。

第三,当保存完成后,更新(如果需要)保存的“Item”类(一次一个属性),不要替换集合中的项目或类似的东西。

这可以帮助您指出正确的道路。当您遇到新问题时,请创建一个新问题。