Xamarin.forms 更新ListView的ObservableCollection中一项的显示

Xamarin.forms 更新ListView的ObservableCollection中一项的显示,xamarin.forms,Xamarin.forms,我有一个绑定到可观察集合的ListView 是否有一种方法可以在SomeModel项的属性发生更改时更新单个单元格,而无需通过更改ObservableCollection重新加载ListView 问题是从中复制的,我的答案也是从中复制的。如果将模型项替换为其自身,则与模型项关联的任何UI都将在可观察集合中刷新 详情: 在ViewModel中,给定属性: public ObservableCollection<Item> Items { get; set; } = new Observ

我有一个绑定到可观察集合的ListView

是否有一种方法可以在SomeModel项的属性发生更改时更新单个单元格,而无需通过更改ObservableCollection重新加载ListView


问题是从中复制的,我的答案也是从中复制的。

如果将模型项替换为其自身,则与模型项关联的任何UI都将在可观察集合中刷新

详情:

在ViewModel中,给定属性:

public ObservableCollection<Item> Items { get; set; } = new ObservableCollection<Item>();
注:以上代码假定项已知为项中的项。如果未知,则在执行替换之前测试IndexOf是否返回>=0

在我的例子中,我在集合上有一个DataTemplateSelector,该项被更改为需要一个不同的模板。具体来说,通过TemplateSelector从模型项读取IsExpanded属性,单击该项可以在折叠视图和展开/详细视图之间切换

注意:使用CollectionView进行测试,但AFAIK也将使用旧的ListView类。 在iOS和Android上测试

技术说明:
此项的替换可能会触发一个事件,其中newItems和oldItems都只包含项

正如我所看到的,您正在尝试将MVVM用作Xamarin.Forms应用程序的模式。您已经在使用ObservableCollection来显示数据列表。当从集合中添加或删除新项时,UI将相应刷新,这是因为ObserverbleCollection正在实现INotifyCollectionChanged

当您想要更改集合中项目的特定值并更新UI时,此问题要实现的是下一个行为。实现这一点的最佳和最简单的方法是为集合中项目的模型实现INotifyPropertyChanged

贝娄,我有一个简单的演示例子如何实现这一点,你的答案是工作,因为我可以看到,但我相信这个例子会更好地为你使用它

我有一个简单的按钮,带有命令和ListView,它保存着我的收集数据

这是我的页面SimpleMvvmExamplePage.xaml:

在Github上的完整演示示例中,我使用的是BindableBase类,在该类中,当在props的setter中使用此SetProperty方法更改某些属性值时,我将处理引发INotifyPropertyChanged的问题

您可以找到以下实现:

最后要显示的是此页面的我的ViewModel,在ViewModel内部,当用户单击ListView上方的按钮时,我会将集合中项目的Seed属性值更改为True。这是我的SimpleMvvmExamplePageViewModel.cs

这段代码将帮助我们实现这种行为:当用户单击按钮时,我们将更改集合中项目属性的值,UI将刷新,复选框值将被选中

这个演示的最终结果可以在下面的gif文件中看到

另外,我可以将它与ListView中的ItemTapped事件结合起来,但我想让它变得非常简单,所以这个例子是这样的


希望这对你有帮助,祝你在编码方面好运

几天后又增加了一个更好的答案;我已经接受了这个答案。对于这个问题,这不是最好的答案,但如果需要,这种方法也会更新项目模板。
public void RefreshMe(Item item)
{
    // Replace the item with itself.
    Items[Items.IndexOf(item)] = item;
}
<StackLayout>

    <Button Text="Set status" 
            Command="{Binding SetStatusCommand}" 
            Margin="6"/>

    <ListView ItemsSource="{Binding Cars}"
              HasUnevenRows="True">

        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>

                    <StackLayout Orientation="Vertical" 
                                 Margin="8">

                        <Label Text="{Binding Name}" 
                               FontAttributes="Bold" />

                        <StackLayout Orientation="Horizontal">

                            <Label Text="Seen?" 
                                   VerticalOptions="Center"/>

                            <CheckBox IsChecked="{Binding Seen}"
                                      Margin="8,0,0,0" 
                                      VerticalOptions="Center" 
                                      IsEnabled="False" />
                        </StackLayout>

                     </StackLayout>

                </ViewCell>
            </DataTemplate>
          </ListView.ItemTemplate>
     </ListView>

 </StackLayout>
public class Car : INotifyPropertyChanged
{
    private string name;
    public string Name
    {
        get { return name; }
        set 
        { 
            name = value;
            OnPropertyChanged();
        }
    }

    private bool seen;
    public bool Seen
    {
        get { return seen; }
        set 
        { 
            seen = value;
            OnPropertyChanged();
        }
    }

    // Make base class for this logic, something like BindableBase
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}
public class SimpleMvvmExamplePageViewModel
{
    public ObservableCollection<Car> Cars { get; set; }

    public ICommand SetStatusCommand { get; private set; }

    public SimpleMvvmExamplePageViewModel()
    {
        // Set simple dummy data for our ObservableCollection of Cars
        Cars = new ObservableCollection<Car>()
        {
            new Car()
            {
                Name = "Audi R8",
                Seen = false
            },

            new Car()
            {
                Name = "BMW M5",
                Seen = false
            },

            new Car()
            {
                Name = "Ferrari 430 Scuderia",
                Seen = false
            },

            new Car()
            {
                Name = "Lamborghini Veneno",
                Seen = false
            },

            new Car()
            {
                Name = "Mercedes-AMG GT R",
                Seen = false
            }
        };

        SetStatusCommand = new Command(SetStatus);
    }

    private void SetStatus()
    {
        Car selectedCar = Cars.Where(c => c.Seen == false)
            .FirstOrDefault();

        if (selectedCar != null)
        {
            // Change the value and update UI automatically
            selectedCar.Seen = true;
        }
    }
}