#c# #xaml #xamarin #xamarin.forms #picker
#c# #xaml #xamarin #xamarin.forms #средство выбора
Вопрос:
Всем вечера,
Проект Xamarin с использованием MVVM
Имейте ProductModel с идентификатором, именем и количеством.
ProductPage.xaml использует listview для отображения списка продуктов. Средство выбора привязано к количеству, когда количество выбирается из средства выбора, вызывается OnPickerSelectedIndexChanged() и добавляет продукт в ObservableCollection DrinksToPurchaseList . Когда пользователь нажимает на корзину покупок, список покупок DrinksToPurchaseList добавляется в глобальную операционную систему, которая затем повторяется на виртуальной машине корзины покупок и отображается на экране.
Если пользователь хочет изменить количество на странице ShoppingCart, он может использовать средство выбора для выбора нового значения. QuantityChanged() вызывается на странице корзины покупок и соответствующим образом обновляется. Все это работает.
Проблема, с которой я сталкиваюсь, заключается в том, что после того, как все это произойдет, функция OnPickerSelectedIndexChanged() на странице продукта вызывается снова, что не имеет ничего общего с тем, что должно происходить.
Я закомментировал код, пока не нашел проблему.
var item = (ProductModel)picker.BindingContext;
на странице продукта
void OnPickerSelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
var item = (ProductModel)picker.BindingContext;
//Dummy Data used to test
//var _productId = 1;
//var _quantity = "4";
//var _productName = "WINE 110011";
//ProductModel item = new ProductModel(){ ProductId = _productId, ProductName = _productName, Quantity = _quantity};
DrinksToPurchaseList.Add(item);
}
Я удалил эту строку и добавил в DD для тестирования, и все работает так, как должно.
Мне нужно var item = (ProductModel)picker.BindingContext;
получить продукт и добавить его в DrinksToPurchaseList.
Почему это происходит и кто-нибудь знает обходной путь?
TY
public class ProductModel : INotifyPropertyChanged
{
//Event
public event PropertyChangedEventHandler PropertyChanged;
//Fields
private string _ProductName;
private string _Quantity;
//Constructor
public ProductModel()
{
//Subscription
this.PropertyChanged = OnPropertyChanged;
}
[PrimaryKey, AutoIncrement]
public int ProductId { get; set; }
//Properties
public string Quantity
{
get { return _Quantity; }
set
{
_Quantity = value;
OnPropertyChanged();
}
}
public string ProductName
{
get { return _ProductName; }
set
{
_ProductName = value;
OnPropertyChanged();
}
}
//OnPropertyChanged
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(Quantity))
{
//Do anything that needs doing when the Quantity changes here...
//var time = "hello
if (_Quantity == "0")
{
// Quantity = "6";
}
}
}
// [NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ProductPageViewModel : BindableObject
{
public ObservableCollection<ProductModel> WineList { get; set; }
public ObservableCollection<ProductModel> AllDrinksList { get; set; }
public ProductPageViewModel()
{
WineList = new ObservableCollection<ProductModel>();
WineList.Add(new ProductModel
{
ProductId = 1,
ProductName = "Wine 101",
Quantity = "4",
});
AllDrinksList = new ObservableCollection<ProductModel>();
}
}
public partial class ProductPage : ContentPage
{
public ProductPageViewModel productPage_ViewModal;
private bool ZeroQuantitySelected = false;
MainPage RootPage { get => Application.Current.MainPage as MainPage; }
private ObservableCollection<ProductModel> DrinksToPurchaseList = new ObservableCollection<ProductModel>();
private bool isWineListVisible = false;
public ProductPage()
{
InitializeComponent();
productPage_ViewModal = new ProductPageViewModel();
BindingContext = productPage_ViewModal;
}
private async void ShoppingCartClicked(object sender, EventArgs e)
{
App.NewPageToLoad = "Shopping Cart";
MenuPage tempMenu = new MenuPage();
int IdOfMenuClicked = tempMenu.GetIdForNavigationMenu("Shopping Cart");
App.globalShoppingCartOC = DrinksToPurchaseList;
await RootPage.NavigateFromMenu(IdOfMenuClicked);
}
void OnPickerSelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
//BELOW LINE IS THE ISSUE CAUSING THE OTHER POST BACK
//var item = (ProductModel)picker.BindingContext;
//DrinksToPurchaseList.Add(item);
//Dummy Data used to test
var _productId = 1;
var _quantity = "4";
var _productName = "WINE 110011";
ProductModel item = new ProductModel() { ProductId = _productId, ProductName = _productName, Quantity = _quantity };
DrinksToPurchaseList.Add(item);
}
}
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ScrollApp2.Views.ProductPage">
<ContentPage.ToolbarItems>
<ToolbarItem Name="shoppingCartImg" Icon="xamarin_logo.png" Priority="0" Order="Primary" Activated="ShoppingCartClicked"/>
<ToolbarItem x:Name="NoItemsInShoppingCart" Priority="0" Order="Primary" Activated="ShoppingCartClicked"/>
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout>
<ListView x:Name="producttablelist" IsVisible="True" VerticalOptions="FillAndExpand" HasUnevenRows="True" ItemsSource="{Binding WineList}" HeightRequest="1500">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout HeightRequest="120" BackgroundColor="Green" HorizontalOptions="StartAndExpand">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Text="{Binding ProductName}" TextColor="Black" VerticalOptions="Start"></Label>
<Picker Grid.Column="4" Grid.Row="2" VerticalOptions="Start" SelectedIndexChanged="OnPickerSelectedIndexChanged" SelectedIndex="{Binding Quantity, Mode=TwoWay}">
<Picker.Items>
<x:String>0</x:String>
<x:String>1</x:String>
<x:String>2</x:String>
<x:String>3</x:String>
<x:String>4</x:String>
<x:String>5</x:String>
<x:String>6</x:String>
</Picker.Items>
</Picker>
</Grid>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
public class ShoppingCartViewModel
{
public ObservableCollection<ProductModel> ShoppingCartList { get; set; }
public ShoppingCartViewModel()
{
ShoppingCartList = new ObservableCollection<ProductModel>();
}
}
<?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="ScrollApp2.Views.ShoppingCartPage">
<ContentPage.ToolbarItems>
<ToolbarItem Name="shoppingCartImg" Icon="shopping_cart.png" Priority="0" Order="Primary" Activated="ShoppingCartClicked"/>
<ToolbarItem x:Name="NoItemsInShoppingCart" Priority="0" Order="Primary" Activated="ShoppingCartClicked"/>
</ContentPage.ToolbarItems>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="80*"/>
<RowDefinition Height="20*"/>
</Grid.RowDefinitions>
<StackLayout Grid.Row="0">
<ListView ItemsSource="{Binding ShoppingCartList}" HasUnevenRows="True" SeparatorVisibility="None">
<ListView.Footer>
<Label x:Name="TotalForItems" HorizontalTextAlignment="End" VerticalTextAlignment="Start" Margin="20,20" FontAttributes="Bold"/>
</ListView.Footer>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid x:Name="ShoppingCartGrid" RowSpacing="25" ColumnSpacing="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Text="{Binding Id}" VerticalOptions="End" IsVisible="False"/>
<Label Grid.Column="2" Grid.Row="1" Text="{Binding ProductName}" VerticalOptions="End"/>
<Picker Grid.Column="4" Grid.Row="2" VerticalOptions="Start" SelectedIndexChanged="QuantityChanged" SelectedIndex="{Binding Quantity, Mode=TwoWay}">
<Picker.Items>
<x:String>0</x:String>
<x:String>1</x:String>
<x:String>2</x:String>
<x:String>3</x:String>
<x:String>4</x:String>
<x:String>5</x:String>
<x:String>6</x:String>
<x:String>7</x:String>
</Picker.Items>
</Picker>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</Grid>
</ContentPage>
public partial class ShoppingCartPage : ContentPage
{
ShoppingCartViewModel ShoppingCartViewModel = new ShoppingCartViewModel();
private Dictionary<int, int> PickerUniquieIdDict = new Dictionary<int, int>();
public decimal TotalForAllItems;
public ShoppingCartPage ()
{
InitializeComponent();
if (App.globalShoppingCartOC != null)
{
// ProductModel P = new ProductModel();
//P.Add(new ProductModel { ProductId = 5, ProductName = "Gin", Image = "Gin.jpg", Description = "700ml", Price = 13.99M, Quantity = 0, SubTotalForItem = 0.00M, Genre = "Wine" });
//DUMMY DATA
//App.globalShoppingCartOC.Add(new ProductModel { ProductId = 5, ProductName = "Gin", Quantity="3" });
foreach (ProductModel Model in App.globalShoppingCartOC)
{
var _quantity = Convert.ToDecimal(Model.Quantity);
if (_quantity > 0)
{
ShoppingCartViewModel.ShoppingCartList.Add(Model);
}
}
}
if (App.GlobalWinePickerUniquieIdDict != null)
{
PickerUniquieIdDict = App.GlobalWinePickerUniquieIdDict;
}
NoItemsInShoppingCart.Text = App.NoOfItemsInShoppingCartGlobalVar;
this.BindingContext = this;
BindingContext = ShoppingCartViewModel;
}
void QuantityChanged(object sender, EventArgs e)
{
var x = 1;
}
void ShoppingCartClicked(object sender, EventArgs e)
{
var x = 1;
}
}
Проблема в том, что при загрузке страницы продукта пользователь выбирает количество и устанавливает его, например, равным 3.
Пользователь нажимает на изображение корзины покупок, загружается страница корзины покупок, пользователь может выбрать средство выбора на странице корзины покупок, чтобы изменить количество, если они это сделают, код отправит обратно в
void QuantityChanged(object sender, EventArgs e)
{
var x = 1;
}
на странице корзины покупок, а затем на
void OnPickerSelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
//var item = (ProductModel)picker.BindingContext;
//Drink
на странице продукта.
Код не должен отправлять обратно в OnPickerSelectedIndexChanged на странице proudcage со страницы корзины покупок?
ОБНОВИТЕ, если вы видели из моего ProductModel.cs, я использую INPC, и он работает.
public string Quantity
{
get { return _Quantity; }
set
{
_Quantity = value;
OnPropertyChanged();
}
}
попадает при изменении количества в сборщике.
Мой вопрос -> Если мне нужно выполнить дополнительную логику на виртуальной машине после того, как это произойдет, к которой я не знаю, как получить доступ …. (именно по этой причине я пытался использовать OnPickerSelectedIndexChanged()) было бы наилучшим подходом переопределить OnPropertyChanged() из ProductModel и вызвать его изProductPageViewModel?
Комментарии:
1.
picker.BindingContext
есть исходные данные, ноProductModel
есть класс? Можете ли вы предоставить один простой способ воспроизвести вашу проблему здесь? Нам полезно узнать о вашей проблеме?2. Я добавил больше кода в исходный вопрос, пожалуйста, посмотрите
3. Если вы можете загрузить свой образец на github, я скачаю ваш образец для тестирования, это поможет воспроизвести вашу проблему.
4. Ах, вишня, было бы здорово, если бы ты мог быстро взглянуть на TY github.com/mlagan06/ScrollApp2
5. Я загружаю ваш образец и тестирую, я нахожу, что количество ProductModel не правильно реализует INotifyPropertyChanged .