Xamarin 表单:联系人搜索 returns 没有值

Xamarin forms: Contact search returns no values

我已经使用 this 博客从 phone 获取联系人。

我的代码:

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>

视图模型

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");
        }
    } 
}

联系人和 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);
}

我的问题是联系人中的搜索功能returns 没有数据。

在 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())));
        }
    }

我上传了一个示例项目here以供参考。

那是因为你没有定义FilteredContacts的set方法。所以这个值永远不会改变。

修改ViewModel代码如下

public class ContactsViewModel : INotifyPropertyChanged
{
    IContactsService _contactService;

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    public string Title => "Contacts";


    string search;
    public string SearchText { 
        
        get { return search; } 
        
        set {
           
             if(search!=value)
            {
                search = value;
                OnPropertyChanged("SearchText");

                if (string.IsNullOrEmpty(SearchText))
                {
                    FilteredContacts  = new ObservableCollection<Contact>(Contacts);
                   
                }

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

        } 
    
    }

    public ObservableCollection<Contact> Contacts { get; set; }

    ObservableCollection<Contact> filteredContacts;
    public ObservableCollection<Contact> FilteredContacts
    {
        get { return filteredContacts; } 
        
        set {
        
            if(filteredContacts!=value)
            {
                filteredContacts = value;
                OnPropertyChanged("FilteredContacts");
            }
        }
    }
    public ContactsViewModel(IContactsService contactService)
    {
        _contactService = contactService;
        Contacts = new ObservableCollection<Contact>();
        Xamarin.Forms.BindingBase.EnableCollectionSynchronization(Contacts, null, ObservableCollectionCallback);
        _contactService.OnContactLoaded += OnContactLoaded;
        LoadContacts();

        FilteredContacts = Contacts;
    }


    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");
        }
    }
}