我想显示与文件关联的图标。 对于与普通桌面应用程序相关联的文件types,这不是问题,而只适用于与(metro / modern)应用程序相关的文件types。
如果文件types与应用程序关联, 并且使用AsParallel()
,则只会获取默认的未知文件types图标。 为了说明,我不会得到null
或图标,而是显示空白纸张的默认图标。 没有AsParallel()
我得到正确的图标。
我尝试了其他几种方法来获取图标,例如, SHGetFileInfo()
或通过dll直接调用ExtractAssociatedIcon()
。 行为总是一样的。
示例 :如果“Adobe Acrobat”是PDF文件的默认应用程序,则在这两种情况下我都会得到正确的Adobe PDF图标。 如果Windows 8或10中的内置(现代UI)应用程序“Reader”是默认应用程序,则在应用AsParallel()
时,将获得未知文件types图标。
XAML:
<Window x:Class="FileIconTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <StackPanel> <TextBox x:Name="TxtFilename" Text="x:\somefile.pdf"/> <Button Click="Button_Click">Go</Button> <Image x:Name="TheIcon" Stretch="None"/> </StackPanel> </Window>
相应的代码:
private void Button_Click(object sender, RoutedEventArgs e) { var list = new List<string>(); list.Add(TxtFilename.Text); var icons = list.AsParallel().Select(GetIcon); // problem with apps // var icons = list.Select(GetIcon); // works always TheIcon.Source = icons.First(); } public static ImageSource GetIcon(string filename) { var icon = System.Drawing.Icon.ExtractAssociatedIcon(filename); var iSource = Imaging.CreateBitmapSourceFromHIcon(icon.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); iSource.Freeze(); return iSource; }
使用说明:只使用两种变体中的一种。 如果两者都执行,即使有不同的variables,问题可能是不可重现的。
这是因为SHGetFileInfo
(或ExtractAssociatedIcon
,内部使用SHGetFileInfo
)只适用于STA线程(单线程单元)。 在MTA线程(多线程单元)上,它只是返回默认图标。 AsParallel
使用来自线程池(MTA)的工作线程。
托马斯的答案基本上是正确的,使用STA线程解决了这个问题。 知道了问题的原因, 这个答案暗示我在正确的方向。 通过使用STA线程的TaskScheduler,我可以使用Parallel.ForEach()
来运行我的代码。
从这里的StaTaskScheduler
(更多信息: MSDN博客文章 ),下面的代码解决了我的问题。
var list = new List<string>(); list.Add(TxtFilename.Text); var ts = new StaTaskScheduler(Environment.ProcessorCount); // can be saved for later reuse var icons = new ConcurrentBag<ImageSource>(); var pOptions = new ParallelOptions { TaskScheduler = ts }; Parallel.ForEach(list, pOptions, file => icons.Add(GetIcon(file))); TheIcon.Source = icons.First();