Обеспечение просмотра большого изображения во время выполнения - PullRequest
0 голосов
/ 30 сентября 2018

Вот проблема.У меня есть вид, который должен отображать изображение и некоторые элементы управления.Пользователь добавляет новые изображения, изменяет некоторые параметры и нажимает кнопку «Готово».Изображения большие и очень большие (400-1500 МБ 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 голосов
/ 30 сентября 2018

Вероятно, самый простой способ асинхронной загрузки изображения - это асинхронное связывание.Вам вообще не придется иметь дело с потоками или задачами.

<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;
        }
    }
}
0 голосов
/ 01 октября 2018

Другим вариантом будет использование привязки priorty с наивысшим приоритетом к полному изображению и более низким приоритетом для быстро загружаемого изображения предварительного просмотра.MS имеет документально подтвержденную приоритетную привязку здесь:

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

0 голосов
/ 30 сентября 2018

Как вы уже упоминали, вы блокируете поток пользовательского интерфейса при загрузке изображения.Вы можете использовать экземпляр класса WriteableBitmap в качестве источника для вашего изображения.Это позволит вам загрузить изображение в фоновом потоке или асинхронной задаче.Вот краткое руководство (не мое) по этому вопросу.

https://www.i -programmer.info /рограмма / wpf-workings / 527-writeablebitmap.html

...