Рисование изображения в окне и его обновление - PullRequest
0 голосов
/ 06 ноября 2018

У меня есть небезопасный класс, который генерирует растровое изображение, которое преобразуется в ToImageSource для рисования в окне. Сам растровое изображение содержит синусоидальный текст, который часто обновляется, и я хочу, чтобы он «двигался» слева направо (стиль выделения?). В любом случае, в WinForm все работает нормально, но я застрял в окне WPF.

Вот несколько примеров кода:

public AboutWindow()
{
    InheritanceBehavior = InheritanceBehavior.SkipAllNow;
    InitializeComponent();
    Initialize();
}

protected override void OnRender(DrawingContext drawingContext)
{
    base.OnRender(drawingContext);

    drawingContext.DrawImage(bitmapRender.WindowBitmap, drawingArea);

    if (!worker.IsBusy) 
        worker.RunWorkerAsync(); // BackgroundWorker in charge of updating the bitmap
}

void DispatcherTimerRender_Tick(object sender, EventArgs e) => InvalidateVisual();

Мои проблемы: в окне ничего не отображается, и DispatchedTimer, который вызывает InvalidateVisual (), приводит к этому исключению:

System.InvalidOperationException: 'Невозможно использовать объект DependencyObject, принадлежащий другому потоку, чем его родительский Freezable.'

Я смотрел на другие темы и знаю, что WPF - это сохраненная система рисования, но я бы все равно хотел ее достичь.

Есть ли какие-либо предложения о "лучшем" способе достижения этого?

Буду очень признателен за любое полезное объяснение / ссылку.

[Редактировать]

<Window x:Class="CustomerManagement.View.AboutWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
       mc:Ignorable="d" Height="450" WindowStartupLocation="CenterScreen" Width="800" ResizeMode="NoResize" AllowsTransparency="True" WindowStyle="None">
    <Grid KeyDown="Grid_KeyDown">
        <Image Width="800" Height="450" Source="{Binding 'Image'}" />
    </Grid>
</Window>

1 Ответ

0 голосов
/ 06 ноября 2018

Вы должны использовать элемент Image, у которого свойство Source связано со свойством ImageSource в модели представления. Это «стандартный» способ, основанный на архитектурном паттерне MVVM, и, следовательно, «лучший» - на мой взгляд.

<Image Source="{Binding Image}"/>

Модель вида может выглядеть так:

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private ImageSource image;
    public ImageSource Image
    {
        get { return image; }
        set
        {
            image = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Image)));
        }
    }
}

и его экземпляр будет присвоен DataContext окна:

public AboutWindow()
{
    InitializeComponent();

    var vm = new ViewModel();
    DataContext = vm;
}

Для тестирования, приведенный ниже код выполняет слайд-шоу файлов изображений в каталоге. Вы также можете назначить любой другой ImageSource - например, DrawingImage - для свойства Image.

var imageFiles = Directory.GetFiles(..., "*.jpg");
var index = -1;
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };

timer.Tick += (s, e) =>
{
    if (++index < imageFiles.Length)
    {
        vm.Image = new BitmapImage(new Uri(imageFiles[index]));
    }
    else
    {
        timer.Stop();
    }
};

timer.Start();
...