0

在执行我的应用程序时,我需要知道在确定是否拍摄现场照片或“不可用图片”之前,是否有可用的图片(来自指定的URI)。同步获取图片(来自Uri)

因为图片只设置一次,所以我需要同步了解图片是否可访问且没有损坏。我试图与无扩展,但我从来没有能够得到的第一个元素(整个应用程序冻结的。首先()语句时)

以下blogger遮住了我的问题,但他的代码,甚至没有编制。我想这可能与Reactive使用的新语法有关。此外,Reactive仍处于Silverlight 5的测试阶段,我猜它可能仍然有不寻常的行为。

我愿意接受任何其他可能的解决方案,但对我来说更好的解决方案将能够创建一个打开读取()扩展方法WebClient类,并使用它像这样:

var pictureStream = new WebClient().OpenRead(_uri); 
if (pictureStream != null) 
{ 
    var picture = new BitmapImage(); 
    picture.SetSource(picture); 
    return picture; 
} 
else 
{ 
    //Picture is unavailable 
} 

非常感谢你!

+2

您可以简单地忘记Silverlight中的同步I/O调用。他们不被允许。这是一件好事。微软故意只留下方法的异步版本,以避免人们编写废话软件,这些软件会在有人执行I/O操作时冻结。只需习惯异步编程。在C#5.0中会有新的'async/await'关键字,它们允许你编写看起来同步的代码,但是在后台编译器会生成所有必要的管道以执行真正的异步非阻塞调用。 – 2012-02-12 22:51:43

+0

嗯,我的确在想假装异步调用,这正是Reactive Extensions设计的原因......所以我想这是可能的。我的整个应用程序被设计为异步,但在这个地方,我真的需要知道当前函数中的信息。一个await函数无疑会完成这项工作...... – Philippe 2012-02-12 22:59:24

+0

@Philippe - Rx是关于抽象事件和异步操作 - 而不是“伪装”它们。如果你曾经使用'.First()'(或其姊妹阻塞函数),那么你很可能不会做正确的事情。我建议你重新考虑你的方法。 – Enigmativity 2012-02-12 23:48:39

回答

0

Silverlight的版本(不得不安装在新的PC上)。

假设你已经定义的缺失图像的const或“静态只读”实例表明,这是你的业务逻辑

private static BitmapImage ToBitmapImage(Stream pictureStream) 
{ 
    if (pictureStream != null) 
    { 
     var picture = new BitmapImage(); 
     picture.SetSource(pictureStream); 
     return picture; 
    } 
    return _missingImage; 
} 

位然后你就可以有一个方法,其中Rx来获得图像,但在引擎盖下使用SL WebClient。

private static IObservable<BitmapImage> GetImage(string path) 
{ 
    var uri = new Uri(path); 

    return Observable.Create<BitmapImage>(o=> 
    { 
     var webClient = new WebClient(); 
     var request = Disposable.Create(webClient.CancelAsync); 
     var readComplete = Observable.FromEventPattern<OpenReadCompletedEventHandler, OpenReadCompletedEventArgs>(
      h => webClient.OpenReadCompleted += h, 
      h => webClient.OpenReadCompleted -= h); 

     var subscription = readComplete 
      .Select(e => ToBitmapImage(e.EventArgs.Result)) 
      .Subscribe(o); 
     webClient.OpenReadAsync(uri); 
     return new CompositeDisposable(request, subscription);   
    }); 
} 

好消息是,SL做所有的线程对你那么不shcedulers是必需的,一切都保持好和响应(即UI不冻结)。

这是你在找什么?

0

的错误一些化妆的想象,他们可以离开未修改的同步代码(在你的情况的代码,希望能够调用一个函数,它返回图片),并在某种程度上只是使其中的一部分配合是异步。这只是不可能的,只要你的代码调用的函数需要异步,那么调用代码本身也是如此,代码调用这些代码一直到任何事件启动代码。

C#语言在地平线上的新功能旨在缓解这种情况,但它们现在不适用于您。它仍然需要链中的所有代码来理解它是异步的。

我经常看到Reactive被吹捧为解决这类问题的方法,然而,Reactive并不是真的被设计来解决这个问题,你最终会跳过一些丑陋的箍来试图解决这个问题。

因此,我提供了我用作博客here的解决方案。有了这个代码到位(它需要添加到项目的代码极短量),你的代码可以写为: -

IEnumerable<AsyncOperation> GetPicture(Uri uri, Action<ImageSource> returnResult) 
    { 
     WebRequest req = WebRequest.Create(uri) 

     Stream pictureStream = null; 
     yield return req.GetRequestStreamAsyncOp(r => 
     { 
      try {reqStream = r; } catch { } 
     }); 

     yield return AsyncOperationService.SwitchToUIThread(); 

     if (pictureStream != null) 
     { 
      var picture = new BitmapImage(); 
      picture.SetSource(picture); 
      returnResult(picture); 
     } 
     else 
     { 
      //Picture is unavailable 
      //returnResult(someOtherPicure); 
     } 

    } 

你调用代码是这样的: -

GetPicture(_uri, picture => 
{ 

     //Do stuff with your picture here. 

}).Run(err => 
{ 
    if (err != null) 
    { 
     //Oops something bad happened code here. 
    } 
}); 
0

Rx对于这种类型的东西来说很不错。我相信这个问题是错误的,你实际上想成为异步。您只需要从Web请求的结果中继续。 Rx可以做到这一点。

var _uri = @"http://blog.stackoverflow.com/wp-content/uploads/stackoverflow-sticker-proof.png"; 
var prictureRequest = Observable.Start<BitmapImage>(()=> 
{ 
    var pictureStream = new WebClient().OpenRead(_uri); 
    if (pictureStream != null) 
    {  
     var picture = new BitmapImage();  
     picture.StreamSource = pictureStream;  
     return picture; 
    } 
    else 
    {  
     //Picture is unavailable 
     //maybe throw new InvalidOperationException("Not valid image"); 
    //or 
    return ImageCache.PictureUnavailable; 
    } 
}); 

然后您订阅请求。

var subscription = pictureRequest.Subscribe(
    img=> Console.WriteLine ("Set image here eg. MyImage.Source = img"), 
    ex=> Console.WriteLine ("Fail!. Do something about exception here") 
    ); 

然后你只需要确保你在另一个线程上订阅(例如通过使用线程池)并确保你在UI线程上更新。我们应该已经使用ThreadPool,因为我们已经使用了Observable.Start让我们进入Rx。

var subscription = pictureRequest 
    //.SubscribeOn(Scheduler.ThreadPool)//Not needed as Observable.Start defaults to this. 
    .ObserveOnDispatcher() 
    .Subscribe(
     img=> Console.WriteLine ("Set image here eg. MyImage.Source = img"), 
     ex=> Console.WriteLine ("Fail!. Do something about exceptio here") 
    ); 

这将适用于WPF代码。如果订阅(ThreadPool)/ Observable,我无法记住我的头顶。开始将与SL的IO规则一起工作(即使用WebRequest)。如果不是的话,我会认为APM就是你想要的。

看看我的博客了解更多有关Rx,异步和下载图像(WPF)的内容。

http://leecampbell.blogspot.com/2011/05/rx-code-from-perth-presentation.html

也有我有一个博客系列,可以帮助您更好地了解Rx的(如不使用。首先())

http://leecampbell.blogspot.com/2010/08/reactive-extensions-for-net.html

+0

我不明白我是如何在代码中检索图片流的时候,我从来没有调用过WebService.OpenReadCompleted。更甚者,WebService.OpenRead在Silverlight中不存在,这正是我想抽象的函数(在扩展方法中)。 – Philippe 2012-02-14 01:24:18

+0

对不起,我把SL4版本扔在一起,我认为你想做什么。查看其他答案。 – 2012-02-14 09:01:32