Search code examples
c#wpfmultithreadingbackgroundworker

UI still freezes using backgroundWorker


I'm quite new to WPF. I am developing a PRISM application and want to update the UI when an enumerable is updated. I use a backgroundWorker in my modelView to update the enumaration. it all works fine until the enumeration it self gets updated and then the UI freezes!! a friend told my I might be able to use the yield keyword but I didn't quite figured it out.

Here is the code:

public void ChangeCollection()
    {
        BackgroundWorker worker = new BackgroundWorker();

        // Set workers job
        worker.DoWork += (sender, e) =>
            {
                RunOnUIThread(() => IsBusy = true);
                e.Result = GetPrimes();
            };

        // On Complete
        worker.RunWorkerCompleted += (sender, e) =>
            {
                RunOnUIThread(() =>
                    {
                        IsBusy = false;

                        // HERE IS WHERE IT GETS STUCK
                        Numbers = new ObservableCollection<int>
                            ((IEnumerable<int>)e.Result);
                    });
            };

        // Start background operation
        worker.RunWorkerAsync();
    } 

    public ObservableCollection<int> Numbers 
    { 
        get {return _Numbers;} 
        set
        {
            _Numbers = value;
            RaisePropertyChanged(() => Numbers);
        }
    }

    public IEnumerable<int> GetPrimes()
    {
        List<int> primes = new List<int>();

        for (int i = 0; i < 100000; i++)
        {
            bool IsPrime = true;

            for (int j = 2; j < i; j++)
            {
                if (i % j == 0)
                    IsPrime = false;
            }

            if (IsPrime)
                primes.Add(i);
        }

        return primes;
    } 

Any advise would be greatly appriciated!

Thanks, Omri


Solution

  • A few things here. 1) Your worker and its delegates should be created when your object containing it is instantiated.

    public class ViewModel 
    {
        BackgroundWorker _primeWorker;
    
        public ViewModel()
        {
            _primeWorker = new BackgroundWorker;
    
            _primeWorker.DoWork += ...
        }
    
        public void AddSomeNumbers()
        {
             if(_primerWorker.IsBusy == false)
                  _primeWorker.RunWorkerAsync();
        }
    }
    

    2) Your collection should be instantiated when the object containing it is instantiated to avoid a null exception being thrown should the object using this class calls the get.

    3) Adding that many items would cause slowness due to each time you add a number an event is fired that the UI thread has to handle.

    This link has more info to help you out. http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx