У меня есть товарная корзина. Я хотел бы показать CartItems в виде списка с ItemName и количеством. Когда я нажимаю кнопку, количество элементов в listView должно увеличиваться.
Моя проблема: CartItem наблюдаемой коллекции увеличивается каждый раз, когда я правильно нажимаю кнопку, но пользовательский интерфейс не обновляется/не обновляется. Есть кто-нибудь, кто может мне помочь??
Вот код:
public class AboutViewModel : BaseViewModel
{
public AboutViewModel()
{
AddCartItem = new Command(AddItem);
cartItems = new ObservableCollection<CartItem>();
cartItems.Add(new CartItem { ItemName = "Item1", Quantity = 4 });
cartItems.Add(new CartItem { ItemName = "Item2", Quantity = 2 });
}
public ICommand AddCartItem { get; }
public ObservableCollection<CartItem> cartItems;
public ObservableCollection<CartItem> CartItems
{
get { return cartItems; }
set
{
cartItems = value;
OnPropertyChanged("CartItems");
}
}
void AddItem()
{
cartItems[0].Quantity++;
CartItems = cartItems;
}
}
<StackLayout>
<ListView ItemsSource = "{Binding CartItems">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text = "{Binding ItemName, Mode=TwoWay}"
Detail = "{Binding Quantity, Mode=TwoWay}"></TextCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackLayout>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height = "*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width = "*"/>
</Grid.ColumnDefinitions>
<BoxView
Color = "Blue" />
<Button Text = "Add Name" Command = "{Binding AddCartItem}"/>
Вы обновляете значение первой записи в cartItems
вспомогательном поле типа ObservableCollection
(которое в идеале должно быть private
BTW), а затем вы по какой-то причине обновляете ссылку общедоступного CartItems
свойства, что не обязательно. В этом случае ваш пользовательский интерфейс будет обновляться только в том случае, если какой-либо из элементов внутри коллекции действительно вызывает событие PropertyChanged
. Можете ли вы показать, где и как определяется класс CartItem
?
Вместо этого используйте CollectionView, он имеет лучшую производительность и восприимчив к изменениям.
Если вы хотите обновить пользовательский интерфейс после изменения значения свойства Quantity
в модели CartItem
, вам необходимо реализовать интерфейс INotifyPropertyChanged
для CartItem
.
Основываясь на вашем коде, я выполнил эту функцию, вы можете обратиться к следующему коду:
CartItem.cs
public class CartItem: INotifyPropertyChanged
{
public string ItemName { get; set; }
//public int Quantity { get; set; }
int _quantity;
public int Quantity
{
get => _quantity;
set => SetProperty(ref _quantity, value);
}
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Овиевмодел.cs
public class AboutViewModel
{
public AboutViewModel()
{
AddCartItem = new Command(AddItem);
CartItems = new ObservableCollection<CartItem>();
CartItems.Add(new CartItem { ItemName = "Item1", Quantity = 4 });
CartItems.Add(new CartItem { ItemName = "Item2", Quantity = 2 });
}
public ICommand AddCartItem { get; }
public ObservableCollection<CartItem> CartItems { get; set; }
void AddItem()
{
CartItems[0].Quantity++;
}
}
MainPage.xaml
<?xml version = "1.0" encoding = "utf-8" ?>
<ContentPage xmlns = "http://xamarin.com/schemas/2014/forms"
xmlns:x = "http://schemas.microsoft.com/winfx/2009/xaml" xmlns:listviewapp = "clr-namespace:ListViewApp"
x:Class = "ListViewApp.MainPage">
<ContentPage.BindingContext>
<listviewapp:AboutViewModel></listviewapp:AboutViewModel>
</ContentPage.BindingContext>
<StackLayout>
<ListView ItemsSource = "{Binding CartItems}">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text = "{Binding ItemName, Mode=TwoWay}"
Detail = "{Binding Quantity, Mode=TwoWay}"></TextCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Text = "Add Name" Command = "{Binding AddCartItem}"/>
</StackLayout>
</ContentPage>
Примечание:
1. На самом деле вам вообще не нужно определять другую переменную cartItems
.
Вы можете определить только переменную CartItems
:
public ObservableCollection<CartItem> CartItems { get; set; }
2. Для документа Класс ObservableCollection мы знаем, что этот класс:
Представляет коллекцию динамических данных, которая предоставляет уведомления, когда элементы добавляются или удаляются, или когда весь список обновляется.
Таким образом, если вы добавите модификаторы public ObservableCollection<CartItem>
для переменной CartItems
, при добавлении или удалении одного или нескольких элементов в этот список пользовательский интерфейс будет обновляться. И если вы хотите, чтобы пользовательский интерфейс обновлялся автоматически после изменения значения свойства Quantity
в модели CartItem
, вам необходимо реализовать интерфейс INotifyPropertyChanged
для CartItem
.
public ObservableCollection<CartItem> CartItems { get; set; }
AddItem
должен добавить новый элемент в список или увеличить количество существующего элемента? Если предполагается увеличить количество, как узнать, какой элемент увеличить?