将 WPF ScrollViewer 内容导出为单独的 PNG
Export WPF ScrollViewer content as separate PNGs
在我的 WPF 应用程序中,我有一个 ScrollViewer
,它由 DataBinding
和 UserControl
动态填充。想象一下,我的 UserControl
是一个简单的东西,只包含一个标签,标签中显示的值来自一个列表。所以当我 运行 应用程序时,它看起来像下面这样:
如您所见,UserControl
有多个实例,每个实例都具有动态填充的不同值。我的目标是将每个 UserControls
导出为单独的 PNG。我的 EXPORT PNG
按钮点击应该这样做。
所以我环顾四周,发现 this example 可以很好地导出 ScorllViewer
.
的全部内容
所以我尝试修改它以实现我的目标,并且我确实让它在一定程度上起作用,但不是我想要的。
这是我的代码:
private void ExportPNG()
{
var dir = Directory.GetCurrentDirectory();
var file = "ITEM_{0}.PNG";
var height = 100.0; // Height of the UserControl
var width = mainSV.ActualWidth;
for (int i = 1; i <= ItemList.Count; i++)
{
var path = System.IO.Path.Combine(dir, string.Format(file, i));
Size size = new Size(width, height);
UIElement element = mainSV.Content as UIElement;
element.Measure(size);
element.Arrange(new Rect(new Point(0, 0), size));
RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32);
VisualBrush sourceBrush = new VisualBrush(element);
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
using (drawingContext)
{
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(width, height)));
}
renderTarget.Render(drawingVisual);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderTarget));
using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write))
{
encoder.Save(stream);
}
}
}
现在导出 5 个 PNG(当我的列表有 5 个项目时),但它们都包含第一个元素的图像:
而且我认为问题可能出在我执行 drawingContext.DrawRectangle()
的地方,因为我的矩形坐标始终相同。所以我尝试将其更改为以下内容,我认为这应该可行,但由于某种原因,它只生成一个 PNG,其中包含第一个 UserControl
和 4 个空 PNG。
using (drawingContext)
{
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, (i-1) * height), new Point(width, height + ((i-1) * height))));
}
结果:
我做错了什么?
如果您想运行代码请find it here。
请检查以下两种方法。我测试了它,它工作得很好。
1.首先,从你的Items控件中找到children
2. 将它们转换为 PNG。
private void ExportPNG()
{
var dir = Directory.GetCurrentDirectory();
var file = "ITEM_{0}.PNG";
var height = 100.0;
var width = 100.0;
var children = GetChildrenOfType<UCDisplayItem>(itC);
foreach (var item in children)
{
var path = System.IO.Path.Combine(dir, string.Format(file, DateTime.Now.Ticks));
Size size = new Size(width, height);
UIElement element = item as UIElement;
element.Measure(size);
element.Arrange(new Rect(new Point(0, 0), size));
RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32);
VisualBrush sourceBrush = new VisualBrush(element);
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
using (drawingContext)
{
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(width, height)));
//drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, (i - 1) * height), new Point(width, height + ((i - 1) * height))));
}
renderTarget.Render(drawingVisual);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderTarget));
using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write))
{
encoder.Save(stream);
}
}
}
public List<T> GetChildrenOfType<T>( DependencyObject depObj)
where T : DependencyObject
{
var result = new List<T>();
if (depObj == null) return null;
var queue = new Queue<DependencyObject>();
queue.Enqueue(depObj);
while (queue.Count > 0)
{
var currentElement = queue.Dequeue();
var childrenCount = VisualTreeHelper.GetChildrenCount(currentElement);
for (var i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(currentElement, i);
if (child is T)
result.Add(child as T);
queue.Enqueue(child);
}
}
return result;
}
在我的 WPF 应用程序中,我有一个 ScrollViewer
,它由 DataBinding
和 UserControl
动态填充。想象一下,我的 UserControl
是一个简单的东西,只包含一个标签,标签中显示的值来自一个列表。所以当我 运行 应用程序时,它看起来像下面这样:
如您所见,UserControl
有多个实例,每个实例都具有动态填充的不同值。我的目标是将每个 UserControls
导出为单独的 PNG。我的 EXPORT PNG
按钮点击应该这样做。
所以我环顾四周,发现 this example 可以很好地导出 ScorllViewer
.
所以我尝试修改它以实现我的目标,并且我确实让它在一定程度上起作用,但不是我想要的。
这是我的代码:
private void ExportPNG()
{
var dir = Directory.GetCurrentDirectory();
var file = "ITEM_{0}.PNG";
var height = 100.0; // Height of the UserControl
var width = mainSV.ActualWidth;
for (int i = 1; i <= ItemList.Count; i++)
{
var path = System.IO.Path.Combine(dir, string.Format(file, i));
Size size = new Size(width, height);
UIElement element = mainSV.Content as UIElement;
element.Measure(size);
element.Arrange(new Rect(new Point(0, 0), size));
RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32);
VisualBrush sourceBrush = new VisualBrush(element);
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
using (drawingContext)
{
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(width, height)));
}
renderTarget.Render(drawingVisual);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderTarget));
using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write))
{
encoder.Save(stream);
}
}
}
现在导出 5 个 PNG(当我的列表有 5 个项目时),但它们都包含第一个元素的图像:
而且我认为问题可能出在我执行 drawingContext.DrawRectangle()
的地方,因为我的矩形坐标始终相同。所以我尝试将其更改为以下内容,我认为这应该可行,但由于某种原因,它只生成一个 PNG,其中包含第一个 UserControl
和 4 个空 PNG。
using (drawingContext)
{
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, (i-1) * height), new Point(width, height + ((i-1) * height))));
}
结果:
我做错了什么?
如果您想运行代码请find it here。
请检查以下两种方法。我测试了它,它工作得很好。 1.首先,从你的Items控件中找到children 2. 将它们转换为 PNG。
private void ExportPNG()
{
var dir = Directory.GetCurrentDirectory();
var file = "ITEM_{0}.PNG";
var height = 100.0;
var width = 100.0;
var children = GetChildrenOfType<UCDisplayItem>(itC);
foreach (var item in children)
{
var path = System.IO.Path.Combine(dir, string.Format(file, DateTime.Now.Ticks));
Size size = new Size(width, height);
UIElement element = item as UIElement;
element.Measure(size);
element.Arrange(new Rect(new Point(0, 0), size));
RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32);
VisualBrush sourceBrush = new VisualBrush(element);
DrawingVisual drawingVisual = new DrawingVisual();
DrawingContext drawingContext = drawingVisual.RenderOpen();
using (drawingContext)
{
drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(width, height)));
//drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, (i - 1) * height), new Point(width, height + ((i - 1) * height))));
}
renderTarget.Render(drawingVisual);
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(renderTarget));
using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write))
{
encoder.Save(stream);
}
}
}
public List<T> GetChildrenOfType<T>( DependencyObject depObj)
where T : DependencyObject
{
var result = new List<T>();
if (depObj == null) return null;
var queue = new Queue<DependencyObject>();
queue.Enqueue(depObj);
while (queue.Count > 0)
{
var currentElement = queue.Dequeue();
var childrenCount = VisualTreeHelper.GetChildrenCount(currentElement);
for (var i = 0; i < childrenCount; i++)
{
var child = VisualTreeHelper.GetChild(currentElement, i);
if (child is T)
result.Add(child as T);
queue.Enqueue(child);
}
}
return result;
}