1

タスク: 要件 (ユーザーが待機せずに次々に保存できる) があるため、マルチスレッドを選択し、キューの概念でそれを完了しようとしていました。しかし、私は 1 つのシナリオで立ち往生しています。

コードに関するタスク: アプリケーションには、単一の Queue クラスを作成し、その中に別のコレクションとオブジェクトを作成した多くのコレクションとオブジェクトがあり、それらはすべてキュー クラス オブジェクトに割り当てられました。ユーザーが変更を保存すると、すべてのコレクションとオブジェクトが満たされ、キューのコレクションとオブジェクトに割り当てられ、キューに追加されます。そのため、バックグラウンド ワーカーがコレクションとオブジェクトを取得してプロセスを実行します。これは、継続的な保存があるため、保存された値が正しいことを確認するために行われます。

シナリオ: アプリケーションには、ユーザーが行を選択し、そこから一意の ID を使用して値がコレクションに読み込まれ、フォームにバインドされるグリッドがあります。したがって、ユーザーは値を更新し、[保存] をクリックします。次に、次の行をクリックし、値がロードされたら、再度変更を加えて保存します。ここで問題が発生します。

以前のすべてのコレクションをキュー コレクションに割り当てたので、ユーザーが変更を加えて [保存] をクリックし、次の行に移動してそれをクリックすると、アプリケーションに既に存在するコレクションがリセットされます (コレクションが行を選択するたびにリセットして、選択した値をロードする)、新しい値がロードされます。これにより、キューにもあるコレクションを反映した変更が行われます。そのため、保存機能はその間に影響を受けています。

今私が必要としているのは、現在のコレクションがすでにリセットされている場合でも、キューにあるコレクションが影響を受けないようにすることです。

どうすれば達成できますか?

//コード:

メインフォーム:

パブリック クラス 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

// クラスの 1 つ:

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

2 に答える 2

1

私は同じ問題に直面しています。以下のリンクからアイデアを得ました。

VB.Netリストをコピーして、後で使用する元の値を保存します

以下のコードを試してください

'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
于 2013-09-30T11:54:02.053 に答える
0

まず、"Item" クラスは "System.ComponentModel.INotifyPropertyChanged" インターフェイスを実装する必要があります。これは基本的に、コレクション/グリッドを「リセット」することなく、クラスに加えられた変更がグリッドに反映されるようにするためです。

次に、すべてのレコードではなく、キューに保存する必要があるものだけを送信します。

第 3 に、保存が完了したら、(必要に応じて) 保存された "Item" クラスを更新し (一度に 1 つのプロパティ)、コレクション内の項目を置き換えたり、そのようなことをしたりしないでください。

これは、正しい道を示すのに役立ちます。新しい問題が発生した場合は、新しい質問を作成してください。

于 2013-09-27T20:49:54.343 に答える