Xamarin Forms ListView не обновляется из ObservableCollection

ListView моего файла XAML заполняется ViewModel, у которого есть ObservableCollection из службы, но ListView не отображает информацию. Я уже проверяю, что служба возвращает верную информацию.

Это код моего XML-файла:

<?xml version = "1.0" encoding = "utf-8" ?>
<ContentPage xmlns = "http://xamarin.com/schemas/2014/forms"
             xmlns:x = "http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class = "XAMLUnit1.Views.NetflixRoulettePage" Title = "Movie">
    <ContentPage.Content>
         <StackLayout>
         <AbsoluteLayout>
                <BoxView Color = "Gray"  AbsoluteLayout.LayoutFlags = "All" AbsoluteLayout.LayoutBounds = "0,0,1,1"></BoxView>
                <SearchBar x:Name = "searchBar"
                           Placeholder = "Search By Actor's name" 
                           PlaceholderColor = "White"
                           AbsoluteLayout.LayoutFlags = "All"
                           AbsoluteLayout.LayoutBounds = "0.1,0.1,1,1"  SearchCommand = "{Binding SearchMovieCommand}" ></SearchBar>
            </AbsoluteLayout>

       <ListView  x:Name = "ListOfMovies"  
            ItemsSource = "{ Binding MovieList}" >
            <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <StackLayout>
                                <ImageCell 
                                        ImageSource = "{Binding poster_path, StringFormat='https://image.tmdb.org/t/p/w500{0}'}">
                                </ImageCell>
                                    <StackLayout Orientation = "Horizontal">
                                    <TextCell Detail = "{Binding title}"></TextCell>
                                    <TextCell Detail = "{Binding release_date}"></TextCell>
                                </StackLayout>
                            </StackLayout>
                        </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

Это ViewModel, который вызывает службу и использует ее ObservableCollection в качестве ItemsSource для ListView:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using XAMLUnit1.Models;
using XAMLUnit1.ServiceImpl;
using XAMLUnit1.Services;

namespace XAMLUnit1.ViewModels
{
  public  class MovieRouletteViewModel
    {
        IMovieService service;
        public ObservableCollection<Movie> MovieList { get; set; }
        public ICommand SearchMovieCommand { get; set; }
        public MovieRouletteViewModel()
        {
            service = new MovieServiceFinder();
            SearchMovieCommand = new Command(GetMovies);
        }

        private void  GetMovies()
        { var list= service.GetMovies("");
            MovieList = list;

        }

    }
}




public partial class NetflixRoulettePage : ContentPage
    {
        MovieRouletteViewModel viewModel;
        public NetflixRoulettePage()
        {
            InitializeComponent();
            viewModel = new MovieRouletteViewModel();
            BindingContext = viewModel;


        }



        private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
        {
        }
    }

вы установили BindingContext?

Jason 07.05.2018 02:47

Да, похоже, ListView не обновляется динамически. Посмотрите на метод GetMovies, который устанавливает свойство MovieList.

Jose Agustin Reinoso 07.05.2018 02:49

@JoseAgustinReinoso Добавьте код, в котором вы устанавливаете BindingContext

SushiHangover 07.05.2018 02:53

@SushiHangover Я выложил код.

Jose Agustin Reinoso 07.05.2018 02:57

GetMovies () заменяет связанный экземпляр MovieList новым экземпляром

Jason 07.05.2018 03:10
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
5
7 493
4

Ответы 4

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

    public MovieRouletteViewModel()
    {
        service = new MovieServiceFinder();
        SearchMovieCommand = new Command(GetMovies);
        MovieList = new ObservableCollection<Movie>();
    }

    private void  GetMovies()
    { 
        var list= service.GetMovies("");
        MovieList.Clear();
        foreach(Movie movie in list)
        {
              MovieList.Add(movie);
        }
    }

Я не согласен с тем, что это нарушит привязку.

François 07.05.2018 07:31

При очистке вместо создания нового списка он сохраняет привязку для меня, как указано на плакате.

Westerlund.io 15.02.2019 22:57

Ваша служебная команда фактически заменяет ObservableCollection, вам необходимо изменить метод GetMovies() на

var list = service.GetMovies("");
MovieList.clear();
foreach(Movie m in list)
{ MovieList.Add(m);}

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

Однако есть несколько решений.

  1. Внедрите INotifyPropertyChanged в коллекцию и замените всю коллекцию, как вы это делаете. Это будет работать нормально. Однако он сбрасывает прокрутку и в основном пересчитывает все с нуля. Кто-то скажет, что это побеждает достоинства ObservableCollection, поскольку у них есть собственная встроенная система уведомлений. Да, это так. Хотя, если вы заменяете всю коллекцию новой коллекцией, вы собираетесь сэкономить на кучу циклических вычислений по сравнению с очисткой и добавлением каждого элемента обратно индивидуально, что в основном будет срабатывать при каждом обновлении.

  2. Звоните Clear и Add по каждому элементу индивидуально. Если коллекция не сильно изменилась, вы можете даже сделать еще один шаг, просто сравнив 2 коллекции и обновив то, что необходимо. Однако еще раз, если коллекции не похожи, тогда этот подход все еще дорог, и на мобильном устройстве вы хотите минимизировать пересчет экрана там, где это возможно.

  3. Создайте коллекцию с подклассами, реализуйте свои собственные методы замены / обновления и добавления / удаления диапазона, а INotifyPropertyChanged предоставит вам лучшее из обоих миров, это позволит атомарную модификацию коллекции, а затем вы можете один раз запустить событие изменения свойства.

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

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

В любом случае удачи

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

Проблема в том, что ваш viewmodel не поддерживает INotifyPropertyChanged.

Ваш пользовательский интерфейс просто не уведомляется, когда вы устанавливаете ObservableCollection.

Я согласен с вами, но в настоящее время я борюсь с этой проблемой на одной странице, даже с внедренным INPC, и по-прежнему список не обновляется. Интересно, что он обновляется, если я инициализирую модель просмотра в ctor модели просмотра, но НЕ, если данные изменяются в подписке MessagingCenter.

Frank 16.02.2021 15:54

Другие вопросы по теме