繁体   English   中英

xamarin 表单 - 与选择器的双向绑定 - 为什么我不能从后面的代码更新选择器?

[英]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事件。

\n

此时您可能想要创建一个 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM