问题
My products page only shows 'Product Name' and 'Quantity', quantity isdisplayed/ binded to the picker.
For test purposes to get this working there is only 2 products loading from the VM. Wine 1 and wine 2.
When the application loads, why is the picker empty with no value selected. When quantity for each item is set to 1, when loading from the VM
Quantity is set to 1, the picker is just not updating when it initially loads, I know this because if I click on the empty picker and select 1. nothing happens because the code hits
if (quantity != value)
// where quantity 1 being selected is already 1 in code behind, so wont call propertyChanged from setter in quantity,
also... if I select the picker and choose another number, say 4 for example. the setter in quantity is hit and OnPropertyChanged is hit, and 4 is displayed on the picker. (I even tested changing the productName if 3 was picked) and this worked.
I know this all works as I have stepped through the code. However another issue that is now happening is that for some reason the code is hitting the quantity get/set AGAIN and setting the value to 0, after everytime it is clicked.
So for example if 4 is clicked, the picker will be updated to 4 on screen, then if I follow it through stepping in the code, the setter in quantity is called again, setting the value to 0, and thus selecting nothing in the picker. Leaving it blank, as it is when it initially loads.
any help to help resolve this would be appreciated thank Y
thank Y for any help received
public class ProductModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int quantity;
private string productName;
public ProductModel()
{ }
[PrimaryKey, AutoIncrement]
public int ProductId { get; set; }
[MaxLength(50)]
public string ProductName
{
get
{
return productName;
}
set
{
productName = value;
OnPropertyChanged();
}
}
public int Quantity
{
get
{
return quantity;
}
set
{
if (quantity != value)
{
quantity = value;
OnPropertyChanged();
//test to check if binding works, successfully changed ProductName to "test" if 3 is picked from picker
if (quantity == 3)
ProductName = "test;";
}
}
}
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(name));
}
}
public class ProductPageViewModel : BindableObject
{
public ObservableCollection<ProductModel> WineList { get; set; }
public ProductPageViewModel ()
{
WineList = new ObservableCollection<ProductModel>();
WineList.Add(new ProductModel { ProductId = 1, ProductName = "Wine 1", Quantity = 1});
WineList.Add(new ProductModel { ProductId = 2, ProductName = "Wine 2", Quantity = 1});
}
<?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.ProductPage">
<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="1" Grid.Row="0" SelectedItem="{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>
namespace ScrollApp2.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ProductPage : ContentPage
{
public ProductPage()
{
InitializeComponent();
BindingContext = new ProductPageViewModel();
}
}
}
回答1:
Your ProductModel
class does not inherit from INotifyPropertyChanged
interface, you’ll need to add the interface to your class and implement it, also making sure to raise the INotifyPropertyChanged.PropertyChanged
event in Quantity
setter.
You might want to create a ProductViewModel
at this point, as I’m not sure you want to add INotifyPropertyChanged
to a POCO class like ProductModel
.
Please don't edit your question with a different one, open a new question. Your previous question might have helped someone else facing the same problem of UI not being updated when changing a property of a class that does not inherit from IPropertyChanged
. My previous answer is now irrelevant to the new question, and will never benefit anyone else.
For your new question, your Quantity
is of type int
and your picker items are of type string
, changing Quantity
type to string
should help solving your issue, you can also use SelectedIndex
instead of SelectedItem
if the index of the items are matching.
<Picker 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>
回答2:
It looks like you have properly implemented INotifyPropertyChanged
on your ProductModel
, but now you need to subscribe to it in the constructor of the ProductModel
class.
I have stubbed up a simple implementation of what it is that you are looking for (I excluded the rest of your code so that it would be easier to digest)
public class ProductModel : INotifyPropertyChanged {
//Event
public event PropertyChangedEventHandler PropertyChanged;
//Fields
private string _ProductName;
private int _Quantity;
//Properties
public int Quantity {
get { return _Quantity; }
set {
_Quantity = value;
OnPropertyChanged();
}
}
public string ProductName {
get { return _ProductName; }
set {
_ProductName = value;
OnPropertyChanged();
}
}
//Constructor
public ProductModel() {
//Subscription
this.PropertyChanged += OnPropertyChanged;
}
//OnPropertyChanged
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e) {
if (e.PropertyName == nameof(Quantity)) {
//Do anything that needs doing when the Quantity changes here...
}
}
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Let me know if this gets you going
来源:https://stackoverflow.com/questions/64407230/xamarin-forms-two-way-binding-with-a-picker-why-cant-i-update-a-picker-from