2011-10-29 60 views
0

我想寫一個抓取聯繫人的方法,並將其轉換爲數據對象並將其返回。我明白,由於聯繫人搜索是異步的,調用方法也需要;但是,我想返回一個對象作爲調用搜索的父方法的一部分,我不確定最佳方法是什麼。如何將異步聯繫人搜索的結果傳遞迴調用方法?

我目前得到的僞代碼:

public Person GetRandomPerson(string s) 
{ 
    Person myPerson = new Person(); 

    Person contacts = new Contacts();    

    contacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(contacts_SearchCompleted); 
    contacts.SearchAsync(String.Empty, FilterKind.None, "All Contacts");    

    return Person; //I'm not sure how this will ever work... 
} 

void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e) 
{ 
    //convert a Contact object to Person object here 
} 

我已經做了一下週圍的地方(like this SO question)讀書,但我不太清楚如何嵌套的異步調用返回會看起來像,或者我如何將來自基於事件的異步聯繫人搜索的結果傳回到父調用方法 - 我如何實現這種效果?

回答

0

好吧,我終於摸索出來,並有兩個部分的解決方案:

1)假冒我想創造出觸點的結果通過作爲第三對象的狀態搜索的數據對象.SearchAsync方法調用中的參數。

2)將GetRandomPerson(最初剛剛關閉Button_Click)的調用移動到後臺線程;在這種情況下我使用ThreadPool.QueueUserWorkItem。看起來UI線程可以理解的不能很好地從WaitOne()恢復。

如果你有興趣,工作代碼的解決方案是:

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

我在聽,如果任何人有一個更優雅的解決方案,這一點,所以請喊出來,如果你有一個仍然有興趣!

+0

直接調用'GetRandomPerson'的人(不知道PersonService的內部)會被阻塞。這與我的回答沒有多大區別。我認爲,在一個線程中調用'GetRandomPerson'應該在'PersonService'中處理 –

+0

我想將後臺線程移動到PersonService可能會更好 - 但我仍然需要將整個調用推送到後臺線程以保持UI線程正在運行,所以這就是爲什麼我保持原樣。 –

1

我改變了一下你的代碼。您需要GetRandomPersoncontacts_SearchCompleted之間的共享類Person。看看contacts.SearchAsync的參數,也許你可以通過myPerson它沒有聲明爲class'es私人領域。

Person myPerson = new Person(); //***** 
public Person GetRandomPerson(string s) 
{ 
    Person contacts = new Contacts();    

    contacts.SearchCompleted += new EventHandler<ContactsSearchEventArgs>(contacts_SearchCompleted); 
    contacts.SearchAsync(String.Empty, FilterKind.None, "All Contacts");    

    wait.WaitOne();  //***** 
    return myPerson; //I'm not sure how this will ever work... 
} 

ManualResetEvent wait = new ManualResetEvent(false); //***** 

void contacts_SearchCompleted(object sender, ContactsSearchEventArgs e) 
{ 
    //Fill myPerson 
    wait.Set(); //***** 
} 
+0

雖然這是一個單身人士 - 所以如果你快速連續兩次調用GetRandomPerson,有(但很小)的機會,你只是得到第二個人的結果兩次... –

+0

雖然我可能能夠通過Person對象作爲第三個參數......嗯。 –

+0

也,這是行不通的,與此處列出的類似問題 - http://stackoverflow.com/questions/7701690/infinite-loop-when-i-combine-a-button-click-and-an-asynchronous-聯繫人調用我懷疑wait.one暫停線程,並從來沒有踢回到contacts_SearchCompleted「設置」的等待...我可以嘗試推contacts.SearchAsync到另一個線程,也許... –

相關問題