2016-12-11 50 views
1

我有一個靜態類,它包含文件擴展名和BitMapSource對象的字典。該類包含一個函數,如果FileInfo對象返回關聯的BitMapSource對象,如果該對象不在字典中,它將得到它並在返回之前將其放入字典中。
從GUI線程執行時,此工作正常。但是,當我嘗試將它放在後臺線程中時,我沒有收到任何迴應。有沒有任何理由,我不應該能夠從後臺線程執行此操作?具有靜態類的異步函數

靜態類

namespace Test.Classes 
{ 
    using System.Collections.Generic; 
    using System.Drawing; 
    using System.IO; 
    using System.Windows; 
    using System.Windows.Interop; 
    using System.Windows.Media.Imaging; 

    public static class IconMap 
    { 
    private static Dictionary<string, BitmapSource> iconDictionary = new Dictionary<string, BitmapSource>(); 

    public static BitmapSource GetFileIcon(FileInfo fileInfo) 
    { 
     if (iconDictionary.ContainsKey(fileInfo.Extension)) 
     { 
     return iconDictionary[fileInfo.Extension]; 
     } 
     else 
     { 
     lock (iconDictionary) 
     { 
      Icon icon = Icon.ExtractAssociatedIcon(fileInfo.FullName); 
      BitmapSource bitMapSource = Imaging.CreateBitmapSourceFromHIcon(icon.Handle, new Int32Rect(0, 0, icon.Width, icon.Height), BitmapSizeOptions.FromEmptyOptions()); 
      iconDictionary.Add(fileInfo.Extension, bitMapSource); 
      return bitMapSource; 
     } 
     } 
    } 
    } 
} 

Control.cs

namespace Test.Controls 
{ 
    using System; 
    using System.Diagnostics; 
    using System.IO; 
    using System.Threading.Tasks; 
    using System.Windows.Controls; 
    using System.Windows.Input; 
    using System.Windows.Media.Imaging; 
    using Microsoft.Office.Interop.Outlook; 

    public partial class AttachedFileInfo : UserControl 
    { 
    private FileInfo file; 

    public AttachedFileInfo(FileInfo fileInfo) 
    { 
     this.InitializeComponent(); 
     this.file = fileInfo; 

     this.FileLink.NavigateUri = new Uri(fileInfo.FullName); 
     this.FileName.Text = fileInfo.Name; 
     this.LoadFileIcon(fileInfo); 
    } 

    private async void LoadFileIcon(FileInfo fileInfo) 
    { 
     Task<BitmapSource> getFileIconTask = Task<BitmapSource>.Factory.StartNew(() => 
     { 
     // If I change this to BitmapSource icon = null; it works as expected. 
     BitmapSource icon = Classes.IconMap.GetFileIcon(fileInfo); 
     return icon; 
     }); 
     await getFileIconTask; 

     this.FileIcon.Source = Classes.IconMap.GetFileIcon(fileInfo); 
     // getFileIconTask.Result; 
    } 

    private void FileLink_RequestNavigate(object sender, System.Windows.Navigation.RequestNavigateEventArgs e) 
    { 
     Process.Start(this.file.FullName); 
    } 
    } 
} 
+2

從字典中同時讀取和寫入是不安全的。使用'ConcurrentDictionary'或用'ReaderWriterLockSlim'封裝訪問以在寫入時阻止併發讀取器。 –

+0

謝謝。我沒有意識到ConcurrentDictionary對象。我改變了我的字典,並改變了添加到TryAdd,但它似乎並沒有解決問題。 – JtM

+0

BitmapSource是一個DependencyObject,這意味着它只能由創建它的線程使用。 –

回答

2

你的圖標不顯示,因爲WPF資源只能從另一個線程使用,如果他們是通過調用.Freeze()法凍結(見代碼如下)。

另一個問題是,即使使用ConcurrentDictionary,它仍然可能發生一個線程將圖標添加到iconDictionary並且當它離開鎖定的代碼塊時,另一個線程可能會進入鎖定的塊,但GetFileIcon()方法不是線程安全的並將相同文件類型的圖標添加到字典中,導致出現ArgumentException。因此,在鎖定中,您必須再次測試特定擴展名的圖標是否已經存在於字典中。

private static ConcurrentDictionary<string, BitmapSource> iconDictionary = new ConcurrentDictionary<string, BitmapSource>(); 

public static BitmapSource GetFileIcon(FileInfo fileInfo) 
{ 
    BitmapSource bitMapSource; 
    if (iconDictionary.TryGetValue(fileInfo.Extension, out bitMapSource)) 
    { 
     return bitMapSource; 
    } 
    else 
    { 
     lock (iconDictionary) 
     { 
      if (iconDictionary.TryGetValue(fileInfo.Extension, out bitMapSource)) 
       return bitMapSource; 

      Icon icon = Icon.ExtractAssociatedIcon(fileInfo.FullName); 
      bitMapSource = Imaging.CreateBitmapSourceFromHIcon(icon.Handle, new Int32Rect(0, 0, icon.Width, icon.Height), BitmapSizeOptions.FromEmptyOptions()); 
      bitMapSource.Freeze();//Allows BitmapSource to be used on another thread 
      iconDictionary[fileInfo.Extension] = bitMapSource; 
      return bitMapSource; 
     } 
    } 
} 
+0

謝謝。我正在把我的頭髮撕掉,而且我沒有太多的開始。 – JtM

相關問題