开发者

Infinite loop when I combine a button click and an asynchronous Contacts call

I have problem when i combines a button click event with a asynchronous call of Contacts on the phone (WP7). The problem is that the SearchCompleted event for the async Contacts call is not run before the Click event is finnished. This will lead to a infinite loop while waiting for that the async call should completes.

In my simplified code example I have a checkbox and a button. When the button is pressed a click event is raised. If the checkbox is checked then an asynchronous SearchAsync call will be done to get all contacts on the phone.

How do I avoid the infinite loop that this code will result in if the checkbox is checked:

    private bool searchCompleted = false;
    private Contact[] contacts;

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        Dictionary<int, string> contactList = new Dictionary<int,string>;

        // ... add contacts to the contactList ...
        contactList.Add(1, "a contact name");

        // if CheckBox is checked add contacts from the phone Contacts
        if (checkBoxContacts.IsChecked == true)
        {
            Contacts cons = new Contacts();

            cons.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(Contacts_SearchCompleted);
            cons.SearchAsync(string.Empty, FilterKind.None, null);

            searchCompleted = false;
 开发者_Python百科           while (!searchCompleted) 
            {
                Thread.Sleep(100);
            }
            int n = 1;
            foreach (Contact contact in contacts)
            {
                contactList.Add(n, contact.DisplayName);
            }
        }

        // .... add more namnes to the contactList from other places....

        // .... do something with the contactList ....

        // Navigate to the next dialog 
        NavigationService.Navigate(new Uri("/NextPage.xaml", UriKind.Relative));
    }

    private void Contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
    {
        contacts = e.Results.ToArray();
        searchCompleted = true;
    }


I had a similar issue recently and I think the problem is that you're calling Thread.Sleep() within button1_Click, which is running on the UI Thread which doesn't take kindly to Thread.Sleep(), or .WaitOne(), etc.

Try executing some of your button click code on a background thread and abstract out your Contact retrieval to some sort of helper class - I've got something like this working:

private void Button_Click(object sender, RoutedEventArgs e)
{
    //this should be done asynchronously - "request" a person

    List<Person> people = new List<Person>();
    PersonService ps = new PersonService();     
    ThreadPool.QueueUserWorkItem(func =>
    {
        for (int i = 0; i < 10; i++)
        {
                    people.Add(ps.GetRandomPerson()); //you need to call this on a separate thread or it will lock the ui thread.                       
        }                                   
        Dispatcher.BeginInvoke(() => { Status.Text = "done"; });    //your button click method is now also asynchronous
    });
}

/*** Helper class ***/      

public class PersonService
{
    AutoResetEvent sync = new AutoResetEvent(false);

    public Person GetRandomPerson()
    {
        Person person = new Person();
        Contacts contacts = new Contacts();            
        contacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(contacts_SearchCompleted);            
        contacts.SearchAsync(String.Empty, FilterKind.None, person);
        sync.WaitOne();
        return person;
    }

    void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
    {
        Contact[] allContacts = e.Results.ToArray();
        Contact randomContact = allContacts[new Random().Next(allContacts.Length)];
        Person person = (Person)e.State;
        person.Name = randomContact.DisplayName;

        sync.Set();
    }
}

Note that this means you will need to treat your button click method as an asynchronous call, since you don't know when the background thread is going to finish processing.


Remove the infinite loop and move the code to populate the contatList to the event handler

 private void Contacts_SearchCompleted(object sender, ContactsSearchEventArgs e)
    {
      contacts = e.Results.ToArray();
      int n = 1;
      foreach (Contact contact in contacts)
      {
        contactList.Add(n, contact.DisplayName);
      }
    }


How long does the search take? If you have very few or no contacts, might the search complete before you get to execute

searchComplete = false;

In which case your loop will never end as searchComplete will never be set to true.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜