【发布时间】:2020-09-30 02:55:44
【问题描述】:
Xamarin forms Using MVVM..Used burger example to have left hand side menu.
//MainPage
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainPage : MasterDetailPage
{
int idOfNewPage;
Dictionary<int, NavigationPage> MenuPages = new Dictionary<int, NavigationPage>();
public MainPage()
{
InitializeComponent();
MasterBehavior = MasterBehavior.Popover;
MenuPages.Add((int)MenuItemType.Products, (NavigationPage)Detail);
}
public async Task NavigateFromMenu(int id)
{
if (!MenuPages.ContainsKey(id))
{
switch (id)
{
case (int)MenuItemType.Products:
MenuPages.Add(id, new NavigationPage(new ProductPage()));
break;
case (int)MenuItemType.Shopping:
MenuPages.Add(id, new NavigationPage(new ShoppingPage()));
break;
case (int)MenuItemType.Browse:
MenuPages.Add(id, new NavigationPage(new ItemsPage()));
break;
case (int)MenuItemType.About:
MenuPages.Add(id, new NavigationPage(new AboutPage()));
break;
}
idOfNewPage = id;
}
idOfNewPage = id;
var newPage = MenuPages[id];
if (newPage != null)
{
Detail = newPage;
if (Device.RuntimePlatform == Device.Android)
await Task.Delay(100);
IsPresented = false;
}
}
}
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MenuPage : ContentPage
{
MainPage RootPage { get => Application.Current.MainPage as MainPage; }
List<HomeMenuItem> menuItems;
public MenuPage()
{
InitializeComponent();
menuItems = new List<HomeMenuItem>
{
new HomeMenuItem {Id = MenuItemType.Products, Title="Products", Icon = "back_nav.png", Name = "test" },
new HomeMenuItem {Id = MenuItemType.ShoppingCart, Title="Shopping Cart", Icon = "back_nav.png"},
new HomeMenuItem {Id = MenuItemType.Browse, Title="Browse", Icon = "back_nav.png"},
new HomeMenuItem {Id = MenuItemType.About, Title="About", Icon = "back_nav.png"}
};
ListViewMenu.ItemsSource = menuItems;
ListViewMenu.ItemSelected += async (sender, e) =>
{
if (e.SelectedItem == null)
return;
var id = (int)((HomeMenuItem)e.SelectedItem).Id;
var MenuBtnClicked = (string)((HomeMenuItem)e.SelectedItem).Title;
await RootPage.NavigateFromMenu(id);
ListViewMenu.SelectedItem = null;
};
}
}
所以这一切都很好,我可以使用左侧的菜单从页面跳回和第四个。 然而,问题在于shoppingPage。
产品页面上显示产品的列表视图。(下)如果用户更改产品的数量,则调用 WineQuantityChanged()。更新屏幕上的数量 并调用 - UpdateShoppingCartItems()。它将产品添加到 DrinksToPurchaseList 中。 现在,当用户单击购物车图标(作为工具栏项添加,而不是从菜单中添加)时,代码调用 ShoppingClicked() 使用 DrinksToPurchase 列表填充 App.globalShoppingCartOC 并加载购物车页面。
//ProductPage.cs
public ProductPage()
{
PopulateQuantityPicker();
InitializeComponent();
productPage_ViewModal = new ProductPageViewModel();
NoItemsInShoppingCart.Text = App.NoOfItemsInShoppingCartGlobalVar;
BindingContext = productPage_ViewModal;
}
private async void ShoppingClicked(object sender, EventArgs e)
{
//global list storing up to date products and quantites
App.globalShoppingCartOC = DrinksToPurchase;
await RootPage.NavigateFromMenu(1);
}
void WineQuantityChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
int newQuantity = picker.SelectedIndex;
string winePickerId = picker.Id.ToString();
int oldQuantity = -1;
int tempDiffOfValues = 0;
var product = (ProductModel)picker.BindingContext;
//code to update quantity
//update shopping cart items
UpdateShoppingCartItems(product, newQuantity);
NoItemsInShoppingCart.Text = quantityOfProducts.ToString();
App.NoOfItemsInShoppingCartGlobalVar = quantityOfProducts.ToString();
}
}
//update item in shopping cart with new quantity
void UpdateShoppingCartItems(ProductModel product, int quantity)
{
if (!DrinksToPurchaseList.Contains(product))
{
product.Quantity = quantity;
DrinksToPurchaseList.Add(product);
}
else
{
ProductModel result = DrinksToPurchaseList.Where(x => x.ProductId == product.ProductId).FirstOrDefault();
if (result != null)
{
//remove from list
if (quantity < 1)
{
DrinksToPurchaseList.Remove(result);
}
else // else update new quantity
{
result.Quantity = quantity;
}
}
}
}
//ProductPage.xaml
<ToolbarItem x:Name="NumberOfItemsInShoppingCart" Priority="0" Order="Primary" Activated="ShoppingClicked"/>
<StackLayout Grid.Row="2">
<Button Text="Wine" Clicked="WineClicked" WidthRequest="100" HorizontalOptions="Start"/>
<ListView ItemsSource="{Binding WineList}" x:Name="WineListView" IsVisible="False" HasUnevenRows="True" SeparatorVisibility="None" VerticalOptions="FillAndExpand" VerticalScrollBarVisibility="Always" HeightRequest="1500">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid x:Name="Wine" RowSpacing="25">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Grid.Row="0" Text="{Binding ProductId}" VerticalOptions="End" IsVisible="False"/>
<controls:CircleImage Grid.Column="1" Grid.Row="0" HeightRequest="60" HorizontalOptions="CenterAndExpand" VerticalOptions="Center" Aspect="AspectFill" WidthRequest="66" Grid.RowSpan="2" Source="{Binding Image}"/>
<Label Grid.Column="2" Grid.Row="0" Text="{Binding ProductName}" VerticalOptions="Start"/>
<Label Grid.Column="2" Grid.Row="0" Text="{Binding Description}" VerticalOptions="End"/>
<Label Grid.Column="3" Grid.Row="0" VerticalOptions="Start" Text="{Binding Price, StringFormat='£{0:0.00}'}"/>
<Picker Grid.Column="4" Grid.Row="0" SelectedIndexChanged="WineQuantityChanged" SelectedIndex="{Binding Quantity}">
<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>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
从购物车页面,用户还可以更改商品的数量,调用 QuantityChanged()-> 调用 UpdateShoppingCartItems() 并使用 ShoppingCartViewModel.ShoppingCartList(保存新数量)重新填充 App.globalShoppingCartOC 例如,他们更改数量,然后返回产品页面(从左侧菜单)。
(应该在 ProductPage 上调用 OnAppearing())并重新加载 VM?
public ShoppingCartPage ()
{
InitializeComponent();
if (App.globalShoppingCartOC != null)
{
foreach (ProductModel Model in App.globalShoppingCartOC)
{
if (Model.Quantity > 0)
{
//populate LV with global shopping OC
Model.SubTotalForItem = Model.Quantity * Model.Price;
ShoppingCartViewModel.ShoppingCartList.Add(Model);//ShoppingCartList is the ListView on xaml
TotalForAllItems += Model.SubTotalForItem;
}
}
}
this.BindingContext = this;
BindingContext = ShoppingCartViewModel;
}
void QuantityChanged(object sender, EventArgs e)
{
//updates correct quantity on screen and calls
//UpdateShoppingCartItems()
}
//update item in shopping cart with new quantity
void UpdateShoppingCartItems(ProductModel product, int quantity)
{
ProductModel result = ShoppingCartViewModel.ShoppingCartList.ToList().Find(x => x.ProductId == product.ProductId);
if (result != null)
{
//remove from list
if (quantity < 1)
{
ShoppingCartViewModel.ShoppingCartList.Remove(result);
}
else // else update new quantity
{
result.Quantity = quantity;
}
}
App.globalShoppingCartOC = ShoppingCartViewModel.ShoppingCartList;
}
//xaml
<StackLayout Grid.Row="0">
<ListView ItemsSource="{Binding ShoppingCartList}" HasUnevenRows="True" SeparatorVisibility="None">
<ListView.Header>
<Button Text="Place Order" Clicked="OrderPlaced_BtnClicked"/>
</ListView.Header>
<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"/>
<controls:CircleImage Grid.Column="1" Grid.Row="1" HeightRequest="60" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand" Aspect="AspectFill" WidthRequest="66" Grid.RowSpan="2" Source="{Binding Image}"/>
<Label Grid.Column="2" Grid.Row="1" Text="{Binding ProductName}" VerticalOptions="End"/>
<Label Grid.Column="2" Grid.Row="2" VerticalOptions="Start" Text="{Binding Description}"/>
<Label Grid.Column="3" Grid.Row="2" VerticalOptions="Start" Text="{Binding Price, StringFormat='£{0:0.00}'}"/>
<Picker Grid.Column="4" Grid.Row="2" VerticalOptions="Start" SelectedIndexChanged="QuantityChanged" SelectedIndex="{Binding Quantity}">
<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>
</ViewCell>
现在,我需要从 productPage_ViewModal.WineList 重新加载“WineList”中的所有产品并遍历 App.globalShoppingCartOC,更新任何新数量。
问题是我可以单步执行并且 OnAppearing 会这样做,但是当页面重新加载时,它会显示原始数量,从用户第一次从产品页面移动到购物车页面。 (所以存储在drinksToOrder 中的数量)
修改
更新代码以在 ProductPage 中包含 OnAppearing
protected override void OnAppearing()
{
base.OnAppearing();
if (App.globalShoppingCartOC != null)
{
if (App.globalShoppingCartOC.Count > 0)
{
foreach(var item in App.globalShoppingCartOC)
{
if(item.Genre == "Wine")
{
productPage_ViewModal.WineList.Where(x => x.ProductId == item.ProductId).FirstOrDefault().Quantity = item.Quantity;
}
}
WineListView.ItemsSource = productPage_ViewModal.WineList;
this.BindingContext = this.productPage_ViewModal;
}
}
}
因此,我可以看到我已经在 productPage_ViewModal.WineList 和 WineListView.ItemsSource 中更新了正确数量的项目
然后又累到bindingContext了……但是从购物车页面返回后页面仍然加载原始的DrinksToPurchaseList
这是为什么?为什么我不能刷新大众来更新?
【问题讨论】:
-
如果实际问题出在 ProductsPage 上,显示该页面的代码会很有帮助。一般来说,我建议每次访问页面时使用 OnAppearing 刷新数据。或者,您可以在页面之间使用公共 VM
-
杰森感谢您的回复。我已经包含 ProductsPage 的代码,现在我已经添加了 OnAppearing,它在从购物车返回到产品页面时被调用。我可以看到 Listview 的 VM 和 itemSource 已更新,但它仍然在屏幕上显示旧的 obseravableCollection - DrinksToOrder ....请参阅 Q 的更新以包含此谢谢...任何建议?
-
“仍然显示旧的 obseravableCollection”和“仍然加载原始的 DrinksToPurchaseList” - 根据您发布的代码,我不知道其中任何一个是什么。
-
对不起 - 我现在也发布了 ShoppingCart 代码......并添加了更好的解释
-
这真的没有回答我的任何一个问题。如果您能够在某处发布您的解决方案,我可以快速查看一下
标签: c# xaml xamarin xamarin.forms