Xamarin создает проблемы с SQLite и await

#c# #sqlite #async-await #xamarin.forms

#c# #sqlite #async-await #xamarin.forms

Вопрос:

Я использую nuget sqlite-net-pcl, в моей модели представления я пытаюсь получить список объявлений из моей базы данных

     private SQLiteAsyncConnection connection;
    public ObservableCollection<Announcement> AnnouncementList { get; private set; }

    public AnnouncementsViewModel() {
        connection = DependencyService.Get<ISQLiteDb>().GetConnection();
        Initialize();
    }    

    public async void Initialize() {
        await connection.CreateTableAsync<Announcement>();
        var announcements = await connection.Table<Announcement>().ToListAsync();
        AnnouncementList = new ObservableCollection<Announcement>(announcements);
        System.Diagnostics.Debug.WriteLine("***********************************");
        System.Diagnostics.Debug.WriteLine(AnnouncementList.Count);
    }
  

в моем коде позади, в конструкторе:

  BindingContext = new AnnouncementsViewModel();
 InitializeComponent();
 var list = (BindingContext as AnnouncementsViewModel).AnnouncementList;
  

Ошибка, которую я получаю, такова:

Исключение System.NullReferenceException: ссылка на объект не установлена для экземпляра объекта.

Я устанавливаю точку останова в своей ViewModel, когда она доходит до первого ожидания, она возвращается к исходному коду, и приложение выходит из строя. Я получаю исключение null, потому что список объявлений не заполнен в ViewModel и не печатал звездочки. Как я могу решить эту проблему?

Спасибо

Комментарии:

1. Какова последовательность вызовов исключения?

2. (BindingContext as AnnouncementsViewModel) бьюсь об заклад, это null

3. @j0ey_wh Я поставил точку останова в этой строке, которая дает мне не удалось разрешить тип: AnnouncementsViewModel

4. @RichardSzalay как мне получить стек вызовов?

5. сделайте это так: var vieModel = BindingContext as AnnouncementsViewModel ; является vieModel нулевым?

Ответ №1:

Вы не можете просто вызвать свой асинхронный Initialize() метод подобным образом. Он вернется немедленно и к тому времени, когда вы приступите к использованию AnnouncementList , Initialize еще не завершен, и он по-прежнему равен null.

Это не идеальное решение, но вы должны добавить .Wait() after Initialize() , чтобы убедиться, что оно завершено до выхода из конструктора.

Я говорю «не идеально», потому что в зависимости от вашего контекста Wait() может произойти блокировка. Если это произойдет, вам, вероятно, лучше выполнить эту инициализацию, прежде чем создавать свою ViewModel, используя только «правильное» ожидание и переход AnnouncementsList в конструктор.

Комментарии:

1. Я не смог выйти. Wait() поскольку Initialize() возвращает void, я изменил ViewModel

2. Чтобы решить эту конкретную проблему, просто измените возвращаемый тип на Task.

3. Когда я запускаю, я получаю только черный экран

Ответ №2:

Новая ViewModel:

   public AnnouncementsViewModel() {
        connection = DependencyService.Get<ISQLiteDb>().GetConnection();
    }
  public async void GetAnnouncement() {
        await connection.CreateTableAsync<Announcement>();
        var announcements = await connection.Table<Announcement>().ToListAsync();
        AnnouncementList = new ObservableCollection<Announcement>(announcements);            System.Diagnostics.Debug.WriteLine("***********************************");
        System.Diagnostics.Debug.WriteLine(AnnouncementList.Count);
    }
  

Затем в моем коде за:

   protected override async void OnAppearing() {
        (BindingContext as AnnouncementsViewModel).GetAnnouncement();
        if ((BindingContext as AnnouncementsViewModel).list != null)
            classAnnouncementListView.ItemsSource = (BindingContext as AnnouncementsViewModel).list;
        base.OnAppearing();
    }
  

Комментарии:

1. Отредактируйте вопрос, чтобы добавить это, а не добавлять ответ.