При работе со списком объектов мы можем столкнуться с проблемой добавления или удаления объектов в этом списке. Так, допусти, у нас данные представлены классом User, который представляет пользователя:
public class User { public string Name { get; set; } = ""; public int Age { get; set; } }
Определим на странице элемент ListView для вывода списка объектов User и поля для добавления одного объекта в список:
namespace HelloApp; class StartPage : ContentPage { public List<User> Users { get; set; } Entry nameEntry, ageEntry; public StartPage() { // определяем данные Users = new List<User> { new User {Name="Tom", Age=38 }, new User {Name = "Bob", Age = 42} }; ListView listView = new ListView(); // определяем источник данных listView.ItemsSource = Users; // определяем шаблон данных listView.ItemTemplate = new DataTemplate(() => { // привязка к свойству Name Label nameLabel = new Label { FontSize = 16 }; nameLabel.SetBinding(Label.TextProperty, "Name"); // привязка к свойству Age Label ageLabel = new Label { FontSize = 14 }; ageLabel.SetBinding(Label.TextProperty, "Age"); // создаем объект ViewCell. return new ViewCell { View = new StackLayout { Padding = new Thickness(0, 5), Orientation = StackOrientation.Vertical, Children = { nameLabel, ageLabel } } }; }); // поля для добавления нового объекта User nameEntry = new Entry { Placeholder = "Enter name", Margin=5 }; ageEntry = new Entry { Placeholder = "Enter age", Margin=5 }; Button saveButton = new Button { Text = "Save", WidthRequest=100, Margin=5, HorizontalOptions = LayoutOptions.Start }; saveButton.Clicked += SaveButton_Clicked; StackLayout form = new StackLayout { Orientation = StackOrientation.Vertical, Children = { nameEntry, ageEntry, saveButton } }; Content = new StackLayout { Children = { form, listView }, Padding=7}; } private void SaveButton_Clicked(object sender, EventArgs e) { int.TryParse(ageEntry.Text, out var age); Users.Add(new User { Name = nameEntry.Text, Age = age }); nameEntry.Text = ageEntry.Text = ""; } }
На странице определена форма для добавления в список Users. В данном случае типом коллекции Users является стандартный класс List, который поддерживает добавление с помощью методов Add()
. По нажатию кнопки срабатывает обработчик SaveButton_Clicked
, в котором берем из текстовых полей введенные значения,
на их основе создаем объект User и добавляем его в список. Мы ожидаем, что после добавления нового пользователя в список Users также обновится и ListView.
Однако после добавления ListView не будет отображать добавленные объекты.
Чтобы решить эту проблемы в качестве типа коллекции, как правило, используется не класс List, а класс ObservableCollection из
пространства имен System.Collections.ObjectModel
. За счет реализации интерфейса INotifyCollectionChanged
при добавлении или удалении
объектов в ObservableCollection автоматически будут изменяться все привязанные к этой коллекции объекты, в том числе и ListView.
Итак, изменим тип коллекции Users:
using System.Collections.ObjectModel; namespace HelloApp; class StartPage : ContentPage { public ObservableCollection<User> Users { get; set; } Entry nameEntry, ageEntry; public StartPage() { // определяем данные Users = new ObservableCollection<User> { new User {Name="Tom", Age=38 }, new User {Name = "Bob", Age = 42} }; ListView listView = new ListView(); // определяем источник данных listView.ItemsSource = Users; // определяем шаблон данных listView.ItemTemplate = new DataTemplate(() => { // привязка к свойству Name Label nameLabel = new Label { FontSize = 16 }; nameLabel.SetBinding(Label.TextProperty, "Name"); // привязка к свойству Age Label ageLabel = new Label { FontSize = 14 }; ageLabel.SetBinding(Label.TextProperty, "Age"); // создаем объект ViewCell. return new ViewCell { View = new StackLayout { Padding = new Thickness(0, 5), Orientation = StackOrientation.Vertical, Children = { nameLabel, ageLabel } } }; }); // поля для добавления нового объекта User nameEntry = new Entry { Placeholder = "Enter name", Margin=5 }; ageEntry = new Entry { Placeholder = "Enter age", Margin=5 }; Button saveButton = new Button { Text = "Save", WidthRequest=100, Margin=5, HorizontalOptions = LayoutOptions.Start }; saveButton.Clicked += SaveButton_Clicked; StackLayout form = new StackLayout { Orientation = StackOrientation.Vertical, Children = { nameEntry, ageEntry, saveButton } }; Content = new StackLayout { Children = { form, listView }, Padding=7}; } private void SaveButton_Clicked(object sender, EventArgs e) { int.TryParse(ageEntry.Text, out var age); Users.Add(new User { Name = nameEntry.Text, Age = age }); nameEntry.Text = ageEntry.Text = ""; } }
Теперь все будет нормально добавляться
Аналогичный пример в xaml. В коде страницы MainPage.xaml:
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="HelloApp.MainPage"> <StackLayout Padding="7"> <StackLayout Orientation="Vertical"> <Entry x:Name="nameEntry" Margin="5" Placeholder = "Enter name" /> <Entry x:Name="ageEntry" Margin="5" Placeholder = "Enter age" /> <Button Clicked="SaveButton_Clicked" Text="Save" WidthRequest="100" HorizontalOptions="Start" /> </StackLayout> <ListView ItemsSource="{Binding Users}"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <ViewCell.View> <StackLayout> <Label Text="{Binding Name}" FontAttributes="Bold" /> <Label Text="{Binding Age}" /> </StackLayout> </ViewCell.View> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackLayout> </ContentPage>
В файл кода MainPage.xaml.cs добавим к странице обработчики кнопок и привязку к списку :
using System.Collections.ObjectModel; namespace HelloApp; public partial class MainPage : ContentPage { public ObservableCollection<User> Users { get; set; } public MainPage() { InitializeComponent(); Users = new ObservableCollection<User> //Users = new List<User> { new User {Name="Tom", Age=38 }, new User {Name = "Bob", Age = 42} }; BindingContext = this; // привязка к текущему объекту } private void SaveButton_Clicked(object sender, EventArgs e) { int.TryParse(ageEntry.Text, out var age); Users.Add(new User { Name = nameEntry.Text, Age = age }); nameEntry.Text = ageEntry.Text = ""; } }