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");
}
}
}
我已经使用 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");
}
}
}