gpt4 book ai didi

.net - 后台线程上的 WPF DrawingVisual?

转载 作者:行者123 更新时间:2023-12-04 12:24:37 24 4
gpt4 key购买 nike

当我使用 WPF 绘制许多简单的形状时,我不需要阻止 UI。

在 WinForms 中,我会设置后台缓冲区并绘制到后台线程上的缓冲区,然后将生成的缓冲区绘制到控件。它运作良好。

在 WPF 中,我尝试过使用 DrawingVisual,但它似乎在编写绘图时阻塞了 UI 线程。

我如何将 DrawingVisual.RenderOpen() 下的所有内容移动到后台线程上,以便在它工作时 UI 线程不会被阻塞?

最佳答案

我想添加一种在其他线程中将 VisualBrush 绘制到 DrawingBrush 的方法。

众所周知,VisualBrush 应该在 UI 线程中使用,而 VisualBrush 不能卡住,不能在其他线程中使用。

如果要在其他线程中使用 VisualBrush 并将其绘制到 DrawingVisual ,则应将 VisualBrush 更改为 Image。

要将 VisualBrush 更改为 Image 作为代码:

  public static BitmapSource ToImageSource(this Brush brush, Size size, double dpiX, double dpiY)
{
DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
drawingContext.DrawRectangle(brush, (Pen) null, new Rect(size));
BitmapImage bitmapImage = new BitmapImage();
if (Math.Abs(size.Width) > 0.001 && Math.Abs(size.Height) > 0.001)
{
RenderTargetBitmap bitmap = new RenderTargetBitmap((int) (size.Width * dpiX / 96.0), (int) (size.Height * dpiY / 96.0), dpiX, dpiY, PixelFormats.Pbgra32);
bitmap.Render((Visual) drawingVisual);
bitmapImage.BeginInit();
bitmapImage.DecodePixelWidth = (int) (size.Width * dpiX / 96.0);
bitmapImage.DecodePixelHeight = (int) (size.Height * dpiY / 96.0);
bitmapImage.StreamSource = (Stream) bitmap.ToMemoryStream(ImageFormat.Png);
bitmapImage.EndInit();
bitmapImage.Freeze();
}
return (BitmapSource) bitmapImage;
}

你可以在其他线程中绘制它。
     var drawVisual=VisualBrush.ToImageSource(drawBounds.Size the drawBounds is we give, Dpix you can write 96, Dpiy);
Thread thread = new Thread(() =>
{
var target = new VisualTarget(hostVisual);
s_event.Set();

var dv = new DrawingVisual();

using (var dc = dv.RenderOpen())
{
dc.DrawRectangle(new ImageBrush(drawVisual), new Pen(Brushes.Black, 0.0), drawBounds);

}
target.RootVisual = dv;
}

但是,如果您应该将一些 VisualBrush 绘制到 DrawingVisual 并将 DrawingVisual 更改为 bitmapImage 并显示图像。

您应该将 VsisualBrush 写入 UIThread 中的图像
        List<(ImageSource brush, Rect drawBounds)> drawVisual = new List<(ImageSource, Rect)>();
foreach (var temp in Elements)
{
UIElement element = temp;
Rect descendantBounds = VisualTreeHelper.GetDescendantBounds(element);

var drawBounds = descendantBounds;
drawBounds.Offset(temp location - new Point());

await Dispatcher.InvokeAsync(() =>
{
var brush = new VisualBrush(element);

drawVisual.Add((brush.ToImageSource(drawBounds.Size, Dpix, Dpiy), drawBounds));
}, DispatcherPriority.Input);
}

对于 VisualTaget 应该使用 Visual ,如何将 DrawingVisual 更改为 BitmapImage 并显示它?
       HostVisual hostVisual = new HostVisual();
List<(ImageSource brush, Rect drawBounds)> drawVisual = new List<(ImageSource, Rect)>();
foreach (var temp in Elements)
{
Element element = temp;
Rect descendantBounds = VisualTreeHelper.GetDescendantBounds(element);

var drawBounds = descendantBounds;
drawBounds.Offset(temp.Bounds.Location - new Point());

await Dispatcher.InvokeAsync(() =>
{
var brush = new VisualBrush(element);

drawVisual.Add((brush.ToImageSource(drawBounds.Size, Dpi.System.X, Dpi.System.Y), drawBounds));
}, DispatcherPriority.Input);
}

Thread thread = new Thread(() =>
{
var target = new VisualTarget(hostVisual);
s_event.Set();

var dv = new DrawingVisual();

using (var dc = dv.RenderOpen())
{
foreach (var temp in drawVisual)
{
dc.DrawRectangle(new ImageBrush(temp.brush), new Pen(Brushes.Black, 0.0), temp.drawBounds);
}
}

var bounds = VisualTreeHelper.GetDescendantBounds(dv);
var width = (int) Math.Round(bounds.Width);
var height = (int) Math.Round(bounds.Height);

var bitmap = new RenderTargetBitmap((int) Math.Round(width * Dpi.System.FactorX),
(int) Math.Round(height * Dpi.System.FactorY), Dpi.System.X, Dpi.System.Y,
PixelFormats.Pbgra32);

bitmap.Render(dv);

dv = new DrawingVisual();
using (var dc = dv.RenderOpen())
{
dc.DrawImage(bitmap, new Rect(size));
}
target.RootVisual = dv;

System.Windows.Threading.Dispatcher.Run();
});

thread.TrySetApartmentState(ApartmentState.STA);

thread.IsBackground = true;
thread.Start();

s_event.WaitOne();
VisualHost.Child = hostVisual;

Element 是我们的 CustomControl,它有一个属性来获取它的位置。

但它不是一个好方法 Dispatcher.InvokeAsync 需要太长时间。

关于.net - 后台线程上的 WPF DrawingVisual?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6084585/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com