xamarin 表单 - 选择器在页面加载时不显示任何值

xamarin forms - picker not displaying any value on page load

将 MVVM 与 xamarin 表单结合使用。 ProductPage 包含产品的 ListView。每个产品都有一个选择器。 用户 select 想要购买的商品的数量。用户点击购物车图像。 ShoppingCartPage 加载显示用户已 select 编辑的项目,但选择器为空白。我希望选择器显示从 productaPage 中选择的数量 我已经逐步完成了后面的代码和

Model.ListQuantites = List_Quantites;
Model.SelectedQuantity = Model.ListQuantites.SingleOrDefault(p => p.Key == tempQuantity.Key && p.Value == tempQuantity.Value)

在 ShoppingCartPage 的 OnAppearing() 上存储了正确的数量值,但我不明白为什么选择器没有显示正确的值。

已尝试以下所有建议:

https://forums.xamarin.com/discussion/153788/set-a-picker-selecteditem-on-page-startup

Item to Display for Picker don't show up on load

但仍然无法正常工作有人知道我做错了什么吗?

感谢任何建议

 public class ProductModel : INotifyPropertyChanged
    {
       
        //Event
        public event PropertyChangedEventHandler PropertyChanged;

        //Fields
        //[PrimaryKey, AutoIncrement]
        private int _ProductId;
        private string _ProductName;
        private string _Quantity;
        private string _Description;
        private string _Image;
        private decimal _Price;
        private decimal _SubTotalForItem;
        private string _Genre;
        public ObservableCollection<Quantity> _ListQuantites;

        //Constructor
        public ProductModel()
        {
            //Subscription
            this.PropertyChanged += OnPropertyChanged;
        }

        [PrimaryKey, AutoIncrement]
        public int ProductId
        {
            get { return _ProductId; }
            set
            {
                if (_ProductId == value) return;
                _ProductId = value;
                OnPropertyChanged();
            }
        }
     

        //Properties
        public string Quantity
        {
            get
            {
                return _Quantity;
            }
            set
            {
                _Quantity = value;
                OnPropertyChanged();
            }
        }

        public ObservableCollection<Quantity> ListQuantites
        {
            get
            {
                return _ListQuantites;
            }
            set
            {
                _ListQuantites = value;
                OnPropertyChanged();
            }
        }

        private Quantity _selectedQuantity;
        public Quantity SelectedQuantity
        {
            get
            {
                return _selectedQuantity;
            }
            set
            {
                if (value == null)
                {
                    _selectedQuantity = _selectedQuantity;
                }
                else
                {
                    _selectedQuantity = value;
                    OnPropertyChanged();
                }
            }
        }

        [MaxLength(50)]
        public string Description
        {
            get
            {
                return _Description;
            }
            set
            {
                _Description = value;
                OnPropertyChanged();
            }
        }

        public string Image
        {
            get
            {
                return _Image;
            }
            set
            {
                _Image = value;
                OnPropertyChanged();
            }
        }

        public decimal Price
        {
            get
            {
                return _Price;
            }
            set
            {
                _Price = value;
                OnPropertyChanged();
            }
        }

        public decimal SubTotalForItem
        {
            get
            {
                return _SubTotalForItem;
            }
            set
            {
                _SubTotalForItem = value;
                OnPropertyChanged();
            }
        }

        public string Genre
        {
            get
            {
                return _Genre;
            }
            set
            {
                _Genre = value;
                OnPropertyChanged();
            }
        }


        public string ProductName
        {
            get { return _ProductName; }
            set
            {
                _ProductName = value;
                OnPropertyChanged();
            }
        }

        
        //OnPropertyChanged
        private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(SelectedQuantity))
            {
                //test quantity amount
            }
        }

        // [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

    }


----------------
 public class Quantity
    {
        public int Key { get; set; }
        public string Value { get; set; }
    }
----------------
 public class PickerService
    {
        public static ObservableCollection<Quantity> GetQuantitiesForProductPage()
        {
            var quantities = new ObservableCollection<Quantity>()
            {
                new Quantity() {Key=1, Value="0"},
                new Quantity() {Key=2, Value="1"},
                new Quantity() {Key=3, Value="2"},
                new Quantity() {Key=4, Value="3"},
                new Quantity() {Key=5, Value="4"},
                new Quantity() {Key=6, Value="5"},
                new Quantity() {Key=7, Value="6"},
                new Quantity() {Key=8, Value="7"},
                new Quantity() {Key=9, Value="8"},
                new Quantity() {Key=10, Value="9"},
                new Quantity() {Key=11, Value="10"}
            };
            return quantities;
        }

        public static ObservableCollection<Quantity> GetQuantitiesForShoppingcart()
        {
            var quantities = new ObservableCollection<Quantity>()
            {
                new Quantity() {Key=1, Value="1"},
                new Quantity() {Key=2, Value="2"},
                new Quantity() {Key=3, Value="3"},
                new Quantity() {Key=4, Value="4"},
                new Quantity() {Key=5, Value="5"},
                new Quantity() {Key=6, Value="6"},
                new Quantity() {Key=7, Value="7"},
                new Quantity() {Key=8, Value="8"},
                new Quantity() {Key=9, Value="9"},
                new Quantity() {Key=10, Value="10"},
            };
            return quantities;
        }
    }
--------------
 public class ShoppingCartViewModel //: INotifyPropertyChanged
    {
        private ObservableCollection<ProductModel> _shoppingCartList;
        public ObservableCollection<ProductModel> ShoppingCartList
        {
            get
            {
                return _shoppingCartList;
            }
            set
            {
                if (_shoppingCartList == value) return;
                _shoppingCartList = value;
            }
        }

        public ShoppingCartViewModel()
        {
            ShoppingCartList = new ObservableCollection<ProductModel>();
        }

    }
----------------
 [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class ShoppingCartPage : ContentPage
    {
        ShoppingCartViewModel ShoppingCartViewModel = new ShoppingCartViewModel();
        public decimal TotalForAllItems;
        public ObservableCollection<Quantity> List_Quantites { get; set; }

        public ShoppingCartPage()
        {
            InitializeComponent();
            BindingContext = ShoppingCartViewModel;
        }

        public int CalculateQuantityOfItemsInShoppingCart()
        {
            int quantityOfProducts = 0;

            if (ShoppingCartViewModel.ShoppingCartList != null)
            {
                foreach (var product in ShoppingCartViewModel.ShoppingCartList)
                {
                    if (product.SelectedQuantity != null)
                    {
                        quantityOfProducts += Convert.ToInt32(product.SelectedQuantity.Value);
                    }
                }
            }

            return quantityOfProducts;
        }

        protected override void OnDisappearing()
        {
            App.globalShoppingCartOC = ShoppingCartViewModel.ShoppingCartList;
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();

            TotalForAllItems = 0.00M;

            List_Quantites = PickerService.GetQuantitiesForShoppingcart();

            ShoppingCartViewModel.ShoppingCartList.Clear();

            if (App.globalShoppingCartOC != null)
            {
                foreach (ProductModel Model in App.globalShoppingCartOC)
                {
                    if (Model.SelectedQuantity != null)
                    {
                        var _quantity = Convert.ToDecimal(Model.SelectedQuantity.Value);
                        if (_quantity > 0)
                        {
                            Model.SubTotalForItem = _quantity * Model.Price;
                            //this line resets Model.SelectedQuantity to 0, so need to re-populate with tempQuantity value
                            Quantity tempQuantity = Model.SelectedQuantity;
                            Model.ListQuantites = List_Quantites;
                            Model.SelectedQuantity = Model.ListQuantites.SingleOrDefault(p => p.Key == tempQuantity.Key && p.Value == tempQuantity.Value);
                            ShoppingCartViewModel.ShoppingCartList.Add(Model);
                            TotalForAllItems += Model.SubTotalForItem;
                        }
                    }
                }

                SubTotalForAllItems.Text = TotalForAllItems.ToString();
            }

            NoItemsInShoppingCart.Text = CalculateQuantityOfItemsInShoppingCart().ToString();
        }

        protected async void SI_Invoked(object sender, EventArgs e)
        {
            var si = sender as SwipeItem;
            var productToRemove = si.CommandParameter as ProductModel;

            var action = await DisplayAlert("Are you sure you want to remove ", productToRemove.ProductName + ".", "Yes", "No");

            if (action)
            {
                ShoppingCartViewModel.ShoppingCartList.Remove(productToRemove);

                Quantity tempQuantity = productToRemove.SelectedQuantity;
                decimal tempQuantityValue = Convert.ToDecimal(tempQuantity.Value);
                decimal subtotalToRemove = productToRemove.Price * tempQuantityValue;
                TotalForAllItems -= subtotalToRemove;
                SubTotalForAllItems.Text = TotalForAllItems.ToString();

                NoItemsInShoppingCart.Text = CalculateQuantityOfItemsInShoppingCart().ToString();
            }
        }

        public void SCQuantityAndSubtotalUpdated(object sender, EventArgs e)
        {
            TotalForAllItems = 0.00M;

            if (ShoppingCartViewModel.ShoppingCartList != null)
            {
                foreach (ProductModel Model in ShoppingCartViewModel.ShoppingCartList)
                {
                    var _quantity = Convert.ToDecimal(Model.SelectedQuantity.Value);
                    if (_quantity > 0)
                    {
                        Model.SubTotalForItem = _quantity * Model.Price;
                        TotalForAllItems += Model.SubTotalForItem;
                    }
                }

                SubTotalForAllItems.Text = TotalForAllItems.ToString();
            }


            NoItemsInShoppingCart.Text = CalculateQuantityOfItemsInShoppingCart().ToString();
        }

        private void PlaceOrder_BtnClicked(object sender, EventArgs e)
        {

        }
    }
-------------------------
   <ContentPage.ToolbarItems>
        <ToolbarItem Name="shoppingCartImg" Icon="shopping_cart.png" Priority="0" Order="Primary"/>
        <ToolbarItem x:Name="NoItemsInShoppingCart" Priority="0" Order="Primary"/>
    </ContentPage.ToolbarItems>

    <ContentPage.Content>
        <StackLayout>
            <ListView ItemsSource="{Binding ShoppingCartList}"  IsVisible="True" VerticalOptions="FillAndExpand" HasUnevenRows="True">
                <ListView.Header>
                    <Button Text="Place Order" Clicked="PlaceOrder_BtnClicked"/>
                </ListView.Header>
                <ListView.Footer>
                    <Label x:Name="SubTotalForAllItems" HorizontalTextAlignment="End" VerticalTextAlignment="Start" Margin="20,20" FontAttributes="Bold"/>
                </ListView.Footer>
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <ViewCell.View>
                                <SwipeView>
                                    <SwipeView.LeftItems>
                                        <SwipeItems Mode="Reveal">
                                            <SwipeItem Text="Details" IconImageSource="xamarin_logo.png" CommandParameter="{Binding .}" BackgroundColor="LightBlue" Invoked="SI_Invoked">
                                            </SwipeItem>
                                        </SwipeItems>
                                    </SwipeView.LeftItems>
                                    
                                    <!--Content of Swipe View -->
                                    <StackLayout BackgroundColor="Green" HorizontalOptions="StartAndExpand">
                                        
                                    <Grid>
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="Auto"/>
                                        </Grid.RowDefinitions>
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="Auto"/>
                                        </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="1"  Text="{Binding Description}" VerticalOptions="End"/>
                                            <Label Grid.Column="3" Grid.Row="0" VerticalOptions="Start" Text="{Binding SubTotalForItem, StringFormat='£{0:0.00}'}"/>
                                          
                                            <Picker x:Name="scPicker" ItemsSource="{Binding ListQuantites, Mode=TwoWay}" SelectedItem="{Binding SelectedQuantity, Mode=TwoWay}" ItemDisplayBinding="{Binding Value}" SelectedIndexChanged="SCQuantityAndSubtotalUpdated"/>
                                        </Grid>
                                    </StackLayout>
                                </SwipeView>
                            </ViewCell.View>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>


        </StackLayout>
    </ContentPage.Content>

-------------------------
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class ProductPage : ContentPage
    {
        public ProductPageViewModel productPage_ViewModal;
        MainPage RootPage { get => Application.Current.MainPage as MainPage; }

        public ProductPage()
        {
            InitializeComponent();
            productPage_ViewModal = new ProductPageViewModel();
            BindingContext = productPage_ViewModal;
        }

        protected override void OnDisappearing()
        {
            App.globalShoppingCartOC = productPage_ViewModal.WineList;
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();

            if (App.globalShoppingCartOC != null)
            {
                //First need to check shoppingCart list for product, if it has been removed in SC,
                //then set quantity to 0
                foreach (var product in productPage_ViewModal.WineList)
                {
                    var doesProductExistInShoppingCart = App.globalShoppingCartOC.Where(x => x.ProductId == product.ProductId).FirstOrDefault();

                    if(doesProductExistInShoppingCart == null)
                    {
                        if (productPage_ViewModal.WineList.Where(x => x.ProductId == product.ProductId).FirstOrDefault().SelectedQuantity != null)
                        {
                            Quantity tempQuantity = new Quantity() { Key = 1, Value = "0" };
                            product.SelectedQuantity = productPage_ViewModal.List_Quantites.SingleOrDefault(p => p.Key == tempQuantity.Key && p.Value == tempQuantity.Value);
                            product.ListQuantites = PickerService.GetQuantitiesForProductPage();
                            // productPage_ViewModal.WineList.Where(x => x.ProductId == product.ProductId).FirstOrDefault().SelectedQuantity.Value = "0";
                        }
                    }
                }

                //Can then update correct quantity for other products still in SC list
                foreach (var product in App.globalShoppingCartOC)
                {
                    if (productPage_ViewModal.WineList.Where(x => x.ProductId == product.ProductId).FirstOrDefault().SelectedQuantity != null)
                    {
                        Quantity tempQuantity = product.SelectedQuantity;
                        product.SelectedQuantity = productPage_ViewModal.List_Quantites.SingleOrDefault(p => p.Key == tempQuantity.Key && p.Value == tempQuantity.Value);
                        product.ListQuantites = PickerService.GetQuantitiesForProductPage();
                        //productPage_ViewModal.WineList.Where(x => x.ProductId == product.ProductId).FirstOrDefault().SelectedQuantity.Value = product.SelectedQuantity.Value;
                    }
                }
            }

            NoItemsInShoppingCart.Text = CalculateQuantityOfItemsInShoppingCart().ToString();
        }

        private async void ShoppingCartClicked(object sender, EventArgs e)
        {
            MenuPage tempMenu = new MenuPage();
             int IdOfMenuClicked = tempMenu.GetIdForNavigationMenu("Shopping Cart");
            await RootPage.NavigateFromMenu(IdOfMenuClicked);
        }

        public void QuantityChanged(object sender, EventArgs e)
        {
            NoItemsInShoppingCart.Text = CalculateQuantityOfItemsInShoppingCart().ToString();
        }

        public int CalculateQuantityOfItemsInShoppingCart()
        {
            int quantityOfProducts = 0;

            if (productPage_ViewModal.WineList != null)
            {
                foreach (var product in productPage_ViewModal.WineList)
                {
                    if (product.SelectedQuantity != null)
                    {
                        quantityOfProducts += Convert.ToInt32(product.SelectedQuantity.Value);
                    }
                }
            }

            return quantityOfProducts;
        }
    }
-------------------------
            Title="ProductPage">
    <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>

    <ContentPage.Content>
        <StackLayout>

            <ListView IsVisible="True" VerticalOptions="FillAndExpand" HasUnevenRows="True" ItemsSource="{Binding WineList}"> <!--HeightRequest="1500"-->
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <StackLayout BackgroundColor="Green" HorizontalOptions="StartAndExpand">
                                <Grid>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto"/>
                                    </Grid.RowDefinitions>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto"/>
                                    </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="1"  Text="{Binding Description}" VerticalOptions="End"/>
                                    <Label Grid.Column="3" Grid.Row="0" VerticalOptions="Start" Text="{Binding Price, StringFormat='£{0:0.00}'}"/>
                                    <Picker x:Name="productPicker" ItemsSource="{Binding ListQuantites}" ItemDisplayBinding="{Binding Value}" SelectedIndexChanged="QuantityChanged" SelectedItem ="{Binding SelectedQuantity}"/>
                                </Grid>
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
            
        </StackLayout>

    </ContentPage.Content>
    </ContentPage>
----------------------------------------------
 public class ProductPageViewModel : BindableObject, INotifyPropertyChanged
    {
        public ObservableCollection<ProductModel> WineList { get; set; }

        public ObservableCollection<Quantity> List_Quantites { get; set; }

        public ProductPageViewModel()
        {
            List_Quantites = PickerService.GetQuantitiesForProductPage();//.OrderBy(c => c.Value).ToList();

            WineList = new ObservableCollection<ProductModel>();
            WineList.Add(new ProductModel { ProductId = 1, ProductName = "Wine 1", ListQuantites = List_Quantites, Image = "wine.jpg", Quantity = "0", Description = "700ml", Price = 10.00M, SubTotalForItem = 0.00M, Genre = "Wine" });
            WineList.Add(new ProductModel { ProductId = 2, ProductName = "Wine 2", ListQuantites = List_Quantites, Image = "wine.jpg", Quantity = "0", Description = "700ml", Price = 10.00M, SubTotalForItem = 0.00M, Genre = "Wine" });
            WineList.Add(new ProductModel { ProductId = 3, ProductName = "Wine 3", ListQuantites = List_Quantites, Image = "wine.jpg", Quantity = "0", Description = "700ml", Price = 5.50M, SubTotalForItem = 0.00M, Genre = "Wine" });
            WineList.Add(new ProductModel { ProductId = 4, ProductName = "Wine 4", ListQuantites = List_Quantites, Image = "wine.jpg", Quantity = "0", Description = "700ml", Price = 5.50M, SubTotalForItem = 0.00M, Genre = "Wine" });
        }

更新

在 ProductPage 上,如果用户更改产品的数量,它会在 productPage_ViewModal.WineList、

中自动更新

当用户单击购物车图标时,将在 ProductPage 上调用 OnDisappearing(),将 productPage_ViewModal.WineList 添加到 global ObservableCollection<ProductModel> globalShoppingCartOC,(存储在App.xaml.cs页面)

从 ShoppingCartPage.xaml.cs 中的 OnAppearing() 开始,ShoppingCartViewModel.ShoppingCartList 通过遍历 globalShoppingCartOC 进行填充,

如果数量大于 0,则添加到 ShoppingCartViewModel.ShoppingCartList,并在 select 前选择器中选择的数量:

Quantity tempQuantity = Model.SelectedQuantity;
Model.ListQuantites = List_Quantites;
Model.SelectedQuantity = Model.ListQuantites.SingleOrDefault(p => p.Key == tempQuantity.Key && p.Value == tempQuantity.Value);

问题是我可以通过单步执行代码看到 'Model.SelectedQuantity' 将存储正确的值,但它不会在带有选择器的 ShoppingCart 屏幕上更新

<Picker x:Name="scPicker" Title="--Select--" ItemsSource="{Binding ListQuantites, Mode=TwoWay}" SelectedItem="{Binding SelectedQuantity, Mode=TwoWay}" ItemDisplayBinding="{Binding Value}" SelectedIndexChanged="SCQuantityAndSubtotalUpdated"/>

根据你的代码,我发现 PickerService.GetQuantitiesForProductPage() PickerService.GetQuantitiesForShoppingcart() 会得到不同的列表,

ProductPage Picker 项目来源:

public static ObservableCollection<Quantity> GetQuantitiesForProductPage()
    {
        var quantities = new ObservableCollection<Quantity>()
        {
            new Quantity() {Key=1, Value="0"},
            new Quantity() {Key=2, Value="1"},
            new Quantity() {Key=3, Value="2"},
            new Quantity() {Key=4, Value="3"},
            new Quantity() {Key=5, Value="4"},
            new Quantity() {Key=6, Value="5"},
            new Quantity() {Key=7, Value="6"},
            new Quantity() {Key=8, Value="7"},
            new Quantity() {Key=9, Value="8"},
            new Quantity() {Key=10, Value="9"},
            new Quantity() {Key=11, Value="10"}
        };
        return quantities;
    }

ShoppingCartPage Picker 项目来源:

public static ObservableCollection<Quantity> GetQuantitiesForShoppingcart()
    {
        var quantities = new ObservableCollection<Quantity>()
        {
            new Quantity() {Key=1, Value="1"},
            new Quantity() {Key=2, Value="2"},
            new Quantity() {Key=3, Value="3"},
            new Quantity() {Key=4, Value="4"},
            new Quantity() {Key=5, Value="5"},
            new Quantity() {Key=6, Value="6"},
            new Quantity() {Key=7, Value="7"},
            new Quantity() {Key=8, Value="8"},
            new Quantity() {Key=9, Value="9"},
            new Quantity() {Key=10, Value="10"},
        };
        return quantities;
    }

所以从 ProductPage 中选择的 SelectedQuantity,在 ShoppingCartPage Picker itemsource 中找不到。 ShoppingCartPage 中的 Picker 不会显示数据。