2012-04-19 59 views
0

我想從兩個不同的網站獲取兩種類型的數據,並將其綁定到一個列表,但我與異步的問題,我想要做的是從一個rss將它添加到列表中,然後從另一個網站獲取信息將其添加到列表中,然後將這兩個添加到綁定的可觀察集合中。但DownloadStringAsync已經過時運行了,並且應用程序崩潰了。你能幫我嗎?我怎樣才能做一個異步任務同步

我的代碼是所有我相信lamdba會比你的情況的回調更好的

private static ObservableCollection<Top> top= new ObservableCollection<Top>(); 
    private static ObservableCollection<string> place= new ObservableCollection<string>(); 
    // Constructor 
    public MainPage() 
    { 
     InitializeComponent(); 
     if (NetworkInterface.GetIsNetworkAvailable()) 
     { 
      LoadSiteContent_A(url1); 

      LoadSiteContent_B(url2); 


     } 
     else 
      MessageBox.Show("No Internet Connection, please connect to use this applacation"); 



     listBox.ItemsSource = top; //trying to bind listbox after web calls 
    } 





    public void LoadSiteContent_A(string url) 
    { 

      //create a new WebClient object 
      WebClient clientC = new WebClient(); 


      clientC.DownloadStringCompleted += new DownloadStringCompletedEventHandler(a_DownloadStringCompleted); 
      clientC.DownloadStringAsync(new Uri(url)); 


    } 

    public void LoadSiteContent_B(string url) 
    { 
      //create a new WebClient object 
      WebClient clientC = new WebClient(); 


      clientC.DownloadStringCompleted += new DownloadStringCompletedEventHandler(b_DownloadStringCompleted); 
      clientC.DownloadStringAsync(new Uri(url)); 


    } 

    public void a_DownloadStringCompleted(Object sender, DownloadStringCompletedEventArgs e) 
    { 
     string testString = ""; 


     if (!e.Cancelled && e.Error == null) 
     { 
      string str; 

      str = (string)e.Result; 

      //Various operations and parsing 


        place.Add(testString); 

      } 


      } 


    } 
    public void b_DownloadStringCompleted(Object sender, DownloadStringCompletedEventArgs e) 
    { 

     string testMatch = ""; 


     if (!e.Cancelled && e.Error == null) 
     { 
      string str; 
      // Size the control to fill the form with a margin 
      str = (string)e.Result; 

       //Various operations and parsing 



       top.Add(new Top(testMatch,(place.Count+1))); 


      } 



    } 


public class TopUsers 
{ 
    public string TopUsername { get; set; } 
    public int Place { get; set; } 

    public TopUsers(string topusername, int place) 
    { 
     this.TopUsername = topusername; 
     this.Place = place; 

    } 
} 


} 
+1

如果你希望它是同步的,爲什麼不直接叫LoadSiteContent_B在a_DownloadStringCompleted()?這將模仿同步活動,但具有異步的好處。 – Archer 2012-04-19 14:48:42

+0

你在異步實現方面做得很好。你只需要找到一種同步添加到可觀察集合的方法。提示:查找「鎖定」關鍵字 – Polity 2012-04-19 14:51:53

+0

劃傷我的提示,您使用的是靜態實例,因此應該重新考慮您的設計。添加到可觀察集合應該在主線程上完成。新提示:查找同步。 – Polity 2012-04-19 14:53:53

回答

0

第一。 爲了同步下載,您必須在LoadSiteContent_A的完整事件中調用LoadSiteContent_B。

private static ObservableCollection<Top> top= new ObservableCollection<Top>(); 
    private static ObservableCollection<string> place= new ObservableCollection<string>(); 
    private string _url1; 
    private string _url2; 
    // Constructor 
    public MainPage(string url1, string url2) 
    { 
     InitializeComponent(); 
     if (NetworkInterface.GetIsNetworkAvailable()) 
     { 
      _url1 = url1; 
      _url2 = url2; 
      LoadSiteContent_A(url1); 
     } 
     else 
      MessageBox.Show("No Internet Connection, please connect to use this applacation"); 
     listBox.ItemsSource = top; //trying to bind listbox after web calls 
    } 

    public void LoadSiteContent_A(string url) 
    { 
      //create a new WebClient object 
      WebClient clientC = new WebClient(); 
      clientC.DownloadStringCompleted += (sender, e) => { 
      string testString = ""; 
      if (!e.Cancelled && e.Error == null) 
      { 
       string str; 
       str = (string)e.Result; 
       //Various operations and parsing 
       place.Add(testString); 
       LoadSiteContent_B(_url2); 
       } 
      }; 

      clientC.DownloadStringAsync(new Uri(url)); 
    } 

    public void LoadSiteContent_B(string url) 
    { 
      //create a new WebClient object 
      WebClient clientC = new WebClient(); 
      clientC.DownloadStringCompleted += (sender, e) => {/*do whatever you need*/}; 
      clientC.DownloadStringAsync(new Uri(url)); 
    } 


public class TopUsers 
{ 
    public string TopUsername { get; set; } 
    public int Place { get; set; } 

    public TopUsers(string topusername, int place) 
    { 
     this.TopUsername = topusername; 
     this.Place = place; 

    } 
} 


} 
1

這是更多的替代答案(AlexTheo的解決方案應該工作)。

當他們給我們(WP開發者)提供新的異步內容時,所有這些變得更加容易。

你的代碼可以這樣寫:

public async MainPage() 
{ 
    InitializeComponent(); 
    DoAsyncLoad(); 
} 
private async Task DoAsyncLoad() // note use of "async" keyword 
{ 
    if (NetworkInterface.GetIsNetworkAvailable()) 
    { 
     await LoadSiteContent_A(""); 
     await LoadSiteContent_B(""); 
    } 
    else 
     MessageBox.Show("No Internet Connection, please connect to use this applacation"); 

    listBox.ItemsSource = top; //trying to bind listbox after web calls 
} 

public async Task LoadSiteContent_A(string url) 
{ 
    //create a new WebClient object 
    WebClient clientC = new WebClient(); 

    var result = await clientC.DownloadStringTaskAsync(new Uri(url)); 
    // No need for a Lambda or setting up an event 

    var testString = result; // result is the string you were waiting for (will be empty of canceled or errored) 
} 
public async Task LoadSiteContent_B(string url) 
{ 
    //create a new WebClient object 
    WebClient clientC = new WebClient(); 

    var result = await clientC.DownloadStringTaskAsync(new Uri(url)); 
    // Again, no need for a Lambda or setting up an event (code is simpler as a result) 
    top.Add(new Top(testMatch, place.Count + 1)); 
} 

有更多的代碼更改你將不得不作出(使用HTTP調用的異步版本並標記LoadSiteContent_A/B爲異步--and設置任務的返回)。

順便說一句,你實際上可以加載最新的Async-CTP3併發布這種方式編寫的WP代碼。儘管大多數人對CTP有點害怕。

我寫了這一篇博客文章,你可以看看這裏 - http://www.jaykimble.net/metro-nuggets-async-is-your-friend.aspx

+0

嗨DevTheo當我有這個代碼'私人異步任務DoAsyncLoad()//注意使用「異步」關鍵字 { }'我得到的錯誤說,預計分半結腸,我是否缺少使用指令? – 2012-04-19 15:53:54

+0

我所說的關鍵是你需要安裝Async CTP3(成功),然後包含AsyncCtpLibrary_Phone.dll(包含在CTP中)。我懷疑你沒有這樣做,所以電話工具/編譯器不知道「異步」和「等待」是什麼。我將繼續並更新我的代碼示例以包含更多的代碼,以便您可以看到它的外觀。我在Async上的博客上有一篇博客文章 - http://www.jaykimble.net/metro-nuggets-async-is-your-friend.aspx(不知道這是否有用) – DevTheo 2012-04-20 16:52:42

1

我不會試圖讓他們的其他類似後一個。通過一個接一個地「堆疊」它們,就像你一開始就失去了異步調用的所有優點。不僅如此,在像Windows Phone這樣的移動平臺上,您必須記住網絡呼叫會排隊以便有效使用天線。當你同時撥打這兩個電話時,他們在相同的天線連接期間執行的可能性要高得多,這是一件「好事」。

接下來,您的每個回調都實際上更新完全獨立的集合。 A正在更新place集合,B正在更新top集合。所以這不是兩個人以任何方式彼此相處的問題。

我在這裏看到的唯一真正的問題就是您正在更新設置爲listBox.ItemsSourcetop集合。您需要將綁定數據的更新封送回UI線程(又名Dispatcher線程),以便綁定到它們的控件將在正確的線程上更新。

所以,你應該做你的任何代碼的唯一改變是元帥增加了新的項目到top收集回Dispatcher線程在B回調。這將是這樣的:

public void b_DownloadStringCompleted(Object sender, DownloadStringCompletedEventArgs e) 
{ 
    string testMatch = ""; 

    if(!e.Cancelled && e.Error == null) 
    { 
     string str; 
     // Size the control to fill the form with a margin 
     str = (string)e.Result; 

     //Various operations and parsing 

     Top newTop = new Top(testMatch,(place.Count+1)); 

     Dispatcher.Invoke(() => 
     { 
      top.Add(newTop); 
     }); 
    } 
} 

有了這個,所有的工作仍然異步/同步,除了在您的項目添加到top收集的小小的一部分。

+0

WebClient類已經自動調用UI線程上的回調,您不必這樣做:http://social.msdn.microsoft.com/Forums/en-US/windowsphone7series/thread/594e1422-3b69-4cd2-a09b-fb500d5eb1d8/ – PhilChuang 2012-04-19 18:37:29

+0

Mea culpa如果是這樣的話,我不是WP專家。我習慣於「純粹的」.NET,但這不是WebClient的工作方式。如果是這種情況,那麼我無法想象問題是什麼,因爲我看不出有什麼問題。我想我們需要@M_K的異常/堆棧跟蹤。 – 2012-04-19 18:46:21

0

即使使用lambda,也有一個更加優雅的解決方案 - 使用自定義Action,其中T是數據類型。

例如:

public void LoadSiteContent_A(string url, Action<string> onCompletion) 
{ 
     //create a new WebClient object 
     WebClient clientC = new WebClient(); 

     clientC.DownloadStringCompleted += (s,e) => 
     { 
      onCompletion(e.Result); 
     }; 
     clientC.DownloadStringAsync(new Uri(url)); 
} 

當你調用這個方法,你可以通過這樣的動作:

LoadSiteContent_a(yourUrlWhatever, data => 
{ 
    // DO SOMETHING WITH DATA 
}); 
相關問題