我需要不要阻止用戶界面,而我使用WPF繪製很多簡單的形狀。在後臺線程上的WPF DrawingVisual?
在WinForms中,我將設置後臺緩衝區並在後臺線程上繪製到緩衝區,然後將得到的緩衝區繪製到控件中。它工作得很好。在WPF中,我已經嘗試過使用DrawingVisual,但它似乎在組成繪圖時阻塞UI線程。
如何將DrawingVisual.RenderOpen()下的所有內容移動到後臺線程,以便在UI線程處於工作狀態時不會被阻止?
我需要不要阻止用戶界面,而我使用WPF繪製很多簡單的形狀。在後臺線程上的WPF DrawingVisual?
在WinForms中,我將設置後臺緩衝區並在後臺線程上繪製到緩衝區,然後將得到的緩衝區繪製到控件中。它工作得很好。在WPF中,我已經嘗試過使用DrawingVisual,但它似乎在組成繪圖時阻塞UI線程。
如何將DrawingVisual.RenderOpen()下的所有內容移動到後臺線程,以便在UI線程處於工作狀態時不會被阻止?
我想添加一種方法來繪製一個VisualBrush DrawingBrush在其他線程。
正如我們所知,VisualBrush應該在UI線程中使用,而VisualBrush不能在其他線程中使用Freeze。
如果要在其他線程中使用VisualBrush並將其繪製到DrawingVisual,則應將VisualBrush更改爲Image。
要改變VisualBrush以圖片作爲代碼:
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並顯示圖像。
你應該WIRTE的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;
元素是我們的CustomControl,它有一個屬性來獲取它的位置。
但是它對於Dispatcher.InvokeAsync來說不是一個好方法,需要太長時間。
DwayneNeed使用HostVisual繪製畫筆,但當畫筆是在UI線程中的VisualBrush時,您不會在其他線程中繪製它。 – lindexi 2017-06-21 02:47:09