在MVVM中将SearchBar与ObservableCollection一起使用

问题描述 投票:0回答:1

我已经在我的应用程序中创建了一个搜索页面,我希望能够在ViewModel中的ObservableCollection中搜索项目并将其显示在CollectionView上。到目前为止,这是我所做的,并且每次运行应用程序时都会出现异常,即System.Reflection.TargetInvocationException: 'Exception has been thrown by the target of an invocation.'SearchPage XAML

<!--Doctors Search Result-->
        <Grid Grid.Row="1">
            <CollectionView ItemsSource="{Binding RecentDoctors}">

                <CollectionView.ItemsLayout>
                    <ListItemsLayout Orientation="Vertical" ItemSpacing="15"/>
                </CollectionView.ItemsLayout>

                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <StackLayout Orientation="Horizontal">
                            <!--Image-->
                            <Frame BackgroundColor="Black"
                                   HeightRequest="20"
                                   WidthRequest="20"
                                   CornerRadius="100"
                                   Margin="20,0,0,0"
                                   HorizontalOptions="Start"
                                   VerticalOptions="Center"
                                   IsClippedToBounds="True">

                                <Image HorizontalOptions="Center"
                                       VerticalOptions="Center"/>
                            </Frame>

                            <StackLayout Orientation="Vertical"
                                         VerticalOptions="Center"
                                         Spacing="-3">
                                <!--Fullname-->
                                <Label Text="{Binding DoctorsName}"
                                       FontSize="19"
                                       FontAttributes="Bold"/>

                                <!--Specialization-->
                                <Label Text="{Binding Specialization}"
                                       FontSize="14"
                                       TextColor="LightGray"/>
                            </StackLayout>
                        </StackLayout>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </Grid>

        <!--Doctors Search Bar-->
        <Grid Grid.Row="0" ColumnSpacing="0" RowSpacing="0">
            <pancake:PancakeView BackgroundColor="#0F8DF4"
                                 HasShadow="True">
                <Grid>
                    <!--The SearchBar-->
                    <renderers:CustomSearchBar x:Name="doctorsSearchBar"
                               Placeholder="Search Doctors by Name, Specialization"
                               VerticalOptions="Center"
                               FontSize="17"
                               TextColor="Black"
                               WidthRequest="320"
                               Text="{Binding SearchedText}"
                               SearchCommand="{Binding SearchBarCommand}"
                               SearchCommandParameter="{Binding Text, Source={x:Reference doctorsSearchBar}}"/>
                </Grid>
            </pancake:PancakeView>
        </Grid>

SearchPage ViewModel

public class TelemedSearchPageViewModel : BaseViewModel
    {
        private string _searchedText;
        public string SearchedText
        {
            get { return _searchedText; }

            set
            {
                _searchedText = value;
                OnPropertyChanged();
                Search();
            }
        }

        public ObservableCollection<RecentDoctorsInfo> RecentDoctors { get; set; } = new ObservableCollection<RecentDoctorsInfo>();

        public ICommand SearchBarCommand { get; set; }

        /// <summary>
        /// Main Constructor
        /// </summary>
        public TelemedSearchPageViewModel()
        {
            SearchBarCommand = new RelayCommand(Search);

            //RecentDoctorsList
            RecentDoctors.Add(new RecentDoctorsInfo()
            {
                DoctorsName = "Steven Strange",
                Specialization = "Sorcerer Supreme",
                Location = "177a Bleecker St. | USA"
            });

            RecentDoctors.Add(new RecentDoctorsInfo()
            {
                DoctorsName = "Peter Parker",
                Specialization = "Spiderman",
                Location = "177a Bleecker St. | USA"
            });

            RecentDoctors.Add(new RecentDoctorsInfo()
            {
                DoctorsName = "Bruce Banner",
                Specialization = "The Hulk",
                Location = "177a Bleecker St. | USA"
            });

            RecentDoctors.Add(new RecentDoctorsInfo()
            {
                DoctorsName = "Reed Richards",
                Specialization = "Mr.Fantastic",
                Location = "177a Bleecker St. | USA"
            });  
        }

        #region METHODS
        public void Search()
        {
            if (RecentDoctors != null && RecentDoctors.Count >0)
            {
                var temp = RecentDoctors.Where(x => x.DoctorsName.ToLower().Contains(SearchedText.ToLower()));

                foreach (var item in temp)
                {
                    RecentDoctors.Add(item);
                }
            }
        }

        #endregion
    }

Edit3:

if (RecentDoctors != null && RecentDoctors.Count > 0)
            {
                var results = RecentDoctors.Where(x => x.DoctorsName.ToLower().Contains(SearchedText.ToLower()));
                SearchResults.Clear();
                foreach (RecentDoctorsInfo item in results)
                {
                    SearchResults.Add(item);
                }
            }
            else
            {
                RecentDoctors.Clear();
            }
xamarin xamarin.forms observablecollection
1个回答
0
投票

如果要在用户键入时执行搜索,则应使用doscs建议的行为

public class SearchBarTextChangedBehavior : Behavior<SearchBar>
{
    protected override void OnAttachedTo(SearchBar bindable)
    {
        base.OnAttachedTo(bindable);
        bindable.TextChanged += this.SearchBar_TextChanged;
    }

    protected override void OnDetachingFrom(SearchBar bindable)
    {
        base.OnDetachingFrom(bindable);
        bindable.TextChanged -= this.SearchBar_TextChanged;
    }

    private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
    {
        ((SearchBar)sender).SearchBarCommand?.Execute(e.NewTextValue);
    }
}

然后将行为附加到您的SearchBar

<renderers:CustomSearchBar
    x:Name="doctorsSearchBar"
    Placeholder="Search Doctors by Name, Specialization"
    VerticalOptions="Center"
    FontSize="17"
    TextColor="Black"
    WidthRequest="320"
    Text="{Binding SearchedText}"
    SearchCommand="{Binding SearchBarCommand}">
    <renderers:CustomSearchBar.Behaviors>
        <behaviors:SearchBarTextChangedBehavior />
    </renderers:CustomSearchBar.Behaviors>
</renderers:CustomSearchBar>

另一方面,您应该创建原始列表的私有副本,并添加与公共收藏夹相同的项目

private List<RecentDoctorsInfo> originalRecentDoctorsList = new List<RecentDoctorsInfo>();

public ObservableCollection<RecentDoctorsInfo> RecentDoctors { get; set; } = new ObservableCollection<RecentDoctorsInfo>();

public ICommand SearchBarCommand { get; set; }

public TelemedSearchPageViewModel()
{
    SearchBarCommand = new RelayCommand(Search);

    //RecentDoctorsList
    RecentDoctors.Add(new RecentDoctorsInfo()
    {
        DoctorsName = "Steven Strange",
        Specialization = "Sorcerer Supreme",
        Location = "177a Bleecker St. | USA"
    });

    RecentDoctors.Add(new RecentDoctorsInfo()
    {
        DoctorsName = "Peter Parker",
        Specialization = "Spiderman",
        Location = "177a Bleecker St. | USA"
    });

    RecentDoctors.Add(new RecentDoctorsInfo()
    {
        DoctorsName = "Bruce Banner",
        Specialization = "The Hulk",
        Location = "177a Bleecker St. | USA"
    });

    RecentDoctors.Add(new RecentDoctorsInfo()
    {
        DoctorsName = "Reed Richards",
        Specialization = "Mr.Fantastic",
        Location = "177a Bleecker St. | USA"
    });

    // Backup copy list.
    originalRecentDoctorsList.Add(new RecentDoctorsInfo()
    {
        DoctorsName = "Steven Strange",
        Specialization = "Sorcerer Supreme",
        Location = "177a Bleecker St. | USA"
    });

    originalRecentDoctorsList.Add(new RecentDoctorsInfo()
    {
        DoctorsName = "Peter Parker",
        Specialization = "Spiderman",
        Location = "177a Bleecker St. | USA"
    });

    originalRecentDoctorsList.Add(new RecentDoctorsInfo()
    {
        DoctorsName = "Bruce Banner",
        Specialization = "The Hulk",
        Location = "177a Bleecker St. | USA"
    });

    originalRecentDoctorsList.Add(new RecentDoctorsInfo()
    {
        DoctorsName = "Reed Richards",
        Specialization = "Mr.Fantastic",
        Location = "177a Bleecker St. | USA"
    });  
}

最后,您的Search方法应清除公共集合(您正在显示的集合),并使用私有作为备份

private void Search()
{
    if (!string.IsNullOrEmpty(SearchedText))
    {
        var filteredDoctors = RecentDoctors
                    .Where(x =>
                        x.DoctorsName.ToLower().Contains(SearchedText.ToLower()))
                    .ToList();

        RecentDoctors.Clear();

        foreach(var recentDoctor in filteredDoctors)
            RecentDoctors.Add(recentDoctor);
    }
    else
    {
        // This is when you clean the text from the search

        RecentDoctors.Clear();

        foreach(var originalRecentDoctor in originalRecentDoctorsList)
            RecentDoctors.Add(originalRecentDoctor);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.