await - async

  • C#
  • .NET 5–6

Es gibt 6 Antworten in diesem Thema. Der letzte Beitrag () ist von loeffel.

    await - async

    Moin allerseits,

    ich hätte da eine Frage zur Anwendung von async und await, deren Beantwortung ich im Netz nicht gefunden habe. Ich verwende WPF, das hat aber hier keine Bedeutung, denke ich. In Winforms wäre es ähnlich, vom Prinzip her gleich.

    Im Hauptfenster wird über das Menu ein Formular erzeugt, das eine größere Anzahl von Daten anzeigen soll, daher bietet sich eine asynchrone Lademethode an.

    Das Formular verwendet dazu das Loaded-Event

    C#-Quellcode

    1. public partial class OrdersTreeViewControl : UserControl
    2. {
    3. public OrdersTreeViewViewmodel Viewmodel { get; set; }
    4. public OrdersTreeViewControl()
    5. {
    6. InitializeComponent();
    7. DataContext = Viewmodel = new(this);
    8. }
    9. private void UserControl_Loaded(object sender, RoutedEventArgs e)
    10. {
    11. Viewmodel.Load();
    12. }
    13. }


    und im Viewmodel

    C#-Quellcode

    1. public async void Load()
    2. {
    3. Mouse.OverrideCursor = Cursors.Wait;
    4. ProgressBarVisibility = Visibility.Visible;
    5. await Task.Run(() => FillIdentNr());
    6. LoadingVisibility = Visibility.Hidden;
    7. TreeViewVisibility = Visibility.Visible;
    8. ProgressBarVisibility = Visibility.Hidden;
    9. Mouse.OverrideCursor = null;
    10. }


    Wie man sieht, liegt die asynchrone Methode im Viewmodel.

    Die Frage ist nun, ob es egal ist oder evtl. mehr Sinn macht, es anders zu lösen, nämlich so:

    C#-Quellcode

    1. private async void UserControl_Loaded(object sender, RoutedEventArgs e)
    2. {
    3. await Task.Run(()=>Viewmodel.Load());
    4. }


    mit

    C#-Quellcode

    1. public void Load()
    2. {
    3. Mouse.OverrideCursor = Cursors.Wait;
    4. ProgressBarVisibility = Visibility.Visible;
    5. FillIdentNr();
    6. LoadingVisibility = Visibility.Hidden;
    7. TreeViewVisibility = Visibility.Visible;
    8. ProgressBarVisibility = Visibility.Hidden;
    9. Mouse.OverrideCursor = null;
    10. }



    Gibt es Argumente für den einen oder anderen Ansatz? Und wenn ja, warum.


    Gruß

    MQ

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „MasterQ“ ()

    Hast Du es ausprobiert? Falls nebenläufig GUI-Daten geändert werden, dürfte es mit ner Exception scheitern.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    Jou.

    MasterQ schrieb:

    daher bietet sich eine asynchrone Lademethode an.
    Das knallt mit ungültigem threadüberbreifenden Vorgang.
    Peobier mal während der Daten-Bestückung das Control still zu legen,
    bei WinForm: .SuspendLayout() und .ResumeLayout(False);
    bei WPF weiß ich nicht.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Da knallt und knirscht nix.

    Ich greife ja nicht direkt auf die GUI-Elemente zu, sondern nur auf Properties des Viewmodels. Diese sind per DataBinding mit den Steuerelementen verknüpft.

    C#-Quellcode

    1. Visibility _visibilityProgressBar = Visibility.Hidden;
    2. public Visibility ProgressBarVisibility
    3. {
    4. get { return _visibilityProgressBar; }
    5. set
    6. {
    7. if (_visibilityProgressBar != value)
    8. {
    9. _visibilityProgressBar = value;
    10. NotifyPropertyChanged();
    11. }
    12. }
    13. }


    und

    XML-Quellcode

    1. <ProgressBar Name="progressBar"
    2. Visibility="{Binding ProgressBarVisibility}"
    3. Width="200"
    4. Height="20"
    5. Value="{Binding Progress}"
    6. Minimum="0"
    7. Maximum="1"
    8. ToolTip="{Binding Progress}"
    9. />
    Dann ist es so ziemlich egal, ob Du Variante A oder B nimmst.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.

    MasterQ schrieb:

    Ich greife ja nicht direkt auf die GUI-Elemente zu, sondern nur auf Properties des Viewmodels.

    hmm, hmm. Aber hier grabschst du aussm View ins Viewmodel - auch nicht wirklich, was man unter Databinding versteht...

    MasterQ schrieb:

    C#-Quellcode

    C#-Quellcode

    1. public partial class OrdersTreeViewControl : UserControl
    2. {
    3. public OrdersTreeViewViewmodel Viewmodel { get; set; }
    4. public OrdersTreeViewControl()
    5. {
    6. InitializeComponent();
    7. DataContext = Viewmodel = new(this);
    8. }
    9. private void UserControl_Loaded(object sender, RoutedEventArgs e)
    10. {
    11. Viewmodel.Load();
    12. }
    13. }
    Wenn ich mich richtig erinnere, marshallt WPF Bindings-Zuweisungen zur Laufzeit an UI Elemente, die auf einem anderen als dem UI-Thread ausgefuehrt werden, immer eigenstaendig auf den UI Thread. WinForms macht das (noch) nicht, wir haben aber gerade einen Vorschlag von der Community, das fuer .NET 8 umzusetzen.

    In WinForms knallt das noch; man muesste es also vor dem Schreiben des Setter der Property, die gebunden ist, selber zurueck auf den UI-Thread delegieren.

    Zu deiner urspruenglichen Frage:
    Bitte achtet darauf bzw. seid euch bewusst, dass das async Keyword NICHTS an der Kompilierung aendert. Es erlaubt lediglich, dass das await Keyword als solches erkannt werden darf.

    "Async Void" Signaturen verwendet bitte nur dann, wenn die Methoden, in denen ihr es verwendet "Ereignis Character" haben. Also: Event Handler, oder wenn ihr OnXXX Methoden ueberschreibt, die events ausloesen. Ansonsten SOLLTEN asynchrone Methoden DRINGEND einen Task zurueckliefern, damit sie awaited werden koennen. Damit man weiss, dass asynchrone Methoden solche sind (Task returning) ist es gute Praxis, sie mit "Async" als Postfix zu bennen.

    Also (aus dem Kopf):

    C#-Quellcode

    1. public Task LoadAsync()
    2. {
    3. Mouse.OverrideCursor = Cursors.Wait;
    4. ProgressBarVisibility = Visibility.Visible;
    5. await Task.Run(() => FillIdentNr());
    6. LoadingVisibility = Visibility.Hidden;
    7. TreeViewVisibility = Visibility.Visible;
    8. ProgressBarVisibility = Visibility.Hidden;
    9. Mouse.OverrideCursor = null;}


    Wichtig ist auch zu wissen, dass es beispielsweise bei Dateioperationen bereits asynchrone Methoden gibt, die sich nicht eines Thread-Pool-Threads im Hintergrund bedienen (oder diesen zumindest vermeiden, wann immer es geht). Man unterscheidet naemlich bei asynchronen Operationen zwischen CPU-Bound und I/O Bound (es gibt einen Haufen von Schaltungen in einem Rechner ausser dem Prozessor, die Dinge beilaeufig ausfueheren konnen - NorthBridge, SouthBridge, MMUs und was weiss ich, bin kein Hardware-Mensch :) ). Also ist es immer sinnvoll zu schauen, ob es fuer Dinge, die man aus der .NET API aufrufen will, nicht schon die entsprechenden ...Async Methode gibt!

    Hope that helps!

    Klaus