Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C#
  4. Async Dispatcher Calls - Need an explaination

Async Dispatcher Calls - Need an explaination

Scheduled Pinned Locked Moved C#
mobiledatabaselinqdesignfunctional
4 Posts 2 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • F Offline
    F Offline
    Foothill
    wrote on last edited by
    #1

    So I decided to update an older application with calls using await...async instead of embeding Thread.Start(() => { myFunction(); }); lambda expressions for long running operations. I have had a few successes but I am a little confused about making asynchronous method call with the dispatcher. Lets start with the original multithreaded database call. It updates a ListView when it is done.

    public bool PushToDatabase(DataCollection data)
    {
    try
    {
    // insert data in database
    PerformDatabaseInsert(data);
    // then update the visual
    App.Current.Dispatcher.Invoke(new Action(() => lst_MyData.ItemsSource = data.ToArray()));
    return true;
    }
    catch (Exception ex)
    {
    // Display error to user
    return false;
    }
    }

    This is all wrapped up in a click event in a pop-out control

    private void btn_Submit_Click(object sender, RoutedEventArgs e)
    {
    if (InputsAreGood())
    {
    DataCollection data = GetFormFields();

    Thread thread = new Thread(() =>
    {
    MainWindow.SetCursor_Wait(); // visual candy via the Dispatcher

    if (PushToDatabase(data))
    {
    ClosePopOutControl();
    }

    MainWindow.SetCursor_Arrow();
    });

    thread.Start();
    }
    else
    {
    // inform user what they missed
    }
    }

    Nothing really fancy. The UI remains responsive while the database operation is performed on another thread. Now, I converted these to asynchronous methods. The code works but I am still not understanding why it is supposed to be better when it seems to make the code look a lot more complicated. I can only surmise that I am going about this all wrong. First, I moved the ListView update to a separate function.

    public async Task UpdateListViewAsync(DataCollection data)
    {
    // Dispatcher is awaitable, so no problems here
    await Dispatcher.Invoke(() =>
    {
    // but you cannot await a void so I have to rewrite it to this
    return Task.Run(() => { lst_MyData.ItemsSource = data.ToArray(); });
    }
    }

    And added an async function to perform the database call.

    public async Task PushToDatabaseAsync(DataCollection data)
    {
    Task dataPushTask = Task.Run(() => PushToDatabase(data));
    bool result = await dataPushTask;
    await UpdateListViewAsync();
    return result;
    }

    There are fewer lines of code in the function but am I really gaining anything here? What I had to rewrite the submit code to really bakes my noodle.

    private btn_Submit

    Richard DeemingR 1 Reply Last reply
    0
    • F Foothill

      So I decided to update an older application with calls using await...async instead of embeding Thread.Start(() => { myFunction(); }); lambda expressions for long running operations. I have had a few successes but I am a little confused about making asynchronous method call with the dispatcher. Lets start with the original multithreaded database call. It updates a ListView when it is done.

      public bool PushToDatabase(DataCollection data)
      {
      try
      {
      // insert data in database
      PerformDatabaseInsert(data);
      // then update the visual
      App.Current.Dispatcher.Invoke(new Action(() => lst_MyData.ItemsSource = data.ToArray()));
      return true;
      }
      catch (Exception ex)
      {
      // Display error to user
      return false;
      }
      }

      This is all wrapped up in a click event in a pop-out control

      private void btn_Submit_Click(object sender, RoutedEventArgs e)
      {
      if (InputsAreGood())
      {
      DataCollection data = GetFormFields();

      Thread thread = new Thread(() =>
      {
      MainWindow.SetCursor_Wait(); // visual candy via the Dispatcher

      if (PushToDatabase(data))
      {
      ClosePopOutControl();
      }

      MainWindow.SetCursor_Arrow();
      });

      thread.Start();
      }
      else
      {
      // inform user what they missed
      }
      }

      Nothing really fancy. The UI remains responsive while the database operation is performed on another thread. Now, I converted these to asynchronous methods. The code works but I am still not understanding why it is supposed to be better when it seems to make the code look a lot more complicated. I can only surmise that I am going about this all wrong. First, I moved the ListView update to a separate function.

      public async Task UpdateListViewAsync(DataCollection data)
      {
      // Dispatcher is awaitable, so no problems here
      await Dispatcher.Invoke(() =>
      {
      // but you cannot await a void so I have to rewrite it to this
      return Task.Run(() => { lst_MyData.ItemsSource = data.ToArray(); });
      }
      }

      And added an async function to perform the database call.

      public async Task PushToDatabaseAsync(DataCollection data)
      {
      Task dataPushTask = Task.Run(() => PushToDatabase(data));
      bool result = await dataPushTask;
      await UpdateListViewAsync();
      return result;
      }

      There are fewer lines of code in the function but am I really gaining anything here? What I had to rewrite the submit code to really bakes my noodle.

      private btn_Submit

      Richard DeemingR Offline
      Richard DeemingR Offline
      Richard Deeming
      wrote on last edited by
      #2

      Foothill wrote:

      it seems to make the code look a lot more complicated

      That's because you've significantly over-complicated it! :)

      private btn_Submit_Click(object sender, RoutedEventArgs e)
      {
      try
      {
      MainWindow.SetCursor_Wait();
      if (InputsAreGood())
      {
      DataCollection data = GetFormFields():
      await PushDataToDatabaseAsync(data);
      ClosePopOutForm();
      }
      else
      {
      // tell user what fields they missed
      }
      }
      catch (Exception ex)
      {
      // display the error to the user
      }
      finally
      {
      MainWindow.SetCusor_Arrow();
      }
      }

      private async Task PushToDatabaseAsync(DataCollection data)
      {
      // Let any exceptions bubble up the call-stack to be displayed by the calling method.
      // TODO: Make this a real async call to the database if possible.
      await Task.Run(() => PerformDatabaseInsert(data));

      // Using "await" means we're back on the UI thread here,
      // so there should be no need to use the Dispatcher.
      if (Dispatcher.CheckAccess())
      {
          UpdateList(data)
      }
      else
      {
          await Dispatcher.BeginInvoke((Action<DataCollection>)UpdateList, data);
      }
      

      }

      private void UpdateList(DataCollection data)
      {
      lst_MyData.ItemsSource = data.ToArray();
      }

      NB: If at all possible, you should make your PerformDatabaseInsert method async, using the built-in async methods on the DbConnection / DbCommand types. If you're using a DataAdapter, there's no async support, so you're stuck with pushing the update onto a background thread.


      "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

      "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

      F 1 Reply Last reply
      0
      • Richard DeemingR Richard Deeming

        Foothill wrote:

        it seems to make the code look a lot more complicated

        That's because you've significantly over-complicated it! :)

        private btn_Submit_Click(object sender, RoutedEventArgs e)
        {
        try
        {
        MainWindow.SetCursor_Wait();
        if (InputsAreGood())
        {
        DataCollection data = GetFormFields():
        await PushDataToDatabaseAsync(data);
        ClosePopOutForm();
        }
        else
        {
        // tell user what fields they missed
        }
        }
        catch (Exception ex)
        {
        // display the error to the user
        }
        finally
        {
        MainWindow.SetCusor_Arrow();
        }
        }

        private async Task PushToDatabaseAsync(DataCollection data)
        {
        // Let any exceptions bubble up the call-stack to be displayed by the calling method.
        // TODO: Make this a real async call to the database if possible.
        await Task.Run(() => PerformDatabaseInsert(data));

        // Using "await" means we're back on the UI thread here,
        // so there should be no need to use the Dispatcher.
        if (Dispatcher.CheckAccess())
        {
            UpdateList(data)
        }
        else
        {
            await Dispatcher.BeginInvoke((Action<DataCollection>)UpdateList, data);
        }
        

        }

        private void UpdateList(DataCollection data)
        {
        lst_MyData.ItemsSource = data.ToArray();
        }

        NB: If at all possible, you should make your PerformDatabaseInsert method async, using the built-in async methods on the DbConnection / DbCommand types. If you're using a DataAdapter, there's no async support, so you're stuck with pushing the update onto a background thread.


        "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

        F Offline
        F Offline
        Foothill
        wrote on last edited by
        #3

        :omg: I can see that. I guess I will chalk that up to this being my first serious attempt and multithreading with the async...await model. Currently reading Best Practices in Asynchronous Programming to get a better idea of what I am doing wrong here and what is the right way. Any other tips to get me started would be appreciated. Does over-complicating something simple make me an engineer? :)

        if (Object.DividedByZero == true) { Universe.Implode(); } Meus ratio ex fortis machina. Simplicitatis de formae ac munus. -Foothill, 2016

        Richard DeemingR 1 Reply Last reply
        0
        • F Foothill

          :omg: I can see that. I guess I will chalk that up to this being my first serious attempt and multithreading with the async...await model. Currently reading Best Practices in Asynchronous Programming to get a better idea of what I am doing wrong here and what is the right way. Any other tips to get me started would be appreciated. Does over-complicating something simple make me an engineer? :)

          if (Object.DividedByZero == true) { Universe.Implode(); } Meus ratio ex fortis machina. Simplicitatis de formae ac munus. -Foothill, 2016

          Richard DeemingR Offline
          Richard DeemingR Offline
          Richard Deeming
          wrote on last edited by
          #4

          Stephen Toub's blog is an excellent resource, although it hasn't been updated in a while, and tends to cover quite advanced topics: Parallel Programming with .NET | All about Async/Await, System.Threading.Tasks, System.Collections.Concurrent, System.Linq, and more…[^] Async/Await FAQ | Parallel Programming with .NET[^]


          "These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer

          "These people looked deep within my soul and assigned me a number based on the order in which I joined" - Homer

          1 Reply Last reply
          0
          Reply
          • Reply as topic
          Log in to reply
          • Oldest to Newest
          • Newest to Oldest
          • Most Votes


          • Login

          • Don't have an account? Register

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • World
          • Users
          • Groups