0

我正在尝试使用 IMultiValueConverter 在另一个线程中提取图标,即使这在另一个项目中有效,但它在这里不起作用。IsAsync=True 会在没有 FullPath 值的情况下启动转换器,并且 IsAsync=False 会阻止 UI,尤其是在从 .lnk 文件中提取图标时。

<Image>
  <Image.Source>
   <MultiBinding Converter="{StaticResource Fullpath2Icon}"   >
    <MultiBinding.Bindings>
      <Binding RelativeSource="{RelativeSource Self}"  />
      <Binding Path="FullPath" IsAsync="True"  />
    </MultiBinding.Bindings>
  </MultiBinding>
 </Image.Source>
</Image>


public class Fullpath2IconConverter : IMultiValueConverter
{
  public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  {
    System.Windows.Controls.Image image = values[0] as System.Windows.Controls.Image;
    if (values[1] == null) return null;
    string mypath = values[1] as string;

    ThreadPool.QueueUserWorkItem((WaitCallback)delegate
    {
      image.Dispatcher.Invoke(DispatcherPriority.Normal,
            (ThreadStart)delegate {
                image.Source = System.Drawing.Icon.ExtractAssociatedIcon(mypath).IconToImageSource();

您能解释一下原因或提出任何改进方法吗?

编辑: 我创建了一个类扩展图像,现在它看起来像这样:

<local:cIconImage Path="{Binding FullPath}"></local:cIconImage>

public class cIconImage : System.Windows.Controls.Image
    {
        public cIconImage()
        {
            //this.Loaded += new RoutedEventHandler(cIconImage_Loaded);
            Dispatcher.BeginInvoke(DispatcherPriority.Input, new ThreadStart(() =>
            {
                Source = GetImage();
            }));
        }

现在填充列表要好得多,并且每个图标都在提取时出现,但是在较长的 .lnk 提取过程中 UI 仍然被锁定。

4

1 回答 1

0

Convert 方法中设置 Image 控件的 Source 属性没有任何意义。更不用说在单独的线程中立即调用 Dispatcher.Invoke。

在 Source 属性上使用简单的绑定,如下所示:

<Image Source="{Binding FullPath, Converter={StaticResource Fullpath2Icon}}">

和一个简单地返回转换结果的单值转换器:

public class Fullpath2IconConverter : IValueConverter
{
    public object Convert(
        object value, Type targetType, object parameter, CultureInfo culture)
    {
        var mypath = value as string;
        return System.Drawing.Icon.ExtractAssociatedIcon(mypath).IconToImageSource();
    }

    ...
}

更新:为了异步加载许多图标图像,您应该绑定到ObservableCollection<ImageSource>视图模型中的一个(没有转换器)并从后台线程填充该集合。请注意,图像是在后台线程中创建的,因此必须被冻结。

public class ViewModel
{
    public ViewModel()
    {
        Icons = new ObservableCollection<ImageSource>();
    }

    public ObservableCollection<ImageSource> Icons { get; set; }

    public void LoadIconsAsync()
    {
        ThreadPool.QueueUserWorkItem(o =>
        {
            foreach (var path in paths)
            {
                var image = System.Drawing.Icon.ExtractAssociatedIcon(mypath).IconToImageSource();
                image.Freeze();

                Application.Current.Dispatcher.Invoke(
                    new Action(() => Icons.Add(image)));
            }
        });
    }
}
于 2014-01-22T16:12:14.807 回答