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