0

For a third party product I need to convert a ContentControl to a Bitmap. Which I thought is no problem because a ContentControl is a UIElement which can be rendered in a Bitmap.

But if I plot this Bitmap than there is no image visible.

It seems that it does not work because I have the contentControl in my Application Resources and if I try to load it it is found but all properties are null or in exception status. What is going wrong here?

This is my contentControl

<ContentControl x:Key="LocationMarker" Width="356" Height="524">
<Canvas Width="356" Height="524">
  <Path Width="355.912" Height="524.355" Canvas.Left="0" Canvas.Top="-0.354675" Stretch="Fill" Fill="{DynamicResource HeaderColorBrush}" Data="...."/>
  <Path Width="150" Height="200" Canvas.Left="100" Canvas.Top="50" Stretch="Fill" Fill="{DynamicResource HeaderColorBrush}" Data="..."/>
  <Path Width="200" Height="170" Canvas.Left="78" Canvas.Top="300" Stretch="Fill" Fill="{DynamicResource HeaderColorBrush}" Data="..."/>
</Canvas>

Thats how I try to get it:

var contentControl = Application.Current.Resources.MergedDictionaries.SelectMany(x => x.MergedDictionaries).FirstOrDefault(x => x.Source.OriginalString.Contains("ContentControls.xaml"))?["LocationMarker"] as ContentControl;
  if (contentControl != null)
  {
    var renderTargetBitmap = new RenderTargetBitmap(41, 74, 96, 96, PixelFormats.Pbgra32);
    renderTargetBitmap.Render(contentControl);
    var encoder = new PngBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
    var stream = new MemoryStream();
    encoder.Save(stream);}

Is a contentControl maybe the wrong type? Is the way of getting it by Resources wrong?

thats how it looks in the debugger: debugger screenshot

Every tip is appreciated!

Nelly
  • 522
  • 6
  • 15
  • why not to `Application.Current.FindResource("LocationMarker") as ContentControl `? – vasily.sib Sep 27 '18 at 10:02
  • Try to actually load the ContentControl so you can see it, before saving to bitmap. See if there is a difference. This method captures what you saw (ignore those visibility is invisible), it doesn’t capture what is not in the VisualTree. – kennyzx Sep 27 '18 at 10:22
  • @ vasily, thanks that way looks much better, but too bad it does not change the problem – Nelly Sep 27 '18 at 11:07
  • @kennyzx I don't know exactly how you mean to do it, but I think the object I load from the resources, the contentcontrol is not good, because beside what you see in the debugger, if I save the bitmap it has also a size of 0 kb. But I don't understand why he loads such a strange object from the resources... is that a kind of threading issue? – Nelly Sep 27 '18 at 11:29
  • I mean you can only save a UIElement if it is visible on the screen. So you need to load the control to a Grid, or Canvas... and be sure it is not hidden, or outside of the screen. You cannot just create a control in memory and save it to a WritableBitmap. Read the docs of the Render method, it is explained in detailed. – kennyzx Sep 27 '18 at 11:34
  • You are right, I come closer to the solution but still don't understand how to solve it. If I use the contentControl normal in xaml it is visible and looks good. And if I take the contentControl from code behind the debugger now know width and height and there are no excpetions anymore, But If I take this object and try to render it as a bitmap and save it on my machine nothing is visible... – Nelly Sep 27 '18 at 12:34

1 Answers1

1

This works for me, notice the Measure and Arrange call added to your original code.

var contentControl = Resources["LocationMarker"] as ContentControl;
if (contentControl != null)
{
    contentControl.Measure(new Size(356, 524));
    contentControl.Arrange(new Rect(new Size(356, 524)));
    var target = new RenderTargetBitmap(
        (int)contentControl.RenderSize.Width, (int)contentControl.RenderSize.Height,
        96, 96, PixelFormats.Pbgra32);
    target.Render(contentControl);

    var encoder = new PngBitmapEncoder();
    var outputFrame = BitmapFrame.Create(target);
    encoder.Frames.Add(outputFrame);

    using (var file = File.OpenWrite("TestImage.png"))
    {
        encoder.Save(file);
    }
}

Code is adopted from this answer.

kennyzx
  • 12,845
  • 6
  • 39
  • 83