سؤال

وأنا أبحث عن طريقة عامة لتنفيذ شاشة الانتظار خلال عمليات طويلة. ولقد استخدمت خيوط عدة مرات من قبل، ولكن لدي شعور بأنني تنفيذه إما ضعيف جدا، أو مع الطريقة الكثير من المتاعب (ونسخ / لصق - الرعب).

وأريد للحفاظ على هذا النحو عامة وبسيطة بقدر الإمكان، ولذا فإنني لن تضطر إلى تنفيذ الكثير من BackgroundWorkers التعامل مع جميع أنواع حماقة، مما يجعل الأمور صعبة للمحافظة عليه.

وهنا ما أود القيام به - يرجى ملاحظة هذا قد تختلف عن ما هو ممكن في الواقع / أفضل الممارسات / أيا كان - باستخدام VB.NET، الإطار 2.0 (حتى لا طرق مجهول):

  Private Sub HandleBtnClick(sender as Object, e as EventArgs) Handles Button.Click
      LoadingScreen.Show()

      'Do stuff here, this takes a while!'
      Dim Result as Object = DoSomethingTakingALongTime(SomeControl.SelectedObject)

      LoadingScreen.Hide()

      ProcessResults(Result)
  End Sub

والتطبيق هو الآن ترابط واحد تماما، لذلك كل شيء يسير على موضوع واجهة المستخدم الرسومية. أنا بحاجة إلى أن تكون قادرة على الوصول إلى الكائنات في DoSomethingTakingALongTime() دون الحصول على استثناءات عبر الموضوع. الخيط GUI ينتظر بعض الطرق (والذي يستغرق وقتا طويلا) لإكمال، في حين أن نموذج LoadingScreen يجب ان تبقى استجابة (انها المتحركة / لديها progressbar / الخ.).

هل هذا / مقاربة جيدة قابلة للتنفيذ أو أرى بهذه الطريقة الساذجة جدا؟ ما هو أفضل الممارسات في هذه المسألة؟ والأهم من ذلك: كيف يمكن لي أن تنفيذ مثل هذا النظام؟ وكما سبق ذكره، ولدي خبرة قليلة جدا مع خيوط، حتى يكون لطيف يرجى: -)

هل كانت مفيدة؟

المحلول

والمشكلة هي أن لديك الحصول على استثناء موضوع عبر عند محاولة لتمرير البيانات موضوع العمال لموضوع واجهة المستخدم الخاص بك. ما عليك القيام به هو التحقق InvokeRequired وbegininvoke قبل وضع الضوابط على واجهة المستخدم الخاص بك حتى لا تحصل على خطأ مثل ذلك:

Private Sub work_CrossThreadEvent(ByVal sender As Object, ByVal e As System.EventArgs) Handles work.CrossThreadEvent

       If Me.InvokeRequired Then
           Me.BeginInvoke(New EventHandler(AddressOf work_CrossThreadEvent), New Object() {sender, e})
           Return
       End If

      Me.Text = "Cross Thread"

End Sub

ومجرد تغيير جزء New EventHandler إلى معالج الحدث باستخدام الخاص بك.

وأيضا أعتقد أن استخدام عامل الخلفية ليست طريقة سيئة لفئات العمال الخاص بك، مجرد إنشاء فئة للعمل الخاص بك واستخدام عامل خلفية للقيام بهذه الاشياء خيوط قليلا مثل هذا:

Public MustInherit Class Worker

    Protected WithEvents worker As BackgroundWorker

    Public Sub New()

        worker = New BackgroundWorker()
        worker.WorkerReportsProgress = True
        worker.WorkerSupportsCancellation = True

    End Sub

    Public Sub Start()

        If (Not worker.IsBusy AndAlso Not worker.CancellationPending) Then
            worker.RunWorkerAsync()
        End If

    End Sub

    Public Sub Cancel()
        If (worker.IsBusy AndAlso Not worker.CancellationPending) Then
            worker.CancelAsync()
        End If
    End Sub

    Protected MustOverride Sub Work()

    Private Sub OnDoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles worker.DoWork
        Work()
    End Sub

    Public Event WorkCompelted As RunWorkerCompletedEventHandler
    Private Sub OnRunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles worker.RunWorkerCompleted
        OnRunWorkerCompleted(e)
    End Sub
    Protected Overridable Sub OnRunWorkerCompleted(ByVal e As RunWorkerCompletedEventArgs)
        RaiseEvent WorkCompelted(Me, e)
    End Sub

    Public Event ProgressChanged As ProgressChangedEventHandler
    Private Sub OnProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles worker.ProgressChanged
        OnProgressChanged(e)
    End Sub
    Protected Overridable Sub OnProgressChanged(ByVal e As ProgressChangedEventArgs)
        RaiseEvent ProgressChanged(Me, e)
    End Sub

End Class

Public Class ActualWork
    Inherits Worker

    Public Event CrossThreadEvent As EventHandler

    Protected Overrides Sub Work()

        'do work here'
        WorkABit()
        worker.ReportProgress(25)

        WorkABit()
        worker.ReportProgress(50)

        WorkABit()
        worker.ReportProgress(75)

        WorkABit()
        worker.ReportProgress(100)

    End Sub

    Private Sub WorkABit()

        If worker.CancellationPending Then Return
        Thread.Sleep(1000)
        RaiseEvent CrossThreadEvent(Me, EventArgs.Empty)

    End Sub

End Class

تنويه .. صدئ قليلا مع رموز ولكن يجب عليك الحصول على هذه الفكرة.

نصائح أخرى

في الخيط الخاص بك، واستخدام Application.Run (yourform) للحصول على ما تريد.

لاحظ أن تحتاج للإشارة إلى شكل لإغلاق نفسها بطريقة أو بأخرى.

وأرجو أن لا تجد هذا غير مفيد - ولكن يهمني السؤال لماذا كنت تريد شاشة الانتظار الخيوط؟ سبب استخدام خيوط في المقام الأول هو بحيث يبقى UI استجابة، وتتم عمليات طويلة في الخلفية.

وعلى خلاف ذلك، بالاضافة الى انك قد يكون مجرد ProgressBar على السيطرة FormLoading الخاص بك، ويكون DoSomethingTakingALongTime لتحديثه بشكل دوري. وهذا لن تحتاج المواضيع على الإطلاق.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top