Question

I am building composite WPF application using MVVM-light. I have Views that have ViewModels injected into them using MEF:

DataContext = App.Container.GetExportedValue<ViewModelBase>(
                ViewModelTypes.ContactsPickerViewModel);

In addition, I have ViewModels for each View (Screens and UserControls), where constructor usually looks like this:

private readonly ICouchDataModel _couchModel;

    [ImportingConstructor]
    public ContactsPickerControlViewModel(ICouchDataModel couchModel)
    {
        _couchModel = couchModel;
        _couchModel.GetContactsListCompleted+=GetContactsListCompleted;
        _couchModel.GetConcatcsListAsync("Andy");
    } 

Currently, I have some performance issues. Everything is just slow. I have 2 kind of related questions

  1. What is the right way of calling DAL methods asynchronously (that access my couchdb)? await/async? Tasks? Because currently I have to write a lot of wrappers(OnBegin, OnCompletion) around each operation, I have GetAsyncResult method that does some crazy things with ThreadPool.QueueUserWorkItem , Action etc. I hope there is the more elegant way of calling

  2. Currently, I have some screens in my application and on each screen, there are different custom UserControls, some of them need same data (or slightly changed) from DB. Questions: what is the right way to share datasource among them? I am mostly viewing data, not editing.

    Example: On Screen A: I have Contacts dropdown list user control (UC1), and contact details user control(UC2). In each user control, their ViewModel is calling DAL:

    _couchModel.GetConcatcsListAsync("Andy");

And on completion I assign result data to a property:

List<ContactInfo> ContactsList = e.Resuls; 

ContactsList is binded to ItemsSource of DropDownListBox in UC1. The same story happens in UC2. So I end up with 2 exactly same calls to DB. Also If I go to Screen B, where I have UC1, I’ll make another call to DB, when I’ll go to Screen B from Screen A.

What is the right way to making these interaction ? e.g. Getting Data and Binding it to UC.

Thank you.

Was it helpful?

Solution

Ad.1
I think you can simply use Task.Factory to invoke code asynchronously (because of that you can get rid off OnBegin, OnCompletion) or if you need more flexibility, than you can make methods async.

Ad. 2
The nice way (in my opinion) to do it is to create DatabaseService (singleton), which would be injected in a constructor. Inside DatabaseService you can implement some logic to determine whether you want to refresh a collection(call DAL) or return the same (it would be some kind of cache).

Then you can call DatabaseService instead of DAL directly and DatabaseService will decide what to do with this call (get collection from DB or return the same or slightly modified current collection).


Edit:
DatabaseService will simply share a collection of objects between ViewModels.
Maybe the name "DBCacheService" would be more appropriate (you will probably use it only for special tasks as caching collections).

I don't know your architecture, but basically you can put that service in your client application, so the plan would be:

  1. Create DatabaseService.cs

    [Export(typeof(IDatabaseService))]
    public class DatabaseService : IDatabaseService
    {
        private List<object> _contacts = new List<object>();
    
        public async Task<List<object>> GetConcatcsList(string name)
        {
            if (_contacts.Count == 0)
            {
                //call DAL to get it
                //_contacts = await Task.Factory.StartNew(() => dal.GetContactsList(name));
            }
            else
            {
                //refresh list if required (there could be some condition)                
            }
    
            return _contacts;
        }
    }
    
  2. Add IDatabaseService to your ViewModel's constructor.

  3. Call IDatabaseService instead of DAL.

If you choose async version of DatabaseService, then you'll need to use await and change your methods to async. You can do it also synchronously and call it (whenever you want it to be asynchronous) like that:

Task.Factory.StartNew(() => 
{
    var result = dbService.GetContactsList("Andy");
});

Edit2:

invoking awaitable method inside Task:

Task.Factory.StartNew(async () => 
{
    ListOfContacts = await _CouchModel.GetConatcsList ("Andy");
});
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top