[英]xamarin forms - two way binding with a picker - why cant I update a picker from code behind?
我的产品页面只显示“产品名称”和“数量”,数量显示/绑定到选择器。
出于测试目的以使其正常工作,只有 2 个产品从 VM 加载。 酒 1 和酒 2。
应用程序加载时,为什么选择器为空且未选择任何值。 当每个项目的数量设置为 1 时,从 VM 加载时
数量设置为 1,选择器在最初加载时没有更新,我知道这是因为如果我点击空选择器并选择 1。没有任何反应,因为代码命中
if (quantity != value)
// 选择的数量 1 在后面的代码中已经是 1,所以不会在数量上从 setter 调用 propertyChanged,
也...如果我选择选择器并选择另一个数字,例如说 4。 数量设置器被命中,OnPropertyChanged 被命中,4 显示在选择器上。 (如果选择了 3,我什至测试了更改 productName )并且这有效。
我知道这一切都有效,因为我已经逐步完成了代码。 然而,现在发生的另一个问题是,由于某种原因,代码在每次点击后都会再次点击 get/set 数量并将值设置为 0。
因此,例如,如果单击 4,选择器将在屏幕上更新为 4,然后如果我通过步进代码来跟踪它,再次调用数量中的设置器,将值设置为 0,从而在选择器中不选择任何内容. 将其留空,就像它最初加载时一样。
任何帮助解决此问题的帮助将不胜感激,谢谢
感谢 Y 收到的任何帮助
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();
}
}
}
您的
ProductModel
类不是从
INotifyPropertyChanged
接口继承的,您需要将该接口添加到您的类中并实现它,同时确保在
Quantity
setter 中引发
INotifyPropertyChanged.PropertyChanged
事件。
此时您可能想要创建一个
ProductViewModel
,因为我不确定您是否想将
INotifyPropertyChanged
添加到像
ProductModel
这样的 POCO 类。
请不要用不同的问题编辑您的问题,请打开一个新问题。 您之前的问题可能已经帮助其他人在更改不是从IPropertyChanged
继承的类的属性时面临同样的 UI 未更新问题。 我之前的回答现在与新问题无关,并且永远不会使其他任何人受益。
对于您的新问题,您的Quantity
类型为int
并且您的选择器项目类型为string
,将Quantity
类型更改为string
应该有助于解决您的问题,如果项目的索引匹配,您还可以使用SelectedIndex
而不是SelectedItem
。
<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>
看起来您已经在ProductModel
上正确实现了INotifyPropertyChanged
,但现在您需要在ProductModel
类的构造函数中订阅它。
我已经找到了您正在寻找的内容的简单实现(我排除了您的其余代码,以便更容易消化)
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));
}
}
让我知道这是否能让你前进
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.