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 task

Async task

Scheduled Pinned Locked Moved C#
csharpdatabasewpflinqcom
9 Posts 4 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.
  • K Offline
    K Offline
    Kenneth Haugland
    wrote on last edited by
    #1

    In the past, I did most of my work with parallel objects using Rx, but that was made a bit cumbersome in the recent project. So I was following the code from Brian Lagunas, I made some tweaks to it to see how it all worked.

    using Prism.Mvvm;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;

    namespace WpfAsynTaskAwait
    {
    public class MainViewModel:BindableBase
    {

        #region "ctor"
        public MainViewModel()
        {
            Text = "1: Main UI thread on: " + Thread.CurrentThread.ManagedThreadId.ToString();
            Task.Run(() => DoSomething(MethodCallback)).Await(CompletedCallback, ErrorCallback);
        }
        #endregion
    
        async Task DoSomething(Action methodCallback)
        {
            await Task.Delay(1500);
            methodCallback?.Invoke("2: Task starts on thread: " + Thread.CurrentThread.ManagedThreadId.ToString());
            await Task.Delay(1500);
            
            //throw new Exception("Aborted exception on thread " + Thread.CurrentThread.ManagedThreadId.ToString());
            
            methodCallback?.Invoke("3: Task runs on thread: " + Thread.CurrentThread.ManagedThreadId.ToString());
            await Task.Delay(1500);            
        }
    
        #region "Variables"
        private string \_text = "Default value";
    
        public string Text
        {
            get { return \_text; }
            set
            {
                SetProperty(ref \_text, value);
            }
        }
        #endregion
    
        #region "Callback methods"
    
        private void CompletedCallback()
        {
            Text = "4: Method completed called from thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
        }
    
        private void MethodCallback(string message)
        {
            Text = message + Environment.NewLine +  "Task callback from thread: " + Thread.CurrentThread.ManagedThreadId.ToString(); 
        }
    
        private void ErrorCallback(Exception ex)
        {
            Text = ex.Message;
        }
        #endregion
    }
    public static class TaskExtensions
    {
        public async static void Await(this Task task, Action completedCallback, Action errorCallback)
        {
            try
            {
                await
    
    L 1 Reply Last reply
    0
    • K Kenneth Haugland

      In the past, I did most of my work with parallel objects using Rx, but that was made a bit cumbersome in the recent project. So I was following the code from Brian Lagunas, I made some tweaks to it to see how it all worked.

      using Prism.Mvvm;
      using System;
      using System.Collections.Generic;
      using System.Linq;
      using System.Text;
      using System.Threading;
      using System.Threading.Tasks;

      namespace WpfAsynTaskAwait
      {
      public class MainViewModel:BindableBase
      {

          #region "ctor"
          public MainViewModel()
          {
              Text = "1: Main UI thread on: " + Thread.CurrentThread.ManagedThreadId.ToString();
              Task.Run(() => DoSomething(MethodCallback)).Await(CompletedCallback, ErrorCallback);
          }
          #endregion
      
          async Task DoSomething(Action methodCallback)
          {
              await Task.Delay(1500);
              methodCallback?.Invoke("2: Task starts on thread: " + Thread.CurrentThread.ManagedThreadId.ToString());
              await Task.Delay(1500);
              
              //throw new Exception("Aborted exception on thread " + Thread.CurrentThread.ManagedThreadId.ToString());
              
              methodCallback?.Invoke("3: Task runs on thread: " + Thread.CurrentThread.ManagedThreadId.ToString());
              await Task.Delay(1500);            
          }
      
          #region "Variables"
          private string \_text = "Default value";
      
          public string Text
          {
              get { return \_text; }
              set
              {
                  SetProperty(ref \_text, value);
              }
          }
          #endregion
      
          #region "Callback methods"
      
          private void CompletedCallback()
          {
              Text = "4: Method completed called from thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
          }
      
          private void MethodCallback(string message)
          {
              Text = message + Environment.NewLine +  "Task callback from thread: " + Thread.CurrentThread.ManagedThreadId.ToString(); 
          }
      
          private void ErrorCallback(Exception ex)
          {
              Text = ex.Message;
          }
          #endregion
      }
      public static class TaskExtensions
      {
          public async static void Await(this Task task, Action completedCallback, Action errorCallback)
          {
              try
              {
                  await
      
      L Offline
      L Offline
      Lost User
      wrote on last edited by
      #2

      Aren't callbacks just executed on the main thread, instead of the invoking one? > "Task callback from thread: " + Thread.CurrentThread.ManagedThreadId.ToString() Aigt, Convert.ToString(Thread.CurrentThread.ManagedThreadId) to avoid a Null-exception. What did your logs say? And if updating directly, instead of binding, does it show the same result?

      Bastard Programmer from Hell :suss: "If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.

      K 1 Reply Last reply
      0
      • L Lost User

        Aren't callbacks just executed on the main thread, instead of the invoking one? > "Task callback from thread: " + Thread.CurrentThread.ManagedThreadId.ToString() Aigt, Convert.ToString(Thread.CurrentThread.ManagedThreadId) to avoid a Null-exception. What did your logs say? And if updating directly, instead of binding, does it show the same result?

        Bastard Programmer from Hell :suss: "If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.

        K Offline
        K Offline
        Kenneth Haugland
        wrote on last edited by
        #3

        It's WPF stuff with PRISM, so I don't really have access to the textbox in the GUI directly. But it says that the application changes the property Text from the background thread. The text is thus updated on the UI via the binding and INotifiedPropertyChange interaction.

        D 1 Reply Last reply
        0
        • K Kenneth Haugland

          It's WPF stuff with PRISM, so I don't really have access to the textbox in the GUI directly. But it says that the application changes the property Text from the background thread. The text is thus updated on the UI via the binding and INotifiedPropertyChange interaction.

          D Offline
          D Offline
          Dave Kreskowiak
          wrote on last edited by
          #4

          If you modify a bound property in your view model from a non-UI thread, WPF automatically marshals the UI update changes for that property to the UI thread. It works for all scalar types, but not collections. You have to create your own collection type that does the marshalling.

          Asking questions is a skill CodeProject Forum Guidelines Google: C# How to debug code Seriously, go read these articles.
          Dave Kreskowiak

          K Richard DeemingR 2 Replies Last reply
          0
          • D Dave Kreskowiak

            If you modify a bound property in your view model from a non-UI thread, WPF automatically marshals the UI update changes for that property to the UI thread. It works for all scalar types, but not collections. You have to create your own collection type that does the marshalling.

            Asking questions is a skill CodeProject Forum Guidelines Google: C# How to debug code Seriously, go read these articles.
            Dave Kreskowiak

            K Offline
            K Offline
            Kenneth Haugland
            wrote on last edited by
            #5

            Thank you for the answer Dave. So I modified the code in the MethodCallback and got exactly what you said :thumbsup: :

            This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.

            Now I have some more research to go further. The change in the code is just banal, Binding to a TextBox and Listview's itemssource directly will throw the exception:

            public class MainViewModel:BindableBase
            {

              //  ObservableCollection MainCollection = new ObservableCollection();
            
                #region "ctor"
                public MainViewModel()
                {
            
                    Text = "1: Main UI thread on: " + Thread.CurrentThread.ManagedThreadId.ToString();
                    TextCollection.Add("1: Main UI thread on: " + Thread.CurrentThread.ManagedThreadId.ToString());
                    Task.Run(() => DoSomething(MethodCallback)).Await(CompletedCallback, ErrorCallback);
                }
                #endregion
            
                async Task DoSomething(Action methodCallback)
                {
                    await Task.Delay(1500);
                    methodCallback?.Invoke("2: Task starts on thread: " + Thread.CurrentThread.ManagedThreadId.ToString());
                    TextCollection.Add("2,5: Task starts on thread: " + Thread.CurrentThread.ManagedThreadId.ToString());
                    await Task.Delay(1500);
                    
                    //throw new Exception("Aborted exception on thread " + Thread.CurrentThread.ManagedThreadId.ToString());
                    
                    methodCallback?.Invoke("3: Task runs on thread: " + Thread.CurrentThread.ManagedThreadId.ToString());
                    await Task.Delay(1500);            
                }
            
                #region "Variables"
            
                private ObservableCollection \_textCollection = new ObservableCollection();
                public ObservableCollection TextCollection
                {
                    get { return \_textCollection; }
                    set { SetProperty(ref \_textCollection, value); }
                }
            
                private string \_text = "Default value";
            
                public string Text
                {
                    get { return \_text; }
                    set
                    {
                        SetProperty(ref \_text, value);
                    }
                }
                #endregion
            
                #region "Callback methods"
            
                private void CompletedCallback()
                {
                    Text = "4: Method completed called from thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
                    TextCollection.Add("4: Method completed called from thread: " +
            
            Richard DeemingR 1 Reply Last reply
            0
            • K Kenneth Haugland

              Thank you for the answer Dave. So I modified the code in the MethodCallback and got exactly what you said :thumbsup: :

              This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread.

              Now I have some more research to go further. The change in the code is just banal, Binding to a TextBox and Listview's itemssource directly will throw the exception:

              public class MainViewModel:BindableBase
              {

                //  ObservableCollection MainCollection = new ObservableCollection();
              
                  #region "ctor"
                  public MainViewModel()
                  {
              
                      Text = "1: Main UI thread on: " + Thread.CurrentThread.ManagedThreadId.ToString();
                      TextCollection.Add("1: Main UI thread on: " + Thread.CurrentThread.ManagedThreadId.ToString());
                      Task.Run(() => DoSomething(MethodCallback)).Await(CompletedCallback, ErrorCallback);
                  }
                  #endregion
              
                  async Task DoSomething(Action methodCallback)
                  {
                      await Task.Delay(1500);
                      methodCallback?.Invoke("2: Task starts on thread: " + Thread.CurrentThread.ManagedThreadId.ToString());
                      TextCollection.Add("2,5: Task starts on thread: " + Thread.CurrentThread.ManagedThreadId.ToString());
                      await Task.Delay(1500);
                      
                      //throw new Exception("Aborted exception on thread " + Thread.CurrentThread.ManagedThreadId.ToString());
                      
                      methodCallback?.Invoke("3: Task runs on thread: " + Thread.CurrentThread.ManagedThreadId.ToString());
                      await Task.Delay(1500);            
                  }
              
                  #region "Variables"
              
                  private ObservableCollection \_textCollection = new ObservableCollection();
                  public ObservableCollection TextCollection
                  {
                      get { return \_textCollection; }
                      set { SetProperty(ref \_textCollection, value); }
                  }
              
                  private string \_text = "Default value";
              
                  public string Text
                  {
                      get { return \_text; }
                      set
                      {
                          SetProperty(ref \_text, value);
                      }
                  }
                  #endregion
              
                  #region "Callback methods"
              
                  private void CompletedCallback()
                  {
                      Text = "4: Method completed called from thread: " + Thread.CurrentThread.ManagedThreadId.ToString();
                      TextCollection.Add("4: Method completed called from thread: " +
              
              Richard DeemingR Offline
              Richard DeemingR Offline
              Richard Deeming
              wrote on last edited by
              #6

              From .NET 4.5 onwards, you can enable collection updates from a background thread fairly simply: WPF 4.5: Observable Collection Cross-Thread Change Notification - Pete Brown's 10rem.net[^] BindingOperations.EnableCollectionSynchronization Method (System.Windows.Data) | Microsoft Docs[^]


              "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

              K 1 Reply Last reply
              0
              • D Dave Kreskowiak

                If you modify a bound property in your view model from a non-UI thread, WPF automatically marshals the UI update changes for that property to the UI thread. It works for all scalar types, but not collections. You have to create your own collection type that does the marshalling.

                Asking questions is a skill CodeProject Forum Guidelines Google: C# How to debug code Seriously, go read these articles.
                Dave Kreskowiak

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

                Dave Kreskowiak wrote:

                You have to create your own collection type that does the marshalling.

                Or, if you're using .NET 4.5 or later, use the built-in method. :) BindingOperations.EnableCollectionSynchronization Method (System.Windows.Data) | Microsoft Docs[^]


                "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

                D 1 Reply Last reply
                0
                • Richard DeemingR Richard Deeming

                  Dave Kreskowiak wrote:

                  You have to create your own collection type that does the marshalling.

                  Or, if you're using .NET 4.5 or later, use the built-in method. :) BindingOperations.EnableCollectionSynchronization Method (System.Windows.Data) | Microsoft Docs[^]


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

                  D Offline
                  D Offline
                  Dave Kreskowiak
                  wrote on last edited by
                  #8

                  Huh, I didn't know know about that. That makes life a little easier. :)

                  Asking questions is a skill CodeProject Forum Guidelines Google: C# How to debug code Seriously, go read these articles.
                  Dave Kreskowiak

                  1 Reply Last reply
                  0
                  • Richard DeemingR Richard Deeming

                    From .NET 4.5 onwards, you can enable collection updates from a background thread fairly simply: WPF 4.5: Observable Collection Cross-Thread Change Notification - Pete Brown's 10rem.net[^] BindingOperations.EnableCollectionSynchronization Method (System.Windows.Data) | Microsoft Docs[^]


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

                    K Offline
                    K Offline
                    Kenneth Haugland
                    wrote on last edited by
                    #9

                    I like this. Not a lot of backbreaking coding work :-\ Literally just added two lines of code and all works well.

                        private object \_TextCollectionLock = new object();
                    
                        public MainViewModel()
                        {
                            BindingOperations.EnableCollectionSynchronization(TextCollection, \_TextCollectionLock);
                            ...
                        }
                    
                    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