2
\$\begingroup\$

I have a WPF application, in which I'd like to bind a collection to a combobox using an asynchronous method :

<ComboBox  Margin="2,0,5,0" Width="178" ItemsSource="{Binding Animateur}" DisplayMemberPath="nom"   SelectedIndex="0"  />

the viewmodel class

_service.GetAnimateur((item, error) =>
                      {
                          if (error != null)
                          {
                              // TODO : traitement d'erreur
                          }
                          else
                          {
                              _Animateur.Clear();
                              item.ForEach(Elem =>
                              {
                                  _Animateur.Add(Elem);
                              });

                          }
                      });

the Asynchrounous method :

public async void GetAnimateur(Action<List<fiche>, Exception> callback)
        {
            try
            {
                Task<List<fiche>> data = (Task<List<fiche>>)Task.Run(
                    () =>
                    {
                        DataEntities _db = new DataEntities();
                        var dpcs = _db.fiche;
                        return new List<fiche>(dpcs);
                    });
                var result = await data;
                callback(result, null);
            }
            catch (Exception ex)
            {
                callback(null, ex);
            } 
        }

I have 20128 items in the table fiche, the problem is that GetAnimateur takes a lot of time to fill the combobox.

  1. What are the errors that I commited in this code?
  2. How can I improve it?
\$\endgroup\$
  • 1
    \$\begingroup\$ // TODO : traitement d'erreur? Are you sure this code is complete? \$\endgroup\$ – RubberDuck Feb 14 '15 at 11:14
  • \$\begingroup\$ @RubberDuck this is the exception handling part(if the connection to the database were lost....) I will add some lines of codes to log the error \$\endgroup\$ – Lamloumi Afif Feb 15 '15 at 11:23
7
\$\begingroup\$

First, I want to point out the behavior of method that is declared as async void. When the code reaches this line:

var result = await data;

The code following after _service.GetAnimateur is executed. async void is there only for event handlers. So using this signature creates more problems than it solves.

Second, I may not see the whole picture, but your GetAnimateur looks weird. I think it is because the problem I've mentioned earlier. The most readable and understandable may be code like:

public Task<IEnumerable<fiche>> GetAnimateur()
{
        return Task.Factory.StartNew(() =>
            {
                DataEntities _db = new DataEntities();
                return (IEnumerable<fiche>) _db.fiche;
            });
}

and consume like:

try
{
    var list = await GetAmateur();
    // success
}
catch (Exception ex)
{
    // fail
}

or even:

GetAmateur().ContinueWith(t =>
    {
        if (t.IsCompleted)
        {
            var list = t.Result;
            // success
        }
        else
        {
            var ex = t.Exception;
            // fail
        }
    }, TaskScheduler.FromCurrentSynchronizationContext());

Third, when you add or remove an item from ObservableCollection, the UI gets updated, slowing down performance. One common way to create an observable collection that supports painless multi-adding is

public class RangeObservableCollection<T> : ObservableCollection<T>
{
    private bool _suppressNotification = false;

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (!_suppressNotification)
            base.OnCollectionChanged(e);
    }

    public void AddRange(IEnumerable<T> list)
    {
        if (list == null)
            throw new ArgumentNullException("list");

        _suppressNotification = true;

        foreach (T item in list)
        {
            Add(item);
        }
        _suppressNotification = false;
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
}

So you simply use RangeObservableCollection instead of ObservableCollection.

Fourth, just don't forget about tuning your EF properly for better performance.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.