2015-05-23 32 views
2
var client = new WebClient(); 
var bytes = client.DownloadData(webUrl); <-- NOT null 

Application.Current.Dispatcher.BeginInvoke(new Action(() => 
{ 
    BitmapImage img = new BitmapImage(); 
    img.BeginInit(); 
    img.StreamSource = new MemoryStream(bytes); <-- null 
    img.EndInit(); 
    img_DownloadCompleted(img, webUrl); 
})); 

上述代碼在線程中執行以避免阻塞UI。來自封閉塊的變量在匿名函數中變爲空

我試圖從互聯網下載圖像到BitmapImage對象。圖像正確下載,但是當我嘗試在我的UI中使用它時(使用Dispatcher.Invoke),我收到以下錯誤消息:The calling thread cannot access this object because a different thread owns it.

因此,我添加了在UI線程上創建圖像的代碼。但是現在,當代碼到達<-- null指示的行時,變量bytes突然變爲空。在執行進入匿名函數之前,它不是null。 (我用調試器檢查過)

有誰知道這是爲什麼? Google不是很有幫助。

將變量類型bytes更改爲var沒有什麼區別。

+0

的片斷提供任何沒有暗示。回到原來的方法,不要忘記調用BitmapImage的Freeze()方法,這樣你就不會再有這種異常了。 –

+0

謝謝! img.EndInit()之後的img.Freeze()確實修復了底層問題。 – Jan

回答

5

您很可能會在以後更改bytes變量,從而修改匿名函數中的「捕獲」值。喜歡的東西:

var bytes = client.DownloadData(webUrl); <-- NOT null 
Application.Current.Dispatcher.BeginInvoke(new Action(() => 
{ 
... img.StreamSource = new MemoryStream(bytes); <-- null 
... 
} 
bytes = null; // something like this - because why not? 

注意即使代碼如下順序和img.StreamSource = ...之前bytes = null;線,它實際上可能會以相反的順序執行(不確定性,因爲它可以運行在其他線程)。

你應該非常小心,這樣的捕獲將被異步執行/在其他線程上執行。更安全的選擇是建立內部獨立的方法匿名函數,所以你不能在以後更改捕獲變量:

Action CreateBitmapAction(bytes[] bytes) 
{ 
return() => 
{ 
    BitmapImage img = new BitmapImage(); 
    img.BeginInit(); 
    img.StreamSource = new MemoryStream(bytes); 
    img.EndInit(); 
    img_DownloadCompleted(img, webUrl); 
}; 
} 

Application.Current.Dispatcher.BeginInvoke(CreateBitmapAction(bytes)); 
+0

你的假設是正確的。在方法的最後一行,我有'bytes = null;'。我不知道匿名方法可以不按順序執行。將來我會用你的建議並把它放在一個包裝方法中。謝謝:) – Jan

+0

@Jan注意到「無序」與事實無關,這是匿名方法 - 它真的取決於委託/ lambda作爲參數來決定何時(如果有)調用提供的方法的函數。您還會發現LINQ(搜索「LINQ懶惰評估」)和事件處理程序(稍微容易理解 - 在添加「Click」處理程序時不會立即調用處理程序)的類似行爲。 –

1

這是由該方法創建一個封閉造成的。 它引用一個超出範圍的對象。阿列克謝的答案將解決這個問題。

,但如果你仍然wan't保留類似的語法將拉姆達在你的代碼,你可以做同樣的事情,像這樣:

var bytes = client.DownloadData(webUrl); 
    Application.Current.Dispatcher.BeginInvoke((Action<byte[]>)(b => 
    { 
     // draw a pink bunny , or what ever here. 
    }),bytes);