我的lightswitch应用程序中有一个功能,可以从我想使用Rx框架重写的网站下载csv文件,并提供同步调用它的可能性。
以下是新旧函数的代码片段。然而,新函数不起作用,对ParseCSV的调用从未发生过。我想知道为什么,如果有更好的解决方案,请随时提供。
旧代码:
private void ObservableCollection<Data> collection;
public ObservableCollection<Data> GetData(string url, ObservableCollection<Data> targetCollection)
{
collection = targetCollection;
if (!string.IsNullOrEmpty(url))
{
WebClient wc = new WebClient();
wc.OpenReadCompleted += new OpenReadCompletedEventHandler(OpenReadCompleted_ParseCSV);
wc.OpenReadAsync(new Uri(url));
}
return collection;
}
private void OpenReadCompleted_ParseCSV(object sender, OpenReadCompletedEventArgs e)
{
if (e.Error != null) return;
var webClient = sender as WebClient;
if (webClient == null) return;
try
{
using (StreamReader reader = new StreamReader(e.Result))
{
string contents = reader.ReadToEnd();
...
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Error parsing CSV!n" + ex.Message);
}
}
新代码(带Rx):
private void ObservableCollection<Data> collection;
public ObservableCollection<Data> GetData(string url, ObservableCollection<Data> targetCollection)
{
collection = targetCollection;
if (!string.IsNullOrEmpty(url))
{
var result = Observable.FromEventPattern<OpenReadCompletedEventHandler, OpenReadCompletedEventArgs>
(
ev => webClient.OpenReadCompleted += ev,
ev => webClient.OpenReadCompleted -= ev
)
.Select(o => o.EventArgs.Result)
.FirstOrDefault()
.ParseCSV();
// Call the Async method
webClient.OpenReadAsync(new Uri(url));
}
return collection;
}
private void ParseCSV(this Stream stream)
{
try
{
using (StreamReader reader = new StreamReader(e.Result))
{
string contents = reader.ReadToEnd();
...
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Unable to get history data!n" + ex.Message);
}
}
很难知道你要做什么(我想你试图在StackOverflow上发布代码,但在翻译过程中丢失了很多),但我认为对此我没有什么改变。
我注意到的一件事是,您正在主线程上解析结果。你可能会这样做,但你可能会考虑这一点:
//Note the void here. Is your intention to return a new collection or contribute
//to an existing one? I assumed the latter and changed the method to be more clear
//that this method causes side effects.
public void GetData(string url, ObservableCollection<Data> targetCollection)
{
var result = Observable
.FromEventPattern<OpenReadCompletedEventHandler, OpenReadCompletedEventArgs>
(
ev => webClient.OpenReadCompleted += ev,
ev => webClient.OpenReadCompleted -= ev
)
.Select(o => ParseCSV(o.EventArgs.Result));
result.Subscribe(targetCollection.Add);
webClient.OpenReadAsync(new Uri(url));
}
//This method now returns a Data object read from a Stream
private static Data ParseCSV(Stream stream)
{
try
{
using (StreamReader reader = new StreamReader(stream))
{
string contents = reader.ReadToEnd();
//...
return data;
}
}
catch (Exception ex)
{
//Use Exception.ToString(). You get error and stack trace information
//For this error as well as any inner exceptions. Nice!
System.Diagnostics.Debug.WriteLine("Unable to get history data!n" + ex.ToString());
}
return null;
}
在这里,对于从webClient请求返回的每个值(只有一个),我们将结果投影到Data
类中,而不是在可观察流之外进行转换。
我对你的方法做了一些小修改。我不特别喜欢这样有副作用的代码(传递集合来贡献似乎是bug的载体),但我会允许的。除此之外,我认为这应该很好地工作。
WPF的改进答案
创建一个新项目并将此代码粘贴到主窗口中。添加一个名为XBStart的按钮,如果您将单击处理程序连接到XBStart_click,您就可以完成所有设置。运行项目并单击按钮!
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
RX.DataReady += new RX.OnData(RX_DataReady);
}
private void RX_DataReady(ObservableCollection<string> Data)
{
Debugger.Break();
}
private void XBStart_Click(object sender, RoutedEventArgs e)
{
RX.GetData("http://www.yahoo.com");
}
}
public static class RX
{
public delegate void OnData(ObservableCollection<string> Data);
public static event OnData DataReady;
private static WebClient webClient;
private static ObservableCollection<string> TheData { get; set; }
private static void Notify()
{
if (DataReady != null)
{
DataReady(TheData);
}
}
public static void GetData(string url)
{
webClient = new WebClient();
TheData = new ObservableCollection<string>();
var result = Observable
.FromEventPattern<OpenReadCompletedEventHandler,
OpenReadCompletedEventArgs>
(
ev => webClient.OpenReadCompleted += ev,
ev => webClient.OpenReadCompleted -= ev
)
.Select(o => Parse.CSV(o.EventArgs.Result));
result.Subscribe<string>(p =>
{
TheData.Add(p);
Notify();
});
webClient.OpenReadAsync(new Uri(url));
}
}
public static class Parse
{
//This method now returns a Data object read from a Stream
public static string CSV(Stream stream)
{
try
{
using (StreamReader reader = new StreamReader(stream))
{
string contents = reader.ReadToEnd();
//...
return contents;
}
}
catch (Exception ex)
{
//Use Exception.ToString().
//You get error and stack trace information
//For this error as well as any inner exceptions. Nice!
System.Diagnostics.Debug.WriteLine("Unable to get history data!n" +
ex.ToString());
}
return null;
}
}