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

有些话、适合烂在心里 提交于 2019-12-11 00:56:58

问题


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

回答1:


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.




回答2:


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



回答3:


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.



来源:https://stackoverflow.com/questions/7701690/infinite-loop-when-i-combine-a-button-click-and-an-asynchronous-contacts-call

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!