locked
Xamarin forms: Contact search returns no values RRS feed

  • Question

  • User351573 posted

    I have done the fetching of contacts from the phone using this blog.

    My Code:

    XAML

    <StackLayout>
            <SearchBar x:Name="filterText"
                        HeightRequest="40"
                        Text="{Binding SearchText}" />
            <ListView   ItemsSource="{Binding FilteredContacts}"
                        HasUnevenRows="True">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <StackLayout Padding="10"
                                         Orientation="Horizontal">
                                <Image  Source="{Binding Image}"
                                        VerticalOptions="Center"
                                        x:Name="image"
                                        Aspect="AspectFit"
                                        HeightRequest="60"/>
                                <StackLayout VerticalOptions="Center">
                                    <Label Text="{Binding Name}"
                                       FontAttributes="Bold"/>
                                    <Label Text="{Binding PhoneNumbers[0]}"/>
                                    <Label Text="{Binding Emails[0]}"/>
                                </StackLayout>
    
                                <Switch
                                    Toggled="OnToggledEvent"
                                    HorizontalOptions="EndAndExpand"
                                    VerticalOptions="CenterAndExpand"/>
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackLayout>
    

    Viewmodel

    public class MainViewModel: INotifyPropertyChanged
    {
        IContactsService _contactService;
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        public string Title => "Contacts";
    
        public string SearchText { get; set; }
        public ObservableCollection<Contact> Contacts { get; set; }
        public ObservableCollection<Contact> FilteredContacts
        {
            get
            {
                return string.IsNullOrEmpty(SearchText) ? Contacts : new ObservableCollection<Contact>(Contacts?.ToList()?.Where(s => !string.IsNullOrEmpty(s.Name) && s.Name.ToLower().Contains(SearchText.ToLower())));
            }
        }
        public MainViewModel(IContactsService contactService)
        {
            _contactService = contactService;
            Contacts = new ObservableCollection<Contact>();
            Xamarin.Forms.BindingBase.EnableCollectionSynchronization(Contacts, null, ObservableCollectionCallback);
            _contactService.OnContactLoaded += OnContactLoaded;
            LoadContacts();
        }
    
    
        void ObservableCollectionCallback(IEnumerable collection, object context, Action accessMethod, bool writeAccess)
        {
            // `lock` ensures that only one thread access the collection at a time
            lock (collection)
            {
                accessMethod?.Invoke();
            }
        }
    
        private void OnContactLoaded(object sender, ContactEventArgs e)
        {
            Contacts.Add(e.Contact);
        }
        async Task LoadContacts()
        {
            try
            {
                await _contactService.RetrieveContactsAsync();
            }
            catch (TaskCanceledException)
            {
                Console.WriteLine("Task was cancelled");
            }
        } 
    }
    

    Contact and IContactsService

    public class Contact
    {
        public string Name { get; set; }
        public string Image { get; set; }
        public string[] Emails { get; set; }
        public string[] PhoneNumbers { get; set; }
    }
    
    public class ContactEventArgs : EventArgs
    {
        public Contact Contact { get; }
        public ContactEventArgs(Contact contact)
        {
            Contact = contact;
        }
    }
    public interface IContactsService
    {
        event EventHandler<ContactEventArgs> OnContactLoaded;
        bool IsLoading { get; }
        Task<IList<Contact>> RetrieveContactsAsync(CancellationToken? token = null);
    }
    

    My problem is the search feature in contacts returns no data.

    Search Code in Viewmodel

    public ObservableCollection<Contact> FilteredContacts
        {
            get
            {
                return string.IsNullOrEmpty(SearchText) ? Contacts : new ObservableCollection<Contact>(Contacts?.ToList()?.Where(s => !string.IsNullOrEmpty(s.Name) && s.Name.ToLower().Contains(SearchText.ToLower())));
            }
        }
    

    I have attached a sample project with this question.

    Monday, August 17, 2020 7:01 AM

Answers

  • User382871 posted

    My problem is the search feature in contacts returns no data. @Sreeee To update the UI at runtime, the model class should implement the INotifyPropertyChanged interface to raise a PropertyChanged event. Check the doc.

    Try change the code of the ContactsViewModel like below: ``` public class ContactsViewModel : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } ... private string searchText; public string SearchText { get { return searchText; } set { if (searchText != value) { searchText = value; FilteredContacts = string.IsNullOrEmpty(SearchText) ? Contacts : new ObservableCollection(Contacts?.ToList()?.Where(s => !string.IsNullOrEmpty(s.Name) && s.Name.ToLower().Contains(SearchText.ToLower()))); NotifyPropertyChanged(); } } }

    private ObservableCollection<Contact> filteredContacts;
    public ObservableCollection<Contact> FilteredContacts
    {
        get
        {
            return string.IsNullOrEmpty(SearchText) ? Contacts : new ObservableCollection<Contact>(Contacts?.ToList()?.Where(s => !string.IsNullOrEmpty(s.Name) && s.Name.ToLower().Contains(SearchText.ToLower())));
        }
        set
        {
            if (filteredContacts != value)
            {
                filteredContacts = value;
    
                NotifyPropertyChanged();
            }
        }
    }
    ...
    

    } ```

    Here is the code file about the ContactsViewModel class, you can refer to it.

    • Marked as answer by Anonymous Thursday, June 3, 2021 12:00 AM
    Monday, August 17, 2020 8:59 AM