我有一个不安全的类,该类会生成位图,该位图将转换为ToImageSource以便绘制到Window中。位图本身包含一个经常更新的正弦文本,我希望它从左向右“移动”(字幕样式?)。无论如何,它在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();
我的问题是:窗口上没有任何显示,并且调用InvalidateVisual()的DispatchedTimer导致此异常:
System.InvalidOperationException:“不能使用与其父Freezable属于不同线程的DependencyObject。”
我看过其他线程,我知道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>
答案 0 :(得分:1)
您应该使用在视图模型中将其Source属性绑定到ImageSource属性的Image元素。我认为,这是基于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();