2012-04-19 54 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 
}); 
相关问题