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)
{
}
}
Да, похоже, ListView не обновляется динамически. Посмотрите на метод GetMovies, который устанавливает свойство MovieList.
@JoseAgustinReinoso Добавьте код, в котором вы устанавливаете BindingContext
@SushiHangover Я выложил код.
GetMovies () заменяет связанный экземпляр MovieList новым экземпляром





Не устанавливайте 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);
}
}
Я не согласен с тем, что это нарушит привязку.
При очистке вместо создания нового списка он сохраняет привязку для меня, как указано на плакате.
Ваша служебная команда фактически заменяет ObservableCollection, вам необходимо изменить метод GetMovies() на
var list = service.GetMovies("");
MovieList.clear();
foreach(Movie m in list)
{ MovieList.Add(m);}
Есть несколько вещей, которые я хочу отметить по этой проблеме, хотя в основном, поскольку комментарии правильно освещают, замена коллекции новой коллекцией нарушает привязки. следовательно, почему он не обновляется.
Однако есть несколько решений.
Внедрите INotifyPropertyChanged в коллекцию и замените всю коллекцию, как вы это делаете. Это будет работать нормально. Однако он сбрасывает прокрутку и в основном пересчитывает все с нуля. Кто-то скажет, что это побеждает достоинства ObservableCollection, поскольку у них есть собственная встроенная система уведомлений. Да, это так. Хотя, если вы заменяете всю коллекцию новой коллекцией, вы собираетесь сэкономить на кучу циклических вычислений по сравнению с очисткой и добавлением каждого элемента обратно индивидуально, что в основном будет срабатывать при каждом обновлении.
Звоните Clear и Add по каждому элементу индивидуально. Если коллекция не сильно изменилась, вы можете даже сделать еще один шаг, просто сравнив 2 коллекции и обновив то, что необходимо. Однако еще раз, если коллекции не похожи, тогда этот подход все еще дорог, и на мобильном устройстве вы хотите минимизировать пересчет экрана там, где это возможно.
Создайте коллекцию с подклассами, реализуйте свои собственные методы замены / обновления и добавления / удаления диапазона, а INotifyPropertyChanged предоставит вам лучшее из обоих миров, это позволит атомарную модификацию коллекции, а затем вы можете один раз запустить событие изменения свойства.
В Интернете есть много примеров всех этих подходов, просто стоит отметить, что удаление и добавление элементов иногда не лучший подход для мобильных устройств. Это зависит от того, насколько велики ваши коллекции, насколько они меняются и почему.
В любом случае удачи
Я не согласен с другими ответами. Вы можете устанавливать Movies сколько угодно раз, это не проблема.
Проблема в том, что ваш viewmodel не поддерживает INotifyPropertyChanged.
Ваш пользовательский интерфейс просто не уведомляется, когда вы устанавливаете ObservableCollection.
Я согласен с вами, но в настоящее время я борюсь с этой проблемой на одной странице, даже с внедренным INPC, и по-прежнему список не обновляется. Интересно, что он обновляется, если я инициализирую модель просмотра в ctor модели просмотра, но НЕ, если данные изменяются в подписке MessagingCenter.
вы установили BindingContext?