Как я могу обновить глобальную коллекцию с помощью асинхронного метода и привязки в представлении? - PullRequest
0 голосов
/ 06 ноября 2018

Мне нужно получить данные из базы данных, чтобы получить необходимые элементы для некоторых комбинированных списков. У меня есть асинхронный метод, который получает все данные, и он вызывается от construtor. Код такой.

private async Task getDataASync()
{
    Task<List<Typ01>> miTsk01 = VariablesGlobales.getData01Async();
    Task<List<Type02>> miTsk02 = VariablesGlobales.getData02Async();
    Task<List<Type03>> miTskT03 = VariablesGlobales.getData03Async();
    Task<List<Type04>> miTsk04 = VariablesGlobales.getData04Async();



    await Task.WhenAll(miTsk01,
    miTsk02,
    miTsk03,
    miTsk04).ConfigureAwait(false);


    GlobalVariables.vgData01.AddRange(miTsk01.Result);
    GlobalVariables.vgData02.AddRange(miTsk02.Result);
    GlobalVariables.vgData03.AddRange(miTsk03.Result);
    GlobalVariables.vgData04.AddRange(miTsk04.Result);
}




public MyViewModel()
{
    getDataASync();
}

XAML

    <ComboBox
      SelectedItem="{Binding MySelectedItem01}"
      ItemsSource="{x:Static vg:VariablesGlobales.vgData01}">
    </ComboBox>

<ComboBox
  SelectedItem="{Binding MySelectedItem02}"
  ItemsSource="{x:Static vg:VariablesGlobales.vgData02}">
</ComboBox>

<ComboBox
  SelectedItem="{Binding MySelectedItem03}"
  ItemsSource="{x:Static vg:VariablesGlobales.vgData03}">
</ComboBox>

<ComboBox
  SelectedItem="{Binding MySelectedItem04}"
  ItemsSource="{x:Static vg:VariablesGlobales.vgData04}">
</ComboBox>

Проблема в том, что я получаю сообщение об ошибке, в котором говорится, что collectionView не может быть изменен другим подпроцессом, отличным от Dispatcher.

Я попытался создать свойство в моей модели представления, которое получает данные из глобальной переменной, и представление связывает это свойство, и затем оно работает.

Действительно, я не очень хорошо понимаю проблему, потому что в методе, который получает данные из базы данных, он ждет, пока я получу все данные, а затем я обновлю глобальные коллекции. Я думал, что я в той же теме, что и основное приложение, но, похоже, я ошибаюсь.

Как я могу обновить глобальные коллекции, чтобы их можно было связать с представлением?

Спасибо.

Ответы [ 2 ]

0 голосов
/ 07 ноября 2018

Действительно, я не очень хорошо понимаю проблему, потому что в методе, который получает данные из базы данных, он ждет, пока я получу все данные, а затем я обновлю глобальные коллекции. Я думал, что я был в той же теме, что и основное приложение, но, похоже, я не прав.

При условии, что вы вызываете getDataASync() в потоке пользовательского интерфейса, единственное, что вам нужно сделать, - это захватить контекст, удалив вызов ConfigureAwait(false):

await Task.WhenAll(miTsk01,
    miTsk02,
    miTsk03,
    miTsk04);

ConfigureAwait(false) предотвращает захват контекста, что означает, что остаток вашего getDataASync() будет выполнен в потоке пула потоков после завершения метода Task.WhenAll, в отличие от того, который выполняется в том же потоке, что и getDataASync() метод был первоначально вызван.

Рекомендуется использовать ConfigureAwait(false) в сервисных методах и везде, где вы можете, но методы, для которых действительно необходим контекст, такой как getDataASync(), где вы заполняете коллекции с привязкой к данным, явно являются исключением. Пожалуйста, обратитесь к @ статье MSDN Magazine Стивена Клири для получения дополнительной информации об этом.

0 голосов
/ 06 ноября 2018

Есть несколько способов справиться с этим.

Самое простое - просто использовать ConfigureAwait (true), который гарантирует, что любое продолжение будет в том же потоке.

await Task.WhenAll(miTsk01,
miTsk02,
miTsk03,
miTsk04).ConfigureAwait(true);

GlobalVariables.vgData01.AddRange( await miTsk01);
GlobalVariables.vgData02.AddRange( await miTsk02);
GlobalVariables.vgData03.AddRange( await miTsk03);
GlobalVariables.vgData04.AddRange( await miTsk04);

Пара заметок

  • Вам следует избегать использования Task.Result, так как это может привести к взаимоблокировке, даже если задача должна быть уже завершена - просто используйте вместо этого задачу await (как указано выше).
  • Вероятно, ваши коллекции должны быть ObservableCollection, а не List, что будет отражать любые изменения в List для связанных элементов управления UI. Они не поддерживают AddRange () в стандартной комплектации, поэтому вам нужно будет добавлять элементы по отдельности.

Альтернативный метод - использовать класс, такой как этот из MvvmLight, который будет захватывать контекст пользовательского интерфейса при запуске приложения, который затем может использоваться в качестве контекста для обновлений пользовательского интерфейса из другого потока.

...