2012-02-16 85 views
1

我在我的lightswitch应用程序中有一个函数,该函数从一个站点下载一个csv文件,我希望使用Rx框架重新编写这个文件并提供同步调用它的可能性。Observable和Webclient获取CSV 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); 
} 
} 
+0

只是一个快速提示 - 你滥用的Rx - 这应该都在一个单一查询来完成没有'FirstOrDefault'在眼前...... – Enigmativity 2012-02-16 12:35:23

+0

这是我第一次拨打电话同步(想法来自功能的尝试炼金术:让Silverlight同步) – sysboard 2012-02-17 08:18:13

+0

Rx全都是关于异步的。如果你试图使它同步,你很可能会陷入僵局。你使用的工具“LinqPad”?如果没有,你应该下载它。在“便笺式”环境中尝试Rx代码非常棒。 – Enigmativity 2012-02-17 11:25:29

回答

1

这很难知道你要什么(我想你试图贬低在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; 
} 

这里,对于回来从Web客户端请求(将只有一个),每个值,我们突出结果到您的Data类,而不是在可观察流之外进行转换。

我对你的方法做了一些小的修改。我并不特别喜欢这种副作用的代码(通过集合来贡献似乎是一个错误的向量),但我会允许它。除此之外,我认为这应该工作得很好。

+0

感谢您提供的解决方案和周到的评论。为此,我已经标记了您的答案有用。这还不是我想要有同步变化的完整解决方案。你能补充一点吗? – sysboard 2012-02-17 08:21:34

0

一种用于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; 
    } 
} 
+0

所有这篇文章已经完成了现有的答案,并将其放入WPF窗口的代码。 OP完全没有问WPF,而且这增加了*与所问的问题无关的*。 – 2012-11-01 21:19:37

+0

确实如此,该帖子的标题显示“针对WPF的改进答案”,我这样做是为了帮助其他人(包括我自己)在WPF土地上遇到同样问题! – 2012-12-21 15:24:00