views:

94

answers:

1

I'm trying something along these lines.

//Somewhere in my app
 System.Uri resourceLocater = new System.Uri("/MyApp;component/Users.xaml", System.UriKind.Relative);
var obj = Application.LoadComponent(resourceLocater);

//Invoke the renderxaml element
var image=RenderXamlElement(obj as UserControl);

//Then I may save this image to a file..





//RenderXamlElement looks like this

byte[] RenderXamlElement(UserControl control)
            {
                Rect rect = new Rect(new Size(control.Width,control.Height));
                RenderTargetBitmap rtb = new RenderTargetBitmap((int)rect.Right,
                  (int)rect.Bottom, 96d, 96d, System.Windows.Media.PixelFormats.Default);
                rtb.Render(control);
                //endcode as PNG
                BitmapEncoder pngEncoder = new PngBitmapEncoder();
                pngEncoder.Frames.Add(BitmapFrame.Create(rtb));

                //save to memory stream
                System.IO.MemoryStream ms = new System.IO.MemoryStream();

                pngEncoder.Save(ms);
                ms.Close();
                return ms.ToArray();
            } 

The usercontrol's snapshot is not rendered properly. Any thoughts?

+1  A: 

What you want to do is use the VisualBrush class built into WPF. This should provide the functionality I think you're looking for.

VisualBrush class on MSDN

Cheers.

EDIT: Expanded answer for expanded question

This code snippet should put you in the right direction for saving the image to a file.

Stefan Wick's blog - Rendering ink and image to a bitmap using WPF

// render InkCanvas' visual tree to the RenderTargetBitmap
RenderTargetBitmap targetBitmap =
    new RenderTargetBitmap((int)inkCanvas1.ActualWidth,
                           (int)inkCanvas1.ActualHeight,
                           96d, 96d,
                           PixelFormats.Default);
targetBitmap.Render(inkCanvas1);

// add the RenderTargetBitmap to a Bitmapencoder
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(targetBitmap));

// save file to disk
FileStream fs = File.Open(fileName, FileMode.OpenOrCreate);
encoder.Save(fs);

EDIT: More code to try and demonstrate possible solution

The XAML:

<Page  
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
  x:Class="UsingVisualBrush.PaintingWithVisuals" >

    <StackPanel Name="MyStackPanel"  
                Orientation="Horizontal" 
                Margin="10" Background="White" 
                HorizontalAlignment="Left"  >
      <Rectangle Name="myRect" Width="150" Height="150" 
                 Stroke="Black" Margin="0,0,5,0" Loaded="UserControl_Loaded"  >
      </Rectangle>
    </StackPanel>
</Page>

Now the code behind...

namespace UsingVisualBrush
{
    public partial class PaintingWithVisuals : Page
    {
        public PaintingWithVisuals() 
        {

        }

        private void UserControl_Loaded(object sender, RoutedEventArgs args)
        {
            Uri resourceLocater = new Uri("/component/Users.xaml", UriKind.Relative);
            var obj = Application.LoadComponent(resourceLocater);

            // Using UserControl-derived class
            var mylocatedControl = obj as UserControl;
            mylocatedControl.Background = Brushes.Blue;
            mylocatedControl.Width = 20;
            mylocatedControl.Height = 20;

            // Using UserControl-derived class
            var myControl = new UserControl();
            myControl.Background = Brushes.Blue;
            myControl.Width = 20;
            myControl.Height = 20;

            // using UIElement-derived class
            var myVisualBrush = new VisualBrush();
            var panel = new StackPanel { Background = Brushes.Transparent };
//            panel.Children.Add(new TextBlock { Background = Brushes.Green, Foreground = Brushes.Black, FontSize = 10, Margin = new Thickness(10), Text = "Hello World from Dave" });
//            panel.Children.Add(myControl);
            panel.Children.Add((UserControl)obj);
            myVisualBrush.Visual = panel;
            ((UserControl)obj).Background = Brushes.Blue;
            myRect.Fill = myVisualBrush;
        }
    }
}

I hope this gets you a bit closer...

Dave White
Thank you for replying. How ever, I think my above code will also work with a Visual, like inkCanvas1. The problem is when loading a usercontrol using LoadComponent, and then creating an image out of that as described in the question.
amazedsaint
Looking at the C# code in the VisualBrush MSDN article, try replacing the assignment of the myStackPanel into the VisualBrush .Visual property with your UserControl that was loaded using LoadComponent. // Use myStackPanel as myVisualBrush's content. myVisualBrush.Visual = myStackPanel; // replace myStackPanel with "obj" from your example.
Dave White
@Dave, Thanks. Tried, but with no result
amazedsaint
@AmazedSaint, I'm not sure what the problem is. I haven't used the LoadComponent method but I've been able to programmatically create a textbox, place it into a stack panel, put it into a VisualBrush and then fill a rect with the VisualBrush.
Dave White
@Dave White thanks, got it working. The issue was, I was also expected to apply a scale transformation to the control. Appreciate your detailed response, marking it as answer.
amazedsaint