Я рендер ListView
<StackLayout>
<Label Text = "Test"/> //This Label is getting rendered
<ListView ItemsSource = "{Binding MusicList,Mode=TwoWay}"
HasUnevenRows = "True"
IsPullToRefreshEnabled = "True"
CachingStrategy = "RecycleElement"
SeparatorColor = "DarkGray">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Label Text = "{Binding Name}" TextColor = "Black"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
Чей ItemsSource привязан к ObservableCollection<Music>
, который доступен в ViewModel
. Вот как я привязываю ViewModel
.
public MainPage()
{
BindingContext = new MainViewModel();
InitializeComponent();
}
Это мой ViewModel
, и здесь я вызываю методы API для получения данных.
private ObservableCollection<Music> _MusicList=new ObservableCollection<Music>();
public ObservableCollection<Music> MusicList
{
get { return _MusicList; }
set
{
if (_MusicList != value)
{
_MusicList = value;
OnPropertyChanged("_MusicList");
}
}
}
public MainViewModel()
{
api = new ApiHelper();
GetSongs();
}
public async void GetSongs()
{
_MusicList = new ObservableCollection<Music>(await api.GetMusicListAsync());
}
Данные поступают в ObservableCollection<Music>
ОБНОВИТЬ
Просто для тестирования я попытался привязать простой строковый список ListStrings = new List<string> {"A","B","C","D","E","F" };
, но он также не появился.
ОБНОВИТЬ Теперь я переопределил метод onAppearing, инициализировал свой список и установил для него ListView ItemsSource. и он работает сейчас .. но не знаю, почему он не работает с привязкой.
У вас есть свойство Name
в вашем классе Music
?
Есть пара вещей, которые могут вызвать проблемы.
ItemsSource = "{Binding MusicList,Mode=TwoWay}"
есть ли веская причина сделать его двухсторонним? Если нет, не делай этого.BindingContext
после InitializeComponent();
Не создавайте новый ObservableCollection
при получении данных. Создавая новую коллекцию, вы теряете привязку данных. Вместо этого измените его так:
public async void GetSongs()
{
var result = await api.GetMusicListAsync();
foreach (var r in result)
_MusicList.Add(r);
}
извините, но ничего не помогло ... я переопределил метод onAppearing, тогда он показал список ... пока не понимаю проблему: /
Пожалуйста, обновите вопрос, указав, что вы пробовали до сих пор
Я думаю, вы совершили ошибку, подняв недвижимость после изменения:
private ObservableCollection<Music> _MusicList=new
ObservableCollection<Music>();
public ObservableCollection<Music> MusicList
{
get { return _MusicList; }
set
{
_MusicList = value;
OnPropertyChanged("MusicList"); //You should raise property change on your Binding variable.
}
}
Как сказал @Gerald, следуйте его совету, и я добавляю, чтобы дать вам представление о решении третьей проблемы, которую он упомянул.
Если вы создаете свою Observable Collection каждый раз, когда получаете данные, вы теряете привязку данных. Если вы используете метод foreach, который будет вызывать событие изменения коллекции несколько раз, если у вас большой список, это может быть проблемой для вас.
Следующая расширенная коллекция поддерживает различные типы коллекции и имеет свойство Сбросить наблюдаемую коллекцию.
В конструкторе модели представления вы можете инициализировать свою коллекцию один раз, например:
public MusicPageViewModel()
{
MusicsData=new ExtendedCollection<Music>();
}
Затем всякий раз, когда вы будете получать данные из своего API, вы будете делать что-то вроде:
public GetMusicsData()
{
MusicsData.Reset(YourApi.GetMusics());
}
Надеюсь, это поможет вам реализовать вашу коллекцию Observable. Это расширенная коллекция Observable, которую вы можете использовать и расширять, если вам нужно:
public class ExtendedCollection<T> : ObservableCollection<T>
{
public ExtendedCollection()
: base()
{
}
public ExtendedCollection(IEnumerable<T> collection)
: base(collection)
{
}
public ExtendedCollection(List<T> list)
: base(list)
{
}
/// <summary>
/// Reset the existings items and fills the new items provided.
/// </summary>
/// <param name = "range"></param>
public void Reset(IEnumerable<T> range)
{
this.Items.Clear();
if (range != null)
{
AddRange(range);
}
}
/// <summary>
/// Add all items in the range;
/// </summary>
/// <param name = "range"></param>
public void AddRange(IEnumerable<T> range)
{
foreach (var item in range)
{
Items.Add(item);
}
//Raise the property change!
this.OnPropertyChanged(new PropertyChangedEventArgs("Count"));
this.OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
извините, но ничего не помогло ... я переопределил метод onAppearing, тогда он показал список ... пока не понимаю проблему: /
Сегодня нашел решение.
public MainPage()
{
InitializeComponent();
BindingContext = this; //Added this
}
Просто добавил BindingContext = this;
в конструктор. Я не знаю, что не так с Xamarin, думаю, это ошибка.
Я последовал за ответом @Gerald Versluis, и это сработало. Я создавал новый Observable при получении данных, и мне нужно было просто использовать метод add () из Observable. Кроме того, мне пришлось инициализировать Observable в конструкторе моей ViewModel.
Эта проблема была решена изменением способа объявления свойств в наблюдаемом объекте. Пример:
Это не удалось
public class MusicItem
{
public string Name;
}
Это сработало успешно:
public class MusicItem
{
public string Name {get; set;}
}
Привязка не может найти имя свойства в первом примере, но работает во втором.
Замените этот
MusicList = new ObservableCollection<Music>(await api.GetMusicListAsync());
на этот_MusicList = new ObservableCollection<Music>(await api.GetMusicListAsync());