【问题标题】:INotifyPropertyChanged - Observable collection not posting back if UI field is changedINotifyPropertyChanged - 如果 UI 字段更改,可观察的集合不会回发
【发布时间】:2020-10-28 16:48:12
【问题描述】:

我一直在查看 INotifyPropertyChanged() 的许多示例。

我选择了以下示例:

https://xamarindev.co.uk/mvvm-and-xamarin-forms/

我已经用这个创建了一个测试项目,一切正常......使用我可以看到的断点

public int Age
{
    get { return _person.Age; }
    set
    {
        _person.Age = value;
        OnPropertyChanged("Age");
        OnPropertyChanged("UserInfo");
    }
}

当用户在应用上更改年龄时触发。

唯一的问题是我想要多个人而不是一个 Person 实例,所以我添加了一个 ObservableCollection 看起来像:

    public class ViewModel1 : BaseModel
{
    private ObservableCollection<Person> _Persons;
    public ObservableCollection<Person> Persons
    {
        get { return _Persons; }
        set
        {
            if (_Persons == value) return;
            _Persons = value;
        }
    }

    private Person _person;
    public ViewModel1()
    {
        Persons = new ObservableCollection<Person>();

        //// set some default here for example
        _person = new Person
        {
            Age = 21,
            FirstName = "Steve",
            LastName = "Hawkins"
        };
        Persons.Add(_person);

        _person = new Person
        {
            Age = 19,
            FirstName = "JimBob",
            LastName = "Jones"
        };
        Persons.Add(_person);
    }

    public int Age
    {
        get { return _person.Age; }
        set
        {
            _person.Age = value;
            OnPropertyChanged("Age");
            OnPropertyChanged("UserInfo");
        }
    }

    public string FirstName
    {
        get { return _person.FirstName; }
        set
        {
            _person.FirstName = value;
            OnPropertyChanged("FirstName");
            OnPropertyChanged("UserInfo");
        }
    }

    public string LastName
    {
        get { return _person.LastName; }
        set
        {
            _person.LastName = value;
            OnPropertyChanged("LastName");
            OnPropertyChanged("UserInfo");
        }
    }

    public string UserInfo
    {
        get
        {
            // return _person.PersonInfo();
            return _Persons[0].PersonInfo();
        }
    }
}

然后将 View 改为显示 ListView:

 <ContentPage.Content>
        <StackLayout>
                      <ListView  x:Name="producttablelist" IsVisible="True" VerticalOptions="FillAndExpand" HasUnevenRows="True" ItemsSource="{Binding Persons}" 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>
                                    <Editor Grid.Row="1" Grid.Column="1" Text="{Binding FirstName, Mode=TwoWay}" HorizontalOptions="CenterAndExpand" TextColor="Black" />
                                    <Editor Grid.Row="1" Grid.Column="2" Text="{Binding LastName, Mode=TwoWay}" HorizontalOptions="CenterAndExpand" TextColor="Black" />
                                    <Editor Grid.Row="2" Grid.Column="1" Text="{Binding Age, Mode=TwoWay}" HorizontalOptions="CenterAndExpand" TextColor="Black" />
                                    <Label Grid.Row="2" Grid.Column="2" Text="{Binding UserInfo}" HorizontalOptions="StartAndExpand" TextColor="Black" />
                                </Grid>
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

        </StackLayout>
    </ContentPage.Content>
</ContentPage>

所以现在,页面加载显示 2 个用户,但如果用户更改应用程序上的年龄...什么也不会发生...它不会在 VM 中回发到年龄...

有人可以帮忙吗?

一直在查看在 https://riptutorial.com/xaml/example/28804/binding-to-a-collection-of-objects-with-inotifypropertychanged-and-inotifycollectionchanged 上找到的其他示例

https://stackoverflow.com/questions/32667408/how-to-implement-inotifypropertychanged-in-xamarin-forms

如果我使用 ObservableCollection,似乎仍然无法启动它,并且当年龄改变时我有其他逻辑要添加,我希望从 VM 而不是从 Person 类(我发现的一些示例有显示)

求帮助

【问题讨论】:

  • 为什么你在 VM 上有 Age 等属性,而不是仅仅使用 Person 类中存在的属性?人应该为它的属性实现 INPC。你的方法真的很不寻常。
  • 添加您的人物模型和您更改年龄的代码
  • @Jason 感谢您的回复。我在 VM 上有属性,因为这正是我提到的示例完成它的方式......我正在从我的原始 Q stackoverflow.com/questions/64490129/… 工作,其中 Cherry 提到我的模型属性没有正确实现 INPC 所以我一直在努力试图弄清楚我做错了什么。如果您有时间,请您快速浏览一下
  • “Age”条目绑定到数据中每个人对象的 Age 属性,而不是基础 VM 的 Age 属性
  • 好的,感谢 Jason 的帮助

标签: xaml xamarin xamarin.forms observablecollection inotifypropertychanged


【解决方案1】:

正如杰森所说:the "Age" entry is bound to the Age property of each person object in your data, not to the Age property of the base VM

您不需要在 ViewModel 中编写这些属性,因为它们已经存在于 Person Model 中。

你真正想要绑定的是Text="{Binding Person.FirstName, Mode=TwoWay}"而不是ViewModel1.FirstName

你可以在这里写Text="{Binding FirstName, Mode=TwoWay}",因为数据绑定会搜索根属性,直到找到模型Person中的属性FirstName

参考:data-bindings-to-mvvm

【讨论】:

    【解决方案2】:

    也许可以尝试使用 SetProperty,它继承自 INotifyPropertyChanged,即像下面的代码那样编写您的公共属性:

        private ObservableCollection<Person> _persons;
    
        public ObservableCollection<Person> Persons
        {
            get => _persons;
            set => SetProperty(ref _persons, value);
        }
    

    ps....如果您遇到问题,您的 baseModel 可能也需要从 INotifyPropertyChanged 继承。我还假设您正在使用像 PrismMVVM 这样的 MVVM 框架

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-04-01
      • 2012-08-04
      • 1970-01-01
      • 1970-01-01
      • 2021-05-27
      • 1970-01-01
      相关资源
      最近更新 更多