ListView 在 Xamarin Forms 中的模式页面操作后未更新

ListView not updating after modal page actions in Xamarin Forms

提问人:Craig85 提问时间:9/29/2023 最后编辑:Craig85 更新时间:9/29/2023 访问量:27

问:

我正在 Xamarin Forms 中创建应用程序。我有一个带有单个 ListViews 的 TabbedPage 来显示和处理坐标和点。为了添加/更新项目,我创建了一个 ToolBarItem。这会在单独的页面上弹出一个模式。此模式具有带有取消(基本上关闭)或提交更改的按钮的输入字段。同样将用于修改现有坐标/点。 我有一个 viewModel(假设是主 viewModel),它有 ObservableCollection 来填充列表视图数据,它实现了 INotifyPropertyChanged 并从 BindableObject 派生:

public class DataViewModel : **BindableObject**, **INotifyPropertyChanged**
    {
        private DataStoreManager dataStoreManager;

        public ObservableCollection<DataItem> Coordinates { get; set; }

        public ObservableCollection<DataItem> Points { get; set; }

        public DataViewModel()
        {
            LoadItems();
        }

        internal void LoadItems()
        {
            dataStoreManager = DataStoreManager.GetInstance();

            this.Coordinates = new ObservableCollection<DataItem>(dataStoreManager.GetAll<DataItem>(DataType.Coordinate));
            this.Points = new ObservableCollection<DataItem>(dataStoreManager.GetAll<DataItem>(DataType.Point));
        }

        public ICommand DeleteCommand => new Command<DataItem>((DataItem item) =>
        {
            dataStoreManager.RemoveItem<DataItem>(item);
            if (item.Type == DataType.Coordinate)
            {
                Coordinates.Remove(item);
                OnPropertyChanged(nameof(Coordinates));
            }
            else if (item.Type == DataType.Point)
            {
                Points.Remove(item);
                OnPropertyChanged(nameof(Points));
            }
        });
    }

此视图模型当前仅处理删除操作。 xaml 代码如下所示:

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            xmlns:viewmodels="clr-namespace:Test.ViewModels"
            x:Class="Test.Views.DataTabbedPage">
    <TabbedPage.ToolbarItems>
        <ToolbarItem Text="New" Order="Primary" Priority="0" Clicked="OnNewButtonClicked" IconImageSource="baseline_note_add_24.xml"></ToolbarItem>
    </TabbedPage.ToolbarItems>
    <ContentPage Title="Coordinates" x:Name="coordinatesPage">
        <ContentPage.BindingContext>
            <viewmodels:DataViewModel />
        </ContentPage.BindingContext>
        <Grid>
            <ListView ItemsSource="{Binding Path=Coordinates}" CachingStrategy="RecycleElement" x:Name="coordinatesListView">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <Grid Padding="20, 15, 20, 0" HorizontalOptions="FillAndExpand">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition />
                                    <ColumnDefinition />
                                </Grid.ColumnDefinitions>
                                <Label Text="{Binding Name}" Grid.Column="0" />
                                <Label Text="{Binding Value}" Grid.Column="1" />
                            </Grid>
                            <ViewCell.ContextActions>
                                <MenuItem Text="Modify" Clicked="OnEditButtonClicked" CommandParameter="{Binding .}"/>
                                <MenuItem Text="Remove" Command="{Binding Source={x:Reference coordinatesPage}, Path=BindingContext.DeleteCommand}" CommandParameter="{Binding .}" />
                            </ViewCell.ContextActions>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </Grid>
    </ContentPage>
    ...
</TabbedPage>

模态页面的 viewmodel 派生自它,这就是 dataEditViewModel。它应该处理更新和新操作:

public class DataEditViewModel : DataViewModel, INotifyPropertyChanged
    {
        private DataStoreManager dataStoreManager;

        public DataItem Item { get; set; } = new DataItem();

        public bool IsNewAction { get; internal set; }

        public bool IsEditAction { get; internal set; }

        public DataEditViewModel()
        {
            this.OnPropertyChanged(nameof(this.Item));
            this.dataStoreManager = DataStoreManager.GetInstance();
        }

        public ICommand NewCommand => new Command<DataItem>((DataItem item) =>
        {
            item.Type = DataType.Coordinate;
            dataStoreManager.AddItem(item);
            Device.BeginInvokeOnMainThread(() => 
            {
                Coordinates.Add(item);
                OnPropertyChanged(nameof(Coordinates));
            });
        });

        public ICommand CommitCommand => new Command<DataItem>((DataItem item) =>
        {
            dataStoreManager.UpdateItem(item);
            DataItem itemToRemove = Coordinates.Single(i => i.Id == item.Id);
            Coordinates.Remove(itemToRemove);
            Coordinates.Add(item);
            OnPropertyChanged(nameof(Coordinates));
        });
    }

此模式的 xaml 如下所示:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:viewmodels="clr-namespace:Test.ViewModels"
             x:Class="Test.Views.DataEditPage"
             x:Name="dataEditPage"
             Title="Edit Data">
    <ContentPage.BindingContext>
        <viewmodels:DataEditViewModel />
    </ContentPage.BindingContext>
    <ContentPage.Content>
        <StackLayout Orientation="Vertical">
            <Entry x:Name="NameEntry" Text="{Binding Path=Item.Name, Mode=TwoWay}" />
            <Entry x:Name="ValueEntry" Text="{Binding Path=Item.Value, Mode=TwoWay}" />
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition />
                </Grid.RowDefinitions>

                <Button Grid.Column="0" Grid.Row="0" Text="Cancel" Clicked="OnCancelButtonClicked" />
                <Button Grid.Column="1" Grid.Row="0" Text="Add" Command="{Binding NewCommand}" CommandParameter="{Binding Item}" Clicked="OnCommitButtonClicked" IsVisible="{Binding IsNewAction}" />
                <Button Grid.Column="1" Grid.Row="0" Text="Save" Command="{Binding CommitCommand}" CommandParameter="{Binding Item}" Clicked="OnCommitButtonClicked" IsVisible="{Binding IsEditAction}" />
            </Grid>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

你能帮我弄清楚为什么列表视图在集合更改后不更新,比如添加或更新吗?删除操作工作得很好,它正确地更新了列表视图。

谢谢你的一切!

(我也尝试在主线程上调用操作,但没有奏效)

Android ListView Xamarin 模式对话框

评论

0赞 Jason 9/29/2023
有 2 个 VM 类,每个类都有自己的 Coordinates 属性。在一个 VM 中添加项不会更新另一个 VM
0赞 Craig85 9/29/2023
Coordinates 是 DataViewModel 的属性,DataEditViewModel 没有它。
0赞 Jason 9/29/2023
NewCommand更新集合 - 这是从哪里来的?Coordinates
0赞 Craig85 9/29/2023
从 EditPageViewModel 的父级,从 DataViewModel。(我刚刚意识到,我没有正确复制这个视图模型,缺少类定义。正在更新。
0赞 Jason 9/29/2023
无论如何,每个页面都有自己的 VM 实例。对一个实例的更改不会影响另一个实例

答: 暂无答案