WPF - 渲染"实时"最佳实践

时间:2014-05-25 10:10:43

标签: c# wpf multithreading rendering

实施说明:

在每个 CompositionTarget.Rendering 事件中,我使用Writablebitmap绘制4个相邻的行, (这是"实时"线图的绘图仪。)

问题:

这很有效,直到UI-Thread看起来很忙,然后是下一个 CompositionTarget.Rendering 事件需要更长时间才能解雇。

问题:

是否有一些机制可以保持一个恒定的渲染间隔,该间隔优先于任何其他UI操作?

可能的灵魂:

我正在考虑创建一个HostVisual ,以及如何为它分配一个DispatcherTimer,
这种方法会起作用吗?

我想到的任何其他方法?

提前谢谢。

1 个答案:

答案 0 :(得分:3)

如果您已经渲染到WritableBitmap中,为什么不在ThreadPool上分离异步任务? WritableBitmap支持来自不同线程的更新,检查例如this questionthe 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>