如何在Silverlight 4中异步调用方法?

问题描述:

我正在开发一个适用于SharePoint的Silverlight应用程序,并希望从列表中获取ListItems。我知道我需要异步查询以避免阻塞UI线程。通常我使用ExecuteQueryAsync,但是由于我喜欢将结果设置为DataGrid源,因此无法工作。如何在Silverlight 4中异步调用方法?

如何异步调用GetItemsFromList方法,并将结果设置为DataGrid源而不会产生太多的代码开销? (拉姆达?)

SharePointHelper类:

public static ListItemCollection GetItemsFromList(string name) 
{ 
    var context = ClientContext.Current; 
    var targetList = context.Web.Lists.GetByTitle("ListName"); 

    CamlQuery camlQuery = new CamlQuery(); 
    camlQuery.ViewXml = string.Format("<View><Query><Where><Eq><FieldRef Name='Title'/><Value Type='Text'>{0}</Value></Eq></Where></Query>RowLimit>4</RowLimit></View>", 
             name); 

    ListItemCollection collListItems = targetList.GetItems(camlQuery); 
    context.ExecuteQuery(); 

    return collListItems; 
} 

UI类:

private void SetDataGridItemSource() 
{ 
    dataGrid.Source = GetItemsFromList("name"); 
} 

我现在已经实现从肖恩Kendrot解决方案:

BackgroundWorker worker = new BackgroundWorker(); 
worker.DoWork += (sender, args) => 
{ 
    args.Result = SharePointHelpers.GetItemsFromList("name"); 
}; 
worker.RunWorkerCompleted += (s, e) => dataSource.Source = e.Result as ListItemCollection; 
worker.RunWorkerAsync(); 

我不熟悉的SharePoint(或甚至的SharePoint为此事)的ClientContext类,但我没有看到任何docs异步方法。如果此通话费用很高,您可以将电话打包为BackgroundWorker。 BackgroundWorker将执行查询,您可以返回结果。您将无法按照您所描述的方式分配Source,但需要在工作人员完成时设置Source。

private void SetDataGridItemSource() 
    { 
     BackgroundWorker worker = new BackgroundWorker(); 
     worker.DoWork += WorkerOnDoWork; 
     worker.RunWorkerCompleted += WorkerOnRunWorkerCompleted; 
     worker.RunWorkerAsync("name");  
    } 

    private void WorkerOnDoWork(object sender, DoWorkEventArgs args) 
    { 
     if(args.Argument != null) 
     { 
      string name = args.Argument.ToString(); 
      var context = ClientContext.Current; 
      var targetList = context.Web.Lists.GetByTitle("ListName"); 

      CamlQuery camlQuery = new CamlQuery(); 
      camlQuery.ViewXml = string.Format("<View><Query><Where><Eq><FieldRef Name='Title'/><Value Type='Text'>{0}</Value></Eq></Where></Query>RowLimit>4</RowLimit></View>", 
               name); 

      ListItemCollection collListItems = targetList.GetItems(camlQuery); 
      context.ExecuteQuery(); 

      args.Result = collListItems; 
     } 
    } 

    private void WorkerOnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs args) 
    { 
     dataGrid.Source = args.Result as ListItemCollection; 
    } 
+0

这将工作,但对于此解决方案,我需要为每个我喜欢打电话的方法添加一个BackgroundWorker,并且必须注册该事件。我希望像@丹Wray尝试更好的解决方案;-) – jwillmer 2012-08-13 16:59:29

+0

使用回调和订阅事件本质上是一回事。由于这些方法看起来不是异步的,所以您需要使它们异步。 BackgroundWorker使这成为可能。如果您不喜欢拥有完整的方法,只需将事件订阅更改为:worker.RunWorkerCompleted + =(s,e)=> dataGrid.Source = e.Result as ListItemCollection; – 2012-08-13 18:36:37

像这样的事情?

public delegate void ItemsLoadedCallback(IEnumerable<object> Entities); 
public static void GetItemsFromList(string name, ItemsLoadedCallback Callback) 
{ 
    // codesnip 

    // Do async thing, on return call: 
    if (Callback != null) 
    { 
     Callback(collListItems); 
    } 
} 


private void SetDataGridItemSource() 
{ 
    GetItemsFromList("name", (items) => dataGrid.Source = items); 
} 
+0

获取此错误:调用的方法或属性可能会阻塞UI线程,并且不允许。请使用后台线程来调用方法或属性,例如使用System.Threading.ThreadPool.QueueUserWorkItem方法来调用方法或属性。 – jwillmer 2012-08-13 16:54:23

+0

我完全不熟悉Sharepoint。我的印象是,你可以在某个地方使用“ExecuteQueryAsync”方法来异步执行你的查询,我上面显示的代码只能真实地显示你如何捕获这个异步调用的结果并将它返回给你的原始代码通过委托调用方法。如果你不能以本地方式异步执行操作,你可能会使用后台工作者来做到这一点,如Shawn的解决方案所示。 – 2012-08-14 07:47:32