タスク: 要件 (ユーザーが待機せずに次々に保存できる) があるため、マルチスレッドを選択し、キューの概念でそれを完了しようとしていました。しかし、私は 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