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. WPF
  4. MVVM Tasks and UI Updating

MVVM Tasks and UI Updating

Scheduled Pinned Locked Moved WPF
wpfcsharpwcfcomdesign
7 Posts 3 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.
  • C Offline
    C Offline
    cjb110
    wrote on last edited by
    #1

    I'm struggling to get my MVVM WPF app to work with a set of Tasks updating the UI. I've got a Command that starts X number of tasks off, for each task I'd like the UI to update when started and when finished. I've also got a second Command to cancel the task, which I'd obviously like working (the code does but as the UI locks the button doesn't) I've used a ListBox bound to an ObvservableCollection<string> for the results, as this seemed better than binding to a string. At the moment I get the UI lockup until all tasks are finished. This is with or without a Task.WaitAll. The results are correct, the tasks don't always start/finish in the same order so they're obviously being generated and updating the collection asynchronously. I've tried an AysncObservableCollection (as per this SO answer) I've tried using the Dispatcher in my method that adds a item to the collection. I've tried variations on the Binding parameters. Can someone give me some hints :confused: Surely people have created a status log with async stuff in MVVM before?? Do I need to move the task creation to the Model? I've seen mention of making sure the Collection is initiated on/by the View, not sure I understand that! The View has a DataContext that's set to my ViewModel. Do they mean I've got to create the Collection in the code behind of the View? that doesn't seem right. Oh this is .NET4.0 on XP, and I'm not using any MVVM frameworks (didn't think that was a good idea as I'm still learning)

    M A 2 Replies Last reply
    0
    • C cjb110

      I'm struggling to get my MVVM WPF app to work with a set of Tasks updating the UI. I've got a Command that starts X number of tasks off, for each task I'd like the UI to update when started and when finished. I've also got a second Command to cancel the task, which I'd obviously like working (the code does but as the UI locks the button doesn't) I've used a ListBox bound to an ObvservableCollection<string> for the results, as this seemed better than binding to a string. At the moment I get the UI lockup until all tasks are finished. This is with or without a Task.WaitAll. The results are correct, the tasks don't always start/finish in the same order so they're obviously being generated and updating the collection asynchronously. I've tried an AysncObservableCollection (as per this SO answer) I've tried using the Dispatcher in my method that adds a item to the collection. I've tried variations on the Binding parameters. Can someone give me some hints :confused: Surely people have created a status log with async stuff in MVVM before?? Do I need to move the task creation to the Model? I've seen mention of making sure the Collection is initiated on/by the View, not sure I understand that! The View has a DataContext that's set to my ViewModel. Do they mean I've got to create the Collection in the code behind of the View? that doesn't seem right. Oh this is .NET4.0 on XP, and I'm not using any MVVM frameworks (didn't think that was a good idea as I'm still learning)

      M Offline
      M Offline
      Matt T Heffron
      wrote on last edited by
      #2

      How are you binding the ListBox and ObservableCollection<string>? Are you creating the ObservableCollection in the ViewModel? Is it bound to the ItemsSource on the ListBox? If you can show some of the code/xaml we can provide more assistance.

      C 1 Reply Last reply
      0
      • M Matt T Heffron

        How are you binding the ListBox and ObservableCollection<string>? Are you creating the ObservableCollection in the ViewModel? Is it bound to the ItemsSource on the ListBox? If you can show some of the code/xaml we can provide more assistance.

        C Offline
        C Offline
        cjb110
        wrote on last edited by
        #3

        Ok, In my view XAML I think the only relevant bits are:

        I've tried some of the Binding options like Async. There's nothing in the .xaml.cs file apart from the initialize call. Oh and its in a UserControl because my app has two modes so I'm using a tab control displaying two UserControls. For my ViewModel, I've got an abstract base ViewModel then a design time and run time classes. All the child classes do is set some properties, there's no other methods or additional properties. In the base ViewModel class the collection is defined:

            private ObservableCollection \_results = new ObservableCollection();
            public ObservableCollection Results
            {
                get { return \_results; }
                set
                {
                    \_results = value;
        
                    RaisePropertyChanged("Results");
                }
            }
        

        I've tried the creation of the collection in the constructor of the BaseViewModel and in the constructors of the child classes. And in case its my Task stuff that's wrong:

            private void DoRunTestCommand()
            {
                \_cancellationTokenSource = new CancellationTokenSource();
        
                Log(String.Format("Submitting {0} requests, every {1}ms, {2} at time."
                    , Model.NumberOfRequests
                    , Model.MSBetweenRequests
                    , Model.NumberOfConcurrentRequests));
                
                CancellationToken cancellationToken = \_cancellationTokenSource.Token;
        
                Task\[\] tasks = new Task\[Model.NumberOfRequests\];
        
                for (int i = 0; i < Model.NumberOfRequests; i++)
                {
                    int idx = i;
        
                    Task r = Task.Factory.StartNew((state) =>
                        {
                            SubmitRequest((int) state);
        
                            cancellationToken.ThrowIfCancellationRequested();
                        }
                        , i
                        , cancellationToken
                        , TaskCreationO
        
        C 1 Reply Last reply
        0
        • C cjb110

          Ok, In my view XAML I think the only relevant bits are:

          I've tried some of the Binding options like Async. There's nothing in the .xaml.cs file apart from the initialize call. Oh and its in a UserControl because my app has two modes so I'm using a tab control displaying two UserControls. For my ViewModel, I've got an abstract base ViewModel then a design time and run time classes. All the child classes do is set some properties, there's no other methods or additional properties. In the base ViewModel class the collection is defined:

              private ObservableCollection \_results = new ObservableCollection();
              public ObservableCollection Results
              {
                  get { return \_results; }
                  set
                  {
                      \_results = value;
          
                      RaisePropertyChanged("Results");
                  }
              }
          

          I've tried the creation of the collection in the constructor of the BaseViewModel and in the constructors of the child classes. And in case its my Task stuff that's wrong:

              private void DoRunTestCommand()
              {
                  \_cancellationTokenSource = new CancellationTokenSource();
          
                  Log(String.Format("Submitting {0} requests, every {1}ms, {2} at time."
                      , Model.NumberOfRequests
                      , Model.MSBetweenRequests
                      , Model.NumberOfConcurrentRequests));
                  
                  CancellationToken cancellationToken = \_cancellationTokenSource.Token;
          
                  Task\[\] tasks = new Task\[Model.NumberOfRequests\];
          
                  for (int i = 0; i < Model.NumberOfRequests; i++)
                  {
                      int idx = i;
          
                      Task r = Task.Factory.StartNew((state) =>
                          {
                              SubmitRequest((int) state);
          
                              cancellationToken.ThrowIfCancellationRequested();
                          }
                          , i
                          , cancellationToken
                          , TaskCreationO
          
          C Offline
          C Offline
          cjb110
          wrote on last edited by
          #4

          Solved it I think. I mentioned that I was trying the AsyncObservableCollection, apparently if I use that then I don't want to pass TaskScheduler.FromCurrentSynchronizationContext() to the task. I don't understand why (I guess a conflict somewhere)...but not sure if I need to understand either :) So my ObservableCollection is now defined as:

              private ObservableCollection \_results = new AsyncObservableCollection();
              public ObservableCollection Results
              {
                  get { return \_results; }
                  set
                  {
                      \_results = value;
          
                      RaisePropertyChanged("Results");
                  }
              }
          

          And my tasks updated the ListBox as and when they start/finish. So I've just got to check if cancellation works, and see if I can still use WaitAll. Ideally I'd like a message when the tasks have all been started and finished (more a WhenAll (if that even exists)), at the moment I get that in the middle. But if I use WaitAll then I don't get the async updating. Note for any others if your using .NET 4.5 then I don't think any of this is an issue as they changed the ObversableCollection.

          C 1 Reply Last reply
          0
          • C cjb110

            Solved it I think. I mentioned that I was trying the AsyncObservableCollection, apparently if I use that then I don't want to pass TaskScheduler.FromCurrentSynchronizationContext() to the task. I don't understand why (I guess a conflict somewhere)...but not sure if I need to understand either :) So my ObservableCollection is now defined as:

                private ObservableCollection \_results = new AsyncObservableCollection();
                public ObservableCollection Results
                {
                    get { return \_results; }
                    set
                    {
                        \_results = value;
            
                        RaisePropertyChanged("Results");
                    }
                }
            

            And my tasks updated the ListBox as and when they start/finish. So I've just got to check if cancellation works, and see if I can still use WaitAll. Ideally I'd like a message when the tasks have all been started and finished (more a WhenAll (if that even exists)), at the moment I get that in the middle. But if I use WaitAll then I don't get the async updating. Note for any others if your using .NET 4.5 then I don't think any of this is an issue as they changed the ObversableCollection.

            C Offline
            C Offline
            cjb110
            wrote on last edited by
            #5

            Using TaskScheduler.Default or TaskScheduler.Current work when using the AsyncObservableCollection, its just FromCurrentSynchronizationContext that doesn't.

            1 Reply Last reply
            0
            • C cjb110

              I'm struggling to get my MVVM WPF app to work with a set of Tasks updating the UI. I've got a Command that starts X number of tasks off, for each task I'd like the UI to update when started and when finished. I've also got a second Command to cancel the task, which I'd obviously like working (the code does but as the UI locks the button doesn't) I've used a ListBox bound to an ObvservableCollection<string> for the results, as this seemed better than binding to a string. At the moment I get the UI lockup until all tasks are finished. This is with or without a Task.WaitAll. The results are correct, the tasks don't always start/finish in the same order so they're obviously being generated and updating the collection asynchronously. I've tried an AysncObservableCollection (as per this SO answer) I've tried using the Dispatcher in my method that adds a item to the collection. I've tried variations on the Binding parameters. Can someone give me some hints :confused: Surely people have created a status log with async stuff in MVVM before?? Do I need to move the task creation to the Model? I've seen mention of making sure the Collection is initiated on/by the View, not sure I understand that! The View has a DataContext that's set to my ViewModel. Do they mean I've got to create the Collection in the code behind of the View? that doesn't seem right. Oh this is .NET4.0 on XP, and I'm not using any MVVM frameworks (didn't think that was a good idea as I'm still learning)

              A Offline
              A Offline
              Abhinav S
              wrote on last edited by
              #6

              Use the INotifyPropertyChanged event on the observable collection. This will be a neater and simpler solution.

              WP Apps - Color Search | Arctic | XKCD | Sound Meter | Speed Dial

              C 1 Reply Last reply
              0
              • A Abhinav S

                Use the INotifyPropertyChanged event on the observable collection. This will be a neater and simpler solution.

                WP Apps - Color Search | Arctic | XKCD | Sound Meter | Speed Dial

                C Offline
                C Offline
                cjb110
                wrote on last edited by
                #7

                How do you mean? The ViewModel already had that, and that on its own didn't work. No items were added until the end.

                    private ObservableCollection \_results = new ObservableCollection();
                    public ObservableCollection Results
                    {
                        get { return \_results; }
                        set
                        {
                            \_results = value;
                
                            RaisePropertyChanged("Results");
                        }
                    }
                

                Or do you mean create a class that derives from ObservableCollection and implement it there?

                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