2

I have recently been trying to learn the process of using Task in WPF and have ran into a snag which more than likely is due to my lack of experience. When executing an asychronous call to my dataservice method "GetFutureWork" the UI thread becomes unresponsive. The code can be seen below. Note this project uses MVVM and the Variable "WorkList" is simply an observable collection used for my listiview's itemsource.

  private async void LoadWork()
    {
        WorkList = await _dataService.GetFutureWork("UserNameHere");
    }

DataService Task

public async Task<IEnumerable<FutureWork>> GetFutureWork(string userName)
    {
        using (_db = new DataEntities())
        {
            var workList = await (from items in _db.REPAIR_CHECK_IN_TABLEs
                where items.LOCATION == userName && items.COMPLETED == "N"
                select new FutureWork
                {
                    FormattedDate = items.EstShipDate.ToString(),
                    ServiceID = items.SERVICE_ID,
                    ImagePath = @"\\192.168.5.50\photos$\" + items.SERVICE_ID + "P1.bmp",
                    Priority = items.PRIORITY
                }).ToListAsync();
            return workList;
        }
    }
HighARc
  • 117
  • 2
  • 11
  • Is `LoadWork()` called from the UI thread? What causes this method to be called? How much time does the constructor of `DataEntities` take? Is there anything special inside it? – Yacoub Massad Jan 07 '16 at 19:14
  • Yes LoadWork Is called from the UI Thread. It is called from the constructor of the viewmodel. ` public FutureWorkViewModel(IDataService dataService) { _dataService = dataService; LoadWork(); }` The constructor of the dataentities takes 145ms so i feel it may not be to blame. – HighARc Jan 07 '16 at 19:39
  • you need to await LoadWork(); as well – AJ X. Jan 07 '16 at 19:41
  • @axlj is right, you have to use `async` & `await` all the way up to be truly async. However, you can't declare constructors as `async` (so that you can `await` inside them) so you better [explore some other options](http://blog.stephencleary.com/2013/01/async-oop-2-constructors.html). – Michael Jan 07 '16 at 19:45
  • In general, it is not a good idea to call `async` methods in the constructor since the object will be constructed before the `async` method completes. However, this does not explain why the application stops responding. Maybe the constructor of `DataEntities` takes a lot of time? Please note that `new DataEntities()` will run on the UI thread. – Yacoub Massad Jan 07 '16 at 19:46
  • Thanks for the help all. I was going about this the wrong way calling the async method from the constructor. I was able to trigger a command to load the method "LoadWork()" once the window had finished loading. See the solution here. [link](http://stackoverflow.com/questions/24572064/calling-async-method-to-load-data-in-constructor-of-viewmodel-has-a-warning) – HighARc Jan 07 '16 at 19:53

1 Answers1

2

You can't call an async function from a window constructor, so as others have mentioned, you'll need another way.

You could use the Window_Loaded event instead of the constructor.

private async void Window_Loaded(object sender, RoutedEventArgs e)
{
    await LoadWork();
}

Then hook it up:

<Window x:Class="AsyncWindow.MainWindow" ... Loaded="Window_Loaded">

EDIT:

If you would prefer to stick with the MVVM pattern, an alternate solution is posted here.

Community
  • 1
  • 1
AJ X.
  • 2,729
  • 1
  • 23
  • 33
  • 1
    Thanks for this, see link I posed above. I achieved a similar fix while still maintaining MVVM design pattern. – HighARc Jan 07 '16 at 19:55
  • Ah perfect. I'd most definitely prefer that way over the way I proposed. Thanks! – AJ X. Jan 07 '16 at 19:59
  • I updated my answer to include the link you mentioned so others don't need to dig through the comments to find it. – AJ X. Jan 07 '16 at 20:04