0

I'm working on a WPF application in which a ViewModel periodically checks a data source to determine if it needs to change the contents of a list. If the ViewModel realizes that the data has changed, it updates a list and the corresponding view updates.

However, I'm struggling to get the update mechanism to work. Within my ViewModel, I declare a timer object. I set this timer for a 1 second interval, subscribe one of my ViewModel methods to the event, and then start the timer.

When the timer triggers and I attempt to change the list, I get a "System.NotSupportedException"

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

So I'm looking for a way around this. I'm relatively new to C# but have thought of a view possible solutions:

  • Have my viewmodel implement a 'run' method in which it just while loops indefinitely and polls a member boolean value that is set via the timer elapsed event. However, this method seems hacky.

  • Find an alternative list object that supports multithreaded access. However, I'm unaware of such a class.

It's also possible that I'm missing the obvious solution since I'm a newbie in C#.

I'd appreciate any thoughts!

Minimal code:

 public class ConnectionPresenter : ObservableObject
 {
      /* private */
      private readonly ObservableCollection<string> _connectedUsers = new ObservableCollection<string> { "Bob" };
      Timer _updateTimer = new Timer(1000);


      public ConnectionPresenter()
      {
           _updateTimer.Elapsed += this.CheckConnections;
           _updateTimer.AutoReset = true;
           _updateTimer.Start();
      }

      private void CheckConnections(object sender, ElapsedEventArgs e)
      {
           _connectedUsers.Add("Bob");
      }

 }
Izzo
  • 4,461
  • 13
  • 45
  • 82
  • I am on mobile but look up the dispatcher – Bailey Miller Aug 04 '17 at 03:08
  • it will go something like Dispatcher.Run and then lambda expression then the code you already have. – Bailey Miller Aug 04 '17 at 03:09
  • You should find better search engine to use... Either google or https://www.bing.com/search?q=from+a+thread+different+from+the+Dispatcher+thread should be fine. I'd recommend against using search on sites like https://www.disney.com/ for programming questions. If none of search result help - make sure to [edit] your question with things you've tried (i.e. from duplicate I selected) and how it did not solve the problem. – Alexei Levenkov Aug 04 '17 at 03:12
  • I am on mobile so ehh but try this just replace code in middle. Dispatcher.Invoke(() =>             {                 btn1.Content = "By Invoke";             }); – Bailey Miller Aug 04 '17 at 03:12
  • private object _lock = new object(); BindingOperations.EnableCollectionSynchronization(_connectedUsers, _lock); is a better solution – rmbq Aug 04 '17 at 08:29

1 Answers1

0

This might work for your case:

 private void CheckConnections(object sender, ElapsedEventArgs e)
 {
      App.Current.Dispatcher.Invoke(() => _connectedUsers.Add("Bob"));
 }
praty
  • 535
  • 2
  • 9