var*_*rin 1 c# asynchronous windows-phone-7
所以我有一个Win Phone应用程序,它正在查找出租车公司列表,并从Bing成功提取他们的姓名和地址,并填充正在向用户显示的列表框.现在我想要做的是,在Bing上搜索这些术语中的每一个,找到每个搜索词返回的命中数并相应地对它们进行排名(一种松散的流行度排名)
void findBestResult(object sender, DownloadStringCompletedEventArgs e)
{
string s = e.Result;
XmlReader reader = XmlReader.Create(new MemoryStream(System.Text.UTF8Encoding.UTF8.GetBytes(s)));
String name = "";
String rName = "";
String phone = "";
List<TaxiCompany> taxiCoList = new List<TaxiCompany>();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name.Equals("pho:Title"))
{
name = reader.ReadInnerXml();
rName = name.Replace("&","&");
}
if (reader.Name.Equals("pho:PhoneNumber"))
{
phone = reader.ReadInnerXml();
}
if (phone != "")
{
string baseURL = "http://api.search.live.net/xml.aspx?Appid=<MyAppID>&query=%22" + name + "%22&sources=web";
WebClient c = new WebClient();
c.DownloadStringAsync(new Uri(baseURL));
c.DownloadStringCompleted += new DownloadStringCompletedEventHandler(findTotalResults);
taxiCoList.Add (new TaxiCompany(rName, phone, gResults));
}
phone = "";
gResults ="";
}
TaxiCompanyDisplayList.ItemsSource = taxiCoList;
}
}
Run Code Online (Sandbox Code Playgroud)
因此,该位代码找到出租车公司并启动异步任务以查找创建每个teaxicompany对象的搜索结果数(gResults).
//Parses search XML result to find number of results
void findTotalResults(object sender, DownloadStringCompletedEventArgs e)
{
lock (this)
{
string s = e.Result;
XmlReader reader = XmlReader.Create(new MemoryStream(System.Text.UTF8Encoding.UTF8.GetBytes(s)));
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name.Equals("web:Total"))
{
gResults = reader.ReadInnerXml();
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
上面的剪辑找到了bing上搜索结果的数量,但问题是因为它启动异步,没有办法将第二种方法中获得的gResults与方法1中的正确公司相关联.有没有办法:
1.)将名称和电话变量传递给第二种方法,在那里创建出租车对象
2.)传回gResults变量,然后才创建相应的taxicompany对象?
好吧,这里有很多事情要做.
获取一些小帮手代码
首先,我想指出几个名为Simple Asynchronous Operation Runner Part 1和Part 2的博客文章.我并不是建议你真正阅读它们(虽然你们也受欢迎,但我被告知他们阅读起来并不容易).你真正需要的是它们中的几个代码块放在你的应用程序中.
首先从第1部分复制"AsyncOperationService"框中的代码,将其放在项目中名为"AsyncOperationService.cs"的新类文件中.
其次,您需要第2部分中的"DownloadString"函数.您可以将其放在任何位置,但我建议您创建一个名为"WebClientUtils"的静态公共类并将其放在那里.
解决方案概要
我们将创建一个class(TaxiCompanyFinder),它有一个方法可以触发异步作业以获得您所获得的结果,然后在作业完成时引发一个事件.
让我们开始吧.你有一个TaxiCompany班级,我会在这里发明我自己的,以便示例尽可能完整: -
public class TaxiCompany
{
public string Name { get; set; }
public string Phone { get; set; }
public int Total { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我们还需要一个EventArgs完成的事件,其中包含已完成的事件List<TaxiCompany>以及Error将返回可能发生的任何异常的属性.看起来像这样: -
public class FindCompaniesCompletedEventArgs : EventArgs
{
private List<TaxiCompany> _results;
public List<TaxiCompany> Results
{
get
{
if (Error != null)
throw Error;
return _results;
}
}
public Exception Error { get; private set; }
public FindCompaniesCompletedEventArgs(List<TaxiCompany> results)
{
_results = results;
}
public FindCompaniesCompletedEventArgs(Exception error)
{
Error = error;
}
}
Run Code Online (Sandbox Code Playgroud)
现在我们可以为这TaxiCompanyFinder堂课的一些简单的骨头开始: -
public class TaxiCompanyFinder
{
protected void OnFindCompaniesCompleted(FindCompaniesCompletedEventArgs e)
{
Deployment.Current.Dispatcher.BeginInvoke(() => FindCompaniesCompleted(this, e));
}
public event EventHandler<FindCompaniesCompletedEventArgs> FindCompaniesCompleted = delegate {};
public void FindCompaniesAsync()
{
// The real work here
}
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,这非常简单.您将注意到在BeginInvoke调度程序上的使用,因为将涉及一系列异步操作,我们希望确保在实际引发事件时它在UI线程上运行,从而更容易使用此类.
分离XML解析
您的原始代码存在的一个问题是,它将枚举XML与尝试执行其他功能混合在一起,它有点spagetti.我识别的第一个函数是解析XML以获取名称和电话号码.将此函数添加到类中: -
IEnumerable<TaxiCompany> CreateCompaniesFromXml(string xml)
{
XmlReader reader = XmlReader.Create(new StringReader(xml));
TaxiCompany result = new TaxiCompany();
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name.Equals("pho:Title"))
{
result.Name = reader.ReadElementContentAsString();
}
if (reader.Name.Equals("pho:PhoneNumber"))
{
result.Phone = reader.ReadElementContentAsString();
}
if (result.Phone != null)
{
yield return result;
result = new TaxiCompany();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,此函数TaxiCompany从xml 生成一组实例,而不尝试执行任何其他操作.使用ReadElementContentAsString它也可以进行更整洁的阅读.此外,消耗xml字符串更加顺畅.
出于类似的原因,将此函数添加到类中: -
private int GetTotalFromXml(string xml)
{
XmlReader reader = XmlReader.Create(new StringReader(xml));
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
if (reader.Name.Equals("web:Total"))
{
return reader.ReadElementContentAsInt();
}
}
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
核心功能
将以下函数添加到类中,这是执行所有真正异步工作的函数: -
private IEnumerable<AsyncOperation> FindCompanies(Uri initialUri)
{
var results = new List<TaxiCompany>();
string baseURL = "http://api.search.live.net/xml.aspx?Appid=<MyAppID>&query=%22{0}%22&sources=web";
string xml = null;
yield return WebClientUtils.DownloadString(initialUri, (r) => xml = r);
foreach(var result in CreateCompaniesFromXml(xml))
{
Uri uri = new Uri(String.Format(baseURL, result.Name), UriKind.Absolute);
yield return WebClientUtils.DownloadString(uri, r => result.Total = GetTotalFromXml(r));
results.Add(result);
}
OnFindCompaniesCompleted(new FindCompaniesCompletedEventArgs(results));
}
Run Code Online (Sandbox Code Playgroud)
它实际上看起来很直接,几乎像同步代码,这是重点.它获取包含所需集合的初始xml,创建TaxiCompany对象集.它通过集合添加Total每个值的foreaches .最后,完成的活动将由全套公司解雇.
我们只需要填写FindCompaniesAsync方法: -
public void FindCompaniesAsync()
{
Uri initialUri = new Uri("ConstructUriHere", UriKind.Absolute);
FindCompanies(initialUri).Run((e) =>
{
if (e != null)
OnFindCompaniesCompleted(new FindCompaniesCompletedEventArgs(e));
});
}
Run Code Online (Sandbox Code Playgroud)
我不知道最初的Uri是什么,或者你是否需要以某种方式使用paramatise,但你只需要调整这个函数.真正的魔法发生在Run扩展方法中,这将通过所有异步操作慢跑,如果有任何返回异常,则完成的事件将触发Error属性集.
使用课程
现在你可以像这样使用这个类:
var finder = new TaxiCompanyFinder();
finder.FindCompaniesCompleted += (s, args) =>
{
if (args.Error == null)
{
TaxiCompanyDisplayList.ItemsSource = args.Results;
}
else
{
// Do something sensible with args.Error
}
}
finder.FindCompaniesAsync();
Run Code Online (Sandbox Code Playgroud)
您也可以考虑使用
TaxiCompanyDisplayList.ItemsSource = args.Results.OrderByDescending(tc => tc.Total);
Run Code Online (Sandbox Code Playgroud)
如果你想让公司总排名最高的公司.
| 归档时间: |
|
| 查看次数: |
5422 次 |
| 最近记录: |