Work with Backgroundworker and Dispatcher



  • I'm writing a program on C# with mvvm. I have two equivalent pieces of code that I think should do exactly the same job. The essence of what is the gradual loading(s) of elements in the collection with the help of BackgroundWorker. The collector has a binding listview and, accordingly, a gradual (objective) addition is displayed in this listview. Code:

    public class ListContactViewModel : ViewModelBase
    {
     public ObservableCollection<MessageChild> DialogListFirstPage { get;set;}
     Dispatcher _dispatcher;
      public ListContactViewModel(VkApi vk)
        {  
            _dispatcher = Application.Current.Dispatcher;
    
       DialogListFirstPage = new ObservableCollection&lt;MessageChild&gt;();
        var bw1 = new BackgroundWorker();
        bw1.DoWork += (o, e) =&gt;
        {
            FirstDialogPageMethod(vk); //Создание коллекции диалогов
    
        };
        bw1.RunWorkerAsync();
    

    //внимания в этом методе достойна только строчка добавления в коллекцию
    private void FirstDialogPageMethod(VkApi vk)
    {
    int totalCount, unreadCount;
    var GetFirstDialigPage = vk.Messages.GetDialogs(20, 0, out totalCount, out unreadCount);

        foreach (var i in GetFirstDialigPage)
        {
    
            var Names = vk.Users.Get(i.UserId.ToString(), ProfileFields.FirstName);
    
           _dispatcher.Invoke(()=&gt; DialogListFirstPage.Add(new MessageChild() { AuthorFirstName = Names.FirstName, AuthorLastName = Names.LastName, Body = i.Body, UserId = i.UserId, Date = i.Date, ChatActiveIds = i.ChatActiveIds, Title = i.Title, UsersCount = i.UsersCount, ChatId = i.ChatId }));
    
        }        
    }
    

    In case I bring a binding line from the chaml:

     <ListBox  ItemsSource="{Binding  DialogListFirstPage,Mode=TwoWay}" >

    And it's all legal, the window opens empty, and I'm watching a permanent addition to the list.

    Situation 2: From the previous window, I'm going to the next one where the same situation is.

      public class CurrentDialogViewModel:ViewModelBase
    {
    public ObservableCollection<MessageChild> ReadyCollection { get; set; }
    Dispatcher disp;
    public CurrentDialogViewModel(VkApi vk,MessageChild parametr)
    {
    disp = Application.Current.Dispatcher;
    ReadyCollection = new ObservableCollection<MessageChild>();
    var bw2 = new BackgroundWorker();
    bw2.DoWork += (p, m) =>
    {

           MoreMessages();
    
       };
       bw2.RunWorkerAsync();
    

    private void MoreMessages()
    {
    foreach (var i in builder.ConcreateDialogCreater(ids))
    {
    disp.Invoke(() => ReadyCollection.Insert(0, i));

       }
       Datas.offset += 200;
    

    }

    where builder.ConcreateDialogCreater(ids) returns

     ObservableCollection<MessageChild>

    Xaml:

       <ListBox ItemsSource="{Binding  ReadyCollection,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">

    So, in this case, when the window opens, it's been empty for a while, after which the list instantly displays all the into ReadyCollection.
    It doesn't have to be inserted, with Add. It doesn't depend on it. builder.ConcreateDialogCreater(ids)'cause I tried to just initialize the object when it was added to the cycle.

     ReadyCollection.Add(new MessageChild());

    A similar historical site is being distributed to all scopes at the end of the last addition. And I want to get a gradual underload like the previous window.
    Why is this happening and what needs to be fixed?

    UPD:
    Once again, I was wrong, and the delay was related to the method of builder. ConcreateDialogCreater(ids). And until he's done the whole-foreach thing doesn't start.
    In the first case, I complete the collection directly in that class and the delay is justified by the work of library methods before adding.
    Again, we need to wait until the method is fully implemented.



  • In DoWork instead of Dispatcher, use the ReportProgress.
    (The WorkerReportsProgress should be included for its work).

    partial class MainWindow : Window {
        public MainWindow() {
            this.DataContext = _List = new ObservableCollection<Message>();
        }
    
    ObservableCollection&lt;Message&gt; _List;
    
    private void Button_Click(object sender, RoutedEventArgs e) {
        var w = new BackgroundWorker() { WorkerReportsProgress = true };
        w.DoWork += (s, we) =&gt; { 
            for (var i = 0; i &lt; 50; i++) {
                Thread.Sleep(100);   // тут что-то делаем 
                w.ReportProgress(0, i);
            }
        };
        w.ProgressChanged += (s, we) =&gt; // выполняется в основном потоке
           _List.Add(new Message() { Text = "t" + we.UserState });
        w.RunWorkerAsync();
    }
    
    class Message {
        public string Text { get; set; }
    }
    

    }




Suggested Topics

  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2
  • 2