0

我有一个带有轮播视图的 Xamarin Forms 应用程序,我的计划是通过底部点击栏中显示的优先级过滤结果。

当视图位于第一张卡片上时,一切正常,但如果您从另一张卡片中点击其中一个过滤器,那么第一个过滤器就会触发 System.ArgumentOutOfRangeException 异常。

我已经尝试了很多方法来将 Carousel View 的位置设置为 0,但都是徒劳的。

  • 使用 CarouselView_PositionChanged 事件 => 不工作
  • 使用 TabHost_SelectedTabIndexChanged 事件 => 不工作
  • 通过 selectedIndex 设置 CarouselView 的属性从 ViewModel 的选项卡视图更改 => 不起作用
  • 把它变成一个 CollectionView 并且一切正常 => 只是看起来很难看

这里的页面

<?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:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
             xmlns:viewModels="clr-namespace:AmsXamarin.ViewModels"
             xmlns:fontAwesome="clr-namespace:FontAwesome"
             xmlns:cells="clr-namespace:AmsXamarin.Cells"
             xmlns:tabs="http://sharpnado.com"
             xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
             x:Class="AmsXamarin.Views.SnagListX.SnagListPage"
             x:Name="mySnagListPage">

    <ContentPage.BindingContext>
        <viewModels:SnagListViewModel />
    </ContentPage.BindingContext>

    <ContentPage.Resources>
        <ResourceDictionary>
            <xct:TabSelectionChangedEventArgs x:Key="TabSelectionChangedEventArgs" />
        </ResourceDictionary>
    </ContentPage.Resources>

    <ContentPage.ToolbarItems>
        <ToolbarItem Command="{Binding ShowMyJobsCommand}"
                     Order="Primary"
                     Priority="0"
                     Text="{Binding MyJobsTitle,Mode=TwoWay}">
        </ToolbarItem>
        <ToolbarItem Command="{Binding AddFaultCommand}"
                     Order="Primary"
                     Priority="0">
            <ToolbarItem.IconImageSource>
                <FontImageSource FontFamily="FAS"
                                 Glyph="{x:Static fontAwesome:FontAwesomeIcons.Plus}"
                                 Color="{AppThemeBinding Dark={StaticResource Third},Light={StaticResource Primary}}"
                                 Size="Large" />
            </ToolbarItem.IconImageSource>
        </ToolbarItem>
        <ToolbarItem Command="{Binding AcceptCommand}"
                     Order="Primary"
                     Priority="0">
            <ToolbarItem.IconImageSource>
                <FontImageSource FontFamily="FAS"
                                 Glyph="{x:Static fontAwesome:FontAwesomeIcons.UserCheck}"
                                 Color="{AppThemeBinding Dark={StaticResource Third},Light={StaticResource Primary}}"
                                 Size="Large" />
            </ToolbarItem.IconImageSource>
        </ToolbarItem>
    </ContentPage.ToolbarItems>

    <ContentPage.Content>
        <StackLayout>
            <Label Style="{StaticResource LabelLarge}"
                   Text="Snag List"
                   VerticalOptions="CenterAndExpand"
                   HorizontalOptions="CenterAndExpand" />

            <StackLayout>
                <IndicatorView x:Name="snagListIndicator"
                               Margin="0,10,0,0"
                               IndicatorColor="LightGray"
                               SelectedIndicatorColor="LightGray"
                               IndicatorSize="6" />
                <RefreshView Command="{Binding RefreshCommand}"
                             IsRefreshing="{Binding IsBusy, Mode=OneWay}"
                             Style="{StaticResource BaseRefreshView}">
                    <CarouselView x:Name="snagListCV"
                                  Margin="10"
                                  IndicatorView="snagListIndicator"
                                  ItemsLayout="HorizontalList"
                                  ItemsSource="{Binding SnagListPriorities.SnagListApps}"
                                  CurrentItem="{Binding SnagListItem}"
                                  Position="{Binding PositionIdx,Mode=OneWay}"
                                  PositionChanged="CarouselView_PositionChanged"
                                  Loop="False"
                                  IsEnabled="{Binding IsNotBusy}">
                        <CarouselView.EmptyView>
                            <StackLayout Padding="12">
                                <Label Style="{StaticResource LabelMedium}"
                                       HorizontalOptions="Center"
                                       Text="{Binding EmptyMessage,Mode=TwoWay}" />
                            </StackLayout>
                        </CarouselView.EmptyView>

                        <CarouselView.ItemTemplate>
                            <DataTemplate>
                                <cells:SnagListCardX />
                            </DataTemplate>
                        </CarouselView.ItemTemplate>
                    </CarouselView>
                </RefreshView>
            </StackLayout>

            <tabs:TabHostView x:Name="TabHost"
                              Margin="13,0,13,10"
                              BackgroundColor="{AppThemeBinding Dark={StaticResource Third},Light={StaticResource Fourth}}"
                              CornerRadius="30"
                              IsSegmented="True"
                              Orientation="Horizontal"
                              TabType="Fixed"
                              SelectedIndex="{Binding SelectedIndex,Mode=TwoWay}"
                              Shades="{StaticResource LightBottomShadow}">
                <tabs:TabHostView.Behaviors>
                    <xct:EventToCommandBehavior EventName="SelectedTabIndexChanged"
                                                Command="{Binding SelectedCommand}"
                                                EventArgsConverter="{StaticResource TabSelectionChangedEventArgs}" />
                </tabs:TabHostView.Behaviors>
                <tabs:TabHostView.Tabs>
                    <tabs:BottomTabItem  Style="{StaticResource BottomTabsMedium}"
                                         Label="All">
                        <tabs:BottomTabItem.Badge>
                            <tabs:BadgeView Style="{StaticResource BadgeViewBase}"
                                            BackgroundColor="{StaticResource All}"
                                            TextColor="White"
                                            Text="{Binding SnagListPriorities.All,Mode=TwoWay}" />
                        </tabs:BottomTabItem.Badge>
                    </tabs:BottomTabItem>
                    <tabs:BottomTabItem Style="{StaticResource BottomTabsMedium}"
                                        Label="High"
                                        StyleClass="">
                        <tabs:BottomTabItem.Badge>
                            <tabs:BadgeView Style="{StaticResource BadgeViewBase}"
                                            BackgroundColor="{StaticResource High}"
                                            TextColor="White"
                                            Text="{Binding SnagListPriorities.High,Mode=OneWay}" />
                        </tabs:BottomTabItem.Badge>
                    </tabs:BottomTabItem>
                    <tabs:BottomTabItem Style="{StaticResource BottomTabsMedium}"
                                        Label="Medium">
                        <tabs:BottomTabItem.Badge>
                            <tabs:BadgeView Style="{StaticResource BadgeViewBase}"
                                            BackgroundColor="{StaticResource Medium}"
                                            TextColor="Black"
                                            Text="{Binding SnagListPriorities.Medium,Mode=TwoWay}" />
                        </tabs:BottomTabItem.Badge>
                    </tabs:BottomTabItem>
                    <tabs:BottomTabItem Style="{StaticResource BottomTabsMedium}"
                                        Label="Low">
                        <tabs:BottomTabItem.Badge>
                            <tabs:BadgeView Style="{StaticResource BadgeViewBase}"
                                            BackgroundColor="{StaticResource Low}"
                                            TextColor="Black"
                                            Text="{Binding SnagListPriorities.Low,Mode=TwoWay}" />
                        </tabs:BottomTabItem.Badge>
                    </tabs:BottomTabItem>
                </tabs:TabHostView.Tabs>
            </tabs:TabHostView>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

和视图模型

using AmsXamarin.Helpers;
using AmsXamarin.Models;
using AmsXamarin.Services;
using MvvmHelpers;
using MvvmHelpers.Commands;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
using Command = MvvmHelpers.Commands.Command;

namespace AmsXamarin.ViewModels
{
    public class SnagListViewModel : BaseViewModel
    {
        readonly ISnagListService snagListService;
        List<SnagListAppX> SnagListAppXs;
        SnagListAppX snagListItem;
        public SnagListAppX SnagListItem
        {
            get { return snagListItem; }
            set
            {
                snagListItem = value;
                OnPropertyChanged();
            }
        }
        SnagListPriorities snagListPriorities;
        public SnagListPriorities SnagListPriorities
        {
            get { return snagListPriorities; }
            set
            {
                snagListPriorities = value;
                OnPropertyChanged();
            }
        }
        public AsyncCommand AddFaultCommand { get; }
        public AsyncCommand AcceptCommand { get; }
        public Command RefreshCommand { get; }
        public Command SelectedCommand { get; }
        public Command ShowMyJobsCommand { get; }
        string emptyMessage;
        public string EmptyMessage
        {
            get { return emptyMessage; }
            set
            {
                emptyMessage = value;
                OnPropertyChanged();
            }
        }
        int positionIdx;
        public int PositionIdx
        {
            get { return positionIdx; }
            set
            {
                positionIdx = value;
                OnPropertyChanged();
            }
        }
        int selectedIndex;
        public int SelectedIndex
        {
            get => selectedIndex;
            set => SetProperty(ref selectedIndex, value);
        }
        string myJobsTitle = "My Jobs";
        int staffId;
        public string MyJobsTitle
        {
            get { return myJobsTitle; }
            set
            {
                myJobsTitle = value;
                OnPropertyChanged();
            }
        }
        bool myJobsEnabled = true;
        bool updateProperty = false;
        public bool AcceptToolBar { get; set; }

        public SnagListViewModel()
        {
            SnagListItem = new SnagListAppX();
            SnagListPriorities = new SnagListPriorities()
            {
                SnagListApps = new ObservableRangeCollection<SnagListAppX>()
            };
            SnagListAppXs = new List<SnagListAppX>();

            AddFaultCommand = new AsyncCommand(ShowAddSnagListItem);
            AcceptCommand = new AsyncCommand(ShowModalAccept);
            SelectedCommand = new Command(Selected);
            RefreshCommand = new Command(Refresh);

            staffId = 0;
            ShowMyJobsCommand = new Command(ShowModalMyJobs);

            snagListService = DependencyService.Get<ISnagListService>();

            Device.BeginInvokeOnMainThread(async () =>
            {
                await GetSnagListItems();
            });
        }

        async Task GetSnagListItems()
        {
            try
            {
                IsBusy = true;

                EmptyMessage = "Loading...";

                SnagListPriorities slp = await snagListService.GetSnagLists(false, true);

                SnagListPriorities.SnagListApps.Clear();
                SnagListPriorities = slp;

                SnagListAppXs.Clear();
                SnagListAppXs.AddRange(slp.SnagListApps);

                EmptyMessage = SnagListAppXs.Count == 0 ? "Good Job! \r\n\r\nCurrently nothing to fix" : "";

                IsBusy = false;
            }
            catch (Exception ex)
            {
                await Application.Current.MainPage.DisplayAlert("Error", ex.Message, "Ok");
            }
        }

        void Selected()
        {
            //PositionIdx = 0;
            //OnPropertyChanged(nameof(PositionIdx));
            //FilterSnagList();
            Refresh();
        }

        void FilterSnagList()
        {
            var allJobs = SnagListAppXs;

            if (staffId != 0) allJobs = allJobs.Where(x => x.StaffId == staffId).ToList();

            if (updateProperty) OnPropertyChanged(nameof(SnagListPriorities));

            if (selectedIndex > 0) allJobs = allJobs.Where(sli => sli.Priority == selectedIndex).ToList();

            SnagListPriorities.SnagListApps.Clear();
            //SnagListPriorities.SnagListApps = new ObservableRangeCollection<SnagListAppX>(allJobs);
            SnagListPriorities.SnagListApps.AddRange(allJobs);
            //OnPropertyChanged(nameof(SnagListPriorities.SnagListApps));
            updateProperty = false;
        }

        void ShowModalMyJobs()
        {
            staffId = myJobsEnabled ? int.Parse(Settings.StaffIdSetting) : 0;
            MyJobsTitle = myJobsEnabled ? "All Jobs" : "My Jobs";
            AcceptToolBar = !myJobsEnabled;
            myJobsEnabled = !myJobsEnabled;
            SelectedIndex = 0;
            updateProperty = true;
        }

        void Refresh()
        {
            IsBusy = true;

            var allJobs = SnagListAppXs.Where(s => s.StaffId == 115);

            SnagListPriorities.SnagListApps.Clear();
            SnagListPriorities.SnagListApps.AddRange(allJobs);

            IsBusy = false;
        }

    }
}

看起来有点乱,但想表明,我已经尝试了很多东西。

最后一次尝试是一个简单的 RefreshView。只要 itemsSource 不变,它就可以工作。一旦它发生变化并且第一张卡未显示,它就会崩溃。

有任何想法吗?非常感谢

调试输出

应用页面

4

0 回答 0