Hallo,
da ich die Problematik hatte, dass ich Content aus unserer WPF-Anwendung in L&L als Custom-Designer-Objekt einbinden wollte (wir benutzen WPF-Charts eines anderen Herstellers), schrieb ich angehängten Konverter, der das System.Drawing.Graphics-Objekt aus dem “DrawDesignerObject”-Callback befüllen kann.
Ich bin sicher, dass das auch jemand anders gut gebrauchen kann.
Viele Grüße
Alex
P.S.: diese Klasse arbeitet mit unsafe-Code, also muss das entsprechend in der enthaltenden Assembly erlaubt werden!
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
namespace WpfApplication3
{
public static class WpfToWinForms
{
public static void DrawFrameworkElementOnGraphics (System.Drawing.Graphics graphics,
System.Drawing.Rectangle clipRectangle, FrameworkElement element)
{
bool limitedResolution;
System.Drawing.Image img = Convert (element, clipRectangle.Width, clipRectangle.Height,
true, out limitedResolution);
if (img != null)
{
graphics.DrawImage (img, clipRectangle.X, clipRectangle.Y, clipRectangle.Width, clipRectangle.Height);
}
}
/// <summary>
/// Renders the specified FrameworkElement to a System.Drawing.Image.
/// </summary>
/// <param name="controlToRender">The control which has to be rendered.
/// Be careful: if this is visible and rendered, its layout may change when allowRearrange is 'true'.</param>
/// <param name="allowRearrange">If false, the FrameworkElement will not be rearranged. It will then get
/// exactly the layout which it already has on the screen (and might be blurry!). Use this if you provided
/// an element/instance which is already arranged on the screen to prevent that layout to be damaged.
/// In most other cases this value should be true!</param>
/// <param name="ResolutionWasLimited">If true is returned, the resulting image does not have the resolution
/// which was specified because the dimensions are too large (but aspect-ratio is reserved).</param>
public static System.Drawing.Image Convert (FrameworkElement controlToRender, int width, int height,
bool allowRearrange, out bool ResolutionWasLimited)
{
ResolutionWasLimited = false;
// The number of pixels which are allowed for the result-image
// Note: on my machine there was an OutOfMemoryException with values higher than ~34,8 MPixel (~138,9 MB)
int RESOLUTION_LIMIT = 20000000; // Still leads to good results
if (width * height > RESOLUTION_LIMIT)
{
double ratio = (double) width / (double) height;
double tempHeight = Math.Sqrt ((double) RESOLUTION_LIMIT / ratio);
width = (int) Math.Round (ratio * tempHeight);
height = (int) Math.Round (tempHeight);
ResolutionWasLimited = true;
}
Size size = new Size ((double) width, (double) height);
RenderTargetBitmap renderTargetBmp;
try
{
if (allowRearrange)
{
// Rearrange the element and apply a scale so that the element will fit completely into the given size
controlToRender.Measure (new Size (double.PositiveInfinity, double.PositiveInfinity));
Size originalWpfSize = controlToRender.DesiredSize;
double factor = Math.Min ((double) width / originalWpfSize.Width, (double) height / originalWpfSize.Height);
controlToRender.LayoutTransform = new ScaleTransform (factor, factor);
controlToRender.Arrange (new Rect (
((double) width - originalWpfSize.Width * factor) / 2d, ((double) height - originalWpfSize.Height * factor) / 2d,
originalWpfSize.Width * factor, originalWpfSize.Height * factor));
renderTargetBmp = new RenderTargetBitmap (width, height, 96, 96, PixelFormats.Pbgra32);
renderTargetBmp.Render (controlToRender);
}
else
{
// Render into an image
Size originalWpfSize = new Size (controlToRender.ActualWidth, controlToRender.ActualHeight);
RenderTargetBitmap intermediateRenderTargetBmp = new RenderTargetBitmap (
(int) originalWpfSize.Width, (int) originalWpfSize.Height, 96, 96, PixelFormats.Default);
intermediateRenderTargetBmp.Render (controlToRender);
Image wpfImage = new Image ();
wpfImage.Source = intermediateRenderTargetBmp;
wpfImage.Stretch = Stretch.Uniform;
wpfImage.Measure (size);
wpfImage.Arrange (new Rect (new Point (0d, 0d), size));
// The image will stretch into the specified size
renderTargetBmp = new RenderTargetBitmap (width, height, 96, 96, PixelFormats.Default);
renderTargetBmp.Render (wpfImage);
}
}
catch
{
double res = ((double) width * height) / 1000000d;
double mem = res * 4;
Console.WriteLine ("!!!!!!!! Too less memory with resolution of " + res.ToString () +
" MPixel (" + mem.ToString () + " MB)");
return null;
}
// Conversion via bit-copy (needs the assembly to allow unsafe code)
byte[] bits = new byte[4 * width * height];
int stride = 4 * width;
renderTargetBmp.CopyPixels (bits, stride, 0);
System.Drawing.Image result;
unsafe
{
fixed (byte* pBits = bits)
{
IntPtr ptr = new IntPtr (pBits);
result = new System.Drawing.Bitmap (width, height, stride,
System.Drawing.Imaging.PixelFormat.Format32bppPArgb, ptr);
}
}
return result;
}
}
}