实施说明:
在每个 CompositionTarget.Rendering 事件中,我使用Writablebitmap绘制4个相邻的行, (这是"实时"线图的绘图仪。)
问题:
这很有效,直到UI-Thread看起来很忙,然后是下一个 CompositionTarget.Rendering 事件需要更长时间才能解雇。
问题:
是否有一些机制可以保持一个恒定的渲染间隔,该间隔优先于任何其他UI操作?
可能的灵魂:
我正在考虑创建一个HostVisual ,以及如何为它分配一个DispatcherTimer,
这种方法会起作用吗?
我想到的任何其他方法?
提前谢谢。答案 0 :(得分:3)
如果您已经渲染到WritableBitmap中,为什么不在ThreadPool上分离异步任务? WritableBitmap支持来自不同线程的更新,检查例如this question或the class documentation remarks上的信息。或者只是运行自己的线程,如果线程池不是你的东西。通过这种方式,您可以控制时间,除了同步图像之外,不需要依赖UI线程进行任何其他操作。
以下是我刚刚编写的一些原始示例代码,可以让您了解我的意思:
public partial class MainWindow : Window
{
private WriteableBitmap mImage;
private bool mShutdown;
private object mUpdateLock = new object();
private IntPtr mBuffer;
private int mStride;
public MainWindow()
{
InitializeComponent();
mImage = new WriteableBitmap(10, 2, 96, 96, PixelFormats.Bgr32, null);
wImage.Source = mImage;
Closed += delegate {
CompositionTarget.Rendering -= CompositionTarget_Rendering;
lock (mUpdateLock)
{
mShutdown = true;
mImage.Unlock();
}
};
mImage.Lock();
mBuffer = mImage.BackBuffer;
mStride = mImage.BackBufferStride;
CompositionTarget.Rendering += CompositionTarget_Rendering;
UpdateAsync();
}
private void CompositionTarget_Rendering(object sender, EventArgs e)
{
lock (mUpdateLock)
{
// for a large image you can optimize that by only updating the parts that changed,
// collect dirty-areas in a list or something (while under the lock of course!)
mImage.AddDirtyRect(new Int32Rect(0, 0, 10, 2));
mImage.Unlock();
mImage.Lock();
// I don't know if these can changes, but docs say to acquire them after locking ...
mBuffer = mImage.BackBuffer;
mStride = mImage.BackBufferStride;
}
}
private async void UpdateAsync()
{
int x = 0;
int y = 0;
int color = 0xFF0000;
for (; ;)
{
lock (mUpdateLock)
{
if (mShutdown)
return;
// feel free to do 'unsafe' code here if you know what you're doing
Marshal.WriteInt32(new IntPtr(mBuffer.ToInt64() + x * 4 + y * mStride), color);
}
if (++x == 10)
{
x = 0;
if (++y == 2)
{
y = 0;
color ^= 0xFF00FF;
}
}
await Task.Delay(500).ConfigureAwait(false);
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Thread.Sleep(2000);
}
}
和相应的XAML
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="Slow" HorizontalAlignment="Left" VerticalAlignment="Top" Click="Button_Click"/>
<Image x:Name="wImage"/>
</Grid>
</Window>