-1

I am creating a WPF MVVM Application where I have a Main Window and different Pages displayed in a Frame. I want to add a Loading Screen with a Progress Bar which updates while the Instances for the Pages get created:

Dim customer_page as new Pg_Custommer

Because there are Databases in some Pages, which get read while creating a new Instance, this takes some Time. I have tried to solve this with a Background Worker, but this did not work because the Thread has no Access to GUI (no STA-Thread). I need a Way to update the Progress Bar after each Class gets loaded.

Maybe someone could tell me how to solve this with a Dispatcher(No idea how these work) or similar.

Thanks in advance and Greetings from Switzerland

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
  • You've shown us none of your code so nobody could give you specific advice. You've tried some stuff. It didn't work. For reasons we can only really guess at. – Andy Feb 26 '23 at 11:00
  • 1
    If you want to update the UI from a background thread like BackgroundWorker (not recommended) or Task.Run (recommended) you must either access the UI element via the static Application.Current.Dispatcher.InvokeAsync() (not recommended) or use Progress (recommended). When using data binding and you update the source property that is bound to the ProgressBar you shouldn't encounter any issues in the first place. – BionicCode Feb 26 '23 at 12:33
  • 1
    [Async in 4.5: Enabling Progress and Cancellation in Async APIs](https://devblogs.microsoft.com/dotnet/async-in-4-5-enabling-progress-and-cancellation-in-async-apis/) – BionicCode Feb 26 '23 at 12:40
  • Does this answer your question? [Async Progress Bar Update](https://stackoverflow.com/questions/36340639/async-progress-bar-update) – Craig Feb 27 '23 at 14:16

1 Answers1

0

The SplashScreen ist a WPF Form with just Code behind, no VMMW, for testing. So i can adress the Progress Bar Value directly.

This is my Example Code:

Public Class SplashScreen

    Public Sub New()
        InitializeComponent()
    End Sub

    Private Async Function LoadClassesTask() As Task

        Dim progress = New Progress(Of Integer)(Sub(percent)
                                                    ProgressBar.Value = percent
                                                End Sub)

        Await Task.Factory.StartNew(FDoWork(progress), CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext())

    End Function

    Public Shared Function FDoWork(progress As IProgress(Of Integer)) As Action

        Dim i As Integer = 0


        'Create New Instances of Page-Classes

        customerpage = New Pg_Customer
        i += intLoadingProgress ' -> Global Integer = 9
        If progress IsNot Nothing Then progress.Report(i)

        pdfpage = New Pg_PDF_View
        i += intLoadingProgress
        If progress IsNot Nothing Then progress.Report(i)

        editorpage = New Pg_Editor
        i += intLoadingProgress
        If progress IsNot Nothing Then progress.Report(i)

        accpage = New Pg_Accounting
        i += intLoadingProgress
        If progress IsNot Nothing Then progress.Report(i)

        accselectpage = New Pg_AccountingSelect
        i += intLoadingProgress
        If progress IsNot Nothing Then progress.Report(i)

        tyreprotokollpage = New Pg_Tyreprotokoll
        i += intLoadingProgress
        If progress IsNot Nothing Then progress.Report(i)

        dbselectpage = New Pg_DatabaseSelect
        i += intLoadingProgress
        If progress IsNot Nothing Then progress.Report(i)

        dbRG = New Pg_Database_RG
        i += intLoadingProgress
        If progress IsNot Nothing Then progress.Report(i)

        dbAP = New Pg_Database_AP
        i += intLoadingProgress
        If progress IsNot Nothing Then progress.Report(i)

        dbMP = New Pg_Database_MP
        i += intLoadingProgress
        If progress IsNot Nothing Then progress.Report(i)

        dbSP = New Pg_Database_SP
        i += intLoadingProgress
        If progress IsNot Nothing Then progress.Report(i)

        pganalyzer = New Pg_DocAnalyzer
        i += intLoadingProgress
        If progress IsNot Nothing Then progress.Report(i)

        dashboardpage = New Pg_Dashboard
        i += intLoadingProgress
        If progress IsNot Nothing Then progress.Report(i)

        delivernotespage = New Pg_DeliveryNotes
        i += intLoadingProgress
        If progress IsNot Nothing Then progress.Report(i)

        dbCar = New Pg_Database_Car
        i += intLoadingProgress
        If progress IsNot Nothing Then progress.Report(i)

        Return Nothing
    End Function

    Private Sub Btn_Start_Click(sender As Object, e As RoutedEventArgs) Handles Btn_Start.Click

        LoadClassesTask()

    End Sub

End Class

It Runs now like this, but still the Page freezes and Progress Bar gets updated after all Classes are instantiated.

I guess im making a very stupid mistake somewhere but i just cant find it.

  • You must await LoadClassesTask in your event handler. Otherwise the invocation is synchronous and therefore blocking the UI thread (ProgressBar can't update until LoadClassesTask has returned). Always await the complete call tree. Also use Task.Run instead of Task.Factory.StartNew. – BionicCode Feb 26 '23 at 18:09