在运行时将大图像显示到视图中

时间:2018-09-30 13:35:49

标签: c# wpf image mvvm large-files

这是问题所在。 我有一个视图,应该显示一个图像和一些控件。 用户添加新图像,更改某些选项,然后单击“完成”。 图像很大而且非常大(400-1500 MB Tiff) 用户应该看到图像的预览,但是如果加载10到15秒甚至更长的时间是可以的,那么他这次有工作。 图像通过MVVM模式进行绑定,就像简单的字符串一样(文件始终位于本地文件夹中)

<Image Name="ImagePreview" Source="{Binding SFilePathForPreview,
         FallbackValue={StaticResource DefaultImage},
         TargetNullValue={StaticResource DefaultImage}}"
         HorizontalAlignment="Center" Width="200" Height="200"
         VerticalAlignment="Center" />

问题是,当用户尝试添加文件以进行加载时,所有内容都将挂起。 我知道这种情况应该通过多线程解决-但不知道如何实现。

我试图像这样从不同线程的视图中更新图像:

Thread newThread = new Thread(LazyLoad);
newThread.Name = "LazyLoad";
newThread.Start(SFilePathForPreview);

public void LazyLoad(object SFilePath)
{            
    try
    {
        string path = (string)SFilePath;

        BitmapImage t_source = new BitmapImage();

        t_source.BeginInit();
        t_source.UriSource = new Uri(path);
        t_source.DecodePixelWidth = 200;
        t_source.EndInit();

        t_source.Freeze();
        this.Dispatcher.Invoke(new Action(delegate
        {
            ImagePreview.Source = t_source;
        }));
    }
    catch
    {
        //...
    }
}

但是无论如何

  

ImagePreview.Source = t_source;

一切都将挂起,直到图像完全加载。

是否可以在后台加载预览并显示这些预览而不会造成可怕的挂起?

3 个答案:

答案 0 :(得分:0)

如前所述,您正在通过图像加载来阻止UI线程。您可以使用WriteableBitmap类实例作为Image的源。这将使您将图像加载到后台线程或异步任务上。这是有关此问题的快速指南(不是我的)。

https://www.i-programmer.info/programming/wpf-workings/527-writeablebitmap.html

答案 1 :(得分:0)

异步加载图像的最简单的方法可能是通过异步绑定。您完全不必处理线程或任务。

<Image Source="{Binding Image, IsAsync=True}"/>

可能的视图模型如下图所示,必须确保可以从后台线程调用Image属性获取器。

public class ViewModel : ViewModelBase
{
    private string imagePath;
    private BitmapImage image;

    public string ImagePath
    {
        get { return imagePath; }
        set
        {
            imagePath = value;
            image = null;
            OnPropertyChanged(nameof(ImagePath));
            OnPropertyChanged(nameof(Image));
        }
    }

    public BitmapImage Image
    {
        get
        {
            lock (this)
            {
                if (image == null &&
                    !string.IsNullOrEmpty(imagePath) &&
                    File.Exists(imagePath))
                {
                    using (var stream = File.OpenRead(imagePath))
                    {
                        image = new BitmapImage();
                        image.BeginInit();
                        image.CacheOption = BitmapCacheOption.OnLoad;
                        image.DecodePixelWidth = 200;
                        image.StreamSource = stream;
                        image.EndInit();
                        image.Freeze();
                    }
                }
            }

            return image;
        }
    }
}

答案 2 :(得分:-1)

另一种选择是使用优先级绑定,其优先级最高的是完整图像,而优先级较低的是加载速度更快的预览图像。 MS已在此处记录了优先级绑定:

https://docs.microsoft.com/en-us/dotnet/framework/wpf/data/how-to-implement-prioritybinding