xamarin 表单 - 与选择器的两种方式绑定 - 为啥我不能从后面的代码更新选择器?

Posted

技术标签:

【中文标题】xamarin 表单 - 与选择器的两种方式绑定 - 为啥我不能从后面的代码更新选择器?【英文标题】:xamarin forms - two way binding with a picker - why cant I update a picker from code behind?xamarin 表单 - 与选择器的两种方式绑定 - 为什么我不能从后面的代码更新选择器? 【发布时间】:2020-10-17 20:53:43 【问题描述】:

我的产品页面仅显示“产品名称”和“数量”,数量显示/绑定到选择器。

出于测试目的,仅从 VM 加载了 2 个产品。葡萄酒 1 和葡萄酒 2。

应用程序加载时,为什么选择器是空的,没有选择任何值。当每个项目的数量设置为 1 时,从 VM 加载时

数量设置为 1,选择器在最初加载时没有更新,我知道这是因为如果我单击空选择器并选择 1。没有任何反应,因为代码命中

if (quantity != value)

//其中选择的数量1在后面的代码中已经是1,所以不会在数量中从setter调用propertyChanged,

还有... 如果我选择选择器并选择另一个数字,例如 4。数量上的setter被击中,OnPropertyChanged被击中,picker上显示4。 (如果选择了 3,我什至测试了更改产品名称) 这行得通。

我知道这一切都有效,因为我已经逐步完成了代码。 但是现在发生的另一个问题是,由于某种原因,代码在每次单击后再次达到 get/set AGAIN 的数量并将值设置为 0。

因此,例如如果单击 4,则选择器将在屏幕上更新为 4,然后如果我通过单步执行代码,再次调用数量设置器,将值设置为 0,因此什么都不选择在选择器中。将其留空,就像它最初加载时一样。

任何有助于解决此问题的帮助将不胜感激,感谢 Y

感谢 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();
        
    

【问题讨论】:

您不需要在数量选择器上使用“SelectedIndexChanged="QuantityChanged"”,因为您已绑定到属性,您可以在属性更改时简单地处理该代码。您需要将以下代码添加到空白的“ProductModel”构造函数中。 “this.PropertyChanged += OnPropertyChanged”,并重写捕获事件的方法。然后在属性发生变化时处理所需的代码 == nameof(Quantity) 感谢您的回答,我已尽力按照您的建议进行操作,但遇到了困难,请查看更新后的 Q 任何帮助将不胜感激,谢谢 Y 是的,你现在很接近了。我将转到一个实际的帖子,以便更轻松地格式化代码。 【参考方案1】:

您的ProductModel 类不继承自INotifyPropertyChanged 接口,您需要将接口添加到您的类并实现它,同时确保在Quantity setter 中引发INotifyPropertyChanged.PropertyChanged 事件.

此时您可能想要创建一个ProductViewModel,因为我不确定您是否要将INotifyPropertyChanged 添加到像ProductModel 这样的POCO 类中。


请不要用其他问题编辑您的问题,请打开一个新问题。您之前的问题可能已经帮助其他人在更改不从IPropertyChanged 继承的类的属性时面临相同的 UI 未更新问题。我之前的答案现在与新问题无关,并且永远不会使其他任何人受益。

对于您的新问题,您的Quantity 类型为int,您的选择器项目类型为string,将Quantity 类型更改为string 应该有助于解决您的问题,您也可以使用@987654335 @ 而不是 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>

【讨论】:

感谢您的回答,我已尽力按照您的建议进行操作,但遇到了困难,请查看更新后的 Q 任何帮助将不胜感激,谢谢 Y 感谢您抽出宝贵时间提供帮助,它解决了“当应用程序加载时,为什么选择器为空且未选择任何值的问题。当每个项目的数量设置为 1 时,从 VM 加载时。我将此标记为正确答案,但我需要两个答案来解决我的问题,所以写了另一个 Q 并评论说 Q 的第二部分也由 ReRoute 回答,同样是 Roger,感谢您帮助我解决这个问题。非常感激。对于未来的裁判将知道将 1 个问题保留在 1 个帖子中,并对任何混淆表示歉意 ***.com/questions/64437205/…【参考方案2】:

看起来您已经在您的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));
        
    

如果这能让你继续前进,请告诉我

【讨论】:

非常感谢您提供的帮助。我犯了需要两个问题来解决我的问题的错误。我已经标记了另一个答案,因为它有助于解决问题的第一部分,但我需要您的答案来帮助正确回发和更新。请接受我的道歉或困惑。我想感谢您的帮助,所以我写了另一个 Q,如果您在那里发布您的答案,我会将其标记为正确。再次感谢您花时间帮助***.com/questions/64437205/… 没关系。我很高兴你让它工作了。不用担心到期的信用,我在这里帮助人们享受乐趣,因为我喜欢编码。

以上是关于xamarin 表单 - 与选择器的两种方式绑定 - 为啥我不能从后面的代码更新选择器?的主要内容,如果未能解决你的问题,请参考以下文章

[微信小程序] 微信小程序下拉滚动选择器picker绑定数据的两种方式

绑定 xamarin 表单选择器值的正确方法

前端图片上传的两种逻辑分析

Jquery详解

React 实现数据双向绑定 事件的绑定以及传参 获取表单值的两种方法

Xamarin Forms 两种方式绑定ActivityIndi​​cator