Data See, Data Do

Mike Hillberg's Blog on Wpf and Silverlight

Tip: Using XamlWriter and XamlReader to clone an object

Tip: Using XamlWriter and XamlReader to clone an object

  • Comments 4

There are multiple ways to clone objects, and multiple definitions of what “clone” should even mean. 

 

The main issue is usually about cloning “deep” vs. “shallow”.  For example, if you have a Customer object that points to an Address object, and you clone the Customer object, does the Address object get cloned too (this would be a deep clone)?  Or does the new Customer reference the original Address object (a shallow clone)? 

 

Another issue is whether you clone just the properties of the object, or the fields instead.  And do you clone event listeners?

 

Yet another issue is that you might clone a property value on the object that is supposed to be unique, such as the Name property on WPF elements.

 

Anyway, here’s a trick to clone an object by writing it out to Xaml then reading it back in.  As such, the cloning rules it follows matches the Xaml serialization rules (see here for some more info).  That primarily means that it only clones public properties – no fields or events – and it clones deep.

 

So here’s what the code might look like:

 

private Object CloneUsingXaml(Object o)

{

    string xaml = XamlWriter.Save(o);

    return XamlReader.Load(new XmlTextReader(new StringReader(xaml)));

}

 

(XamlReader.Load doesn’t have an overload that takes a string, so you need to convert the string into an XmlReader.)

 

Here’s an example.  Take this app:

 

<Window x:Class="WPFApplication1.Window1"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="Window1" Height="300" Width="300" Loaded='OnLoaded'>

   

    <Grid Name='Grid1'>

            <Grid.ColumnDefinitions>

                  <ColumnDefinition Width="*"/>

                  <ColumnDefinition Width="*"/>

            </Grid.ColumnDefinitions>

   

            <Rectangle Name='_rectangle1' Fill='Red' Width='20' Height='20' />

       

    </Grid>

</Window>

 

… and clone the Rectangle during load with:

 

private void OnLoaded(object sender, RoutedEventArgs args)

{

    Rectangle rectangle2 = CloneUsingXaml(_rectangle1) as Rectangle;

 

    rectangle2.Name = null;

    Grid.SetColumn(rectangle2, 1);

    Grid1.Children.Add(rectangle2);

}

 

… and you get a Window with two rectangles.

 

Here’s what the intermediate Xaml looks like:

 

<Rectangle

  Fill="#FFFF0000"

  Name="_rectangle1"

  Width="20" Height="20"

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" />

 

Note here that the Name property got cloned, which isn’t what we want, so I removed the Name after running the clone.

 

  • PingBack from http://anoriginalidea.wordpress.com/2007/12/13/weird-science-defining-winforms-in-xaml/

  • @"(XamlReader.Load doesn’t have an overload that takes a string, so you need to convert the string into an XmlReader.)"

    WPF doesn't, but Silverlight does.  Unfortunately, the documentation for Silverlight's XamlReader.Load(string) overload is AWFUL.

    It's not obvious or mentioned anywhere in the Silverlight documentation, but it seems every string representation of xml passed into XamlReader.Load(string) must be prepended with the following C# string: @"<?Mapping XmlNamespace=""local"" ClrNamespace=""your-application-namespace"" Assembly=""your-assembly"" ?>"

    Even so, I've been having trouble getting it to correctly parse/use the xaml I supply it.

  • Are you sure this works? I am facing a big issue in loading controls having name -

    http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/ef97f8a1-2773-46a3-8133-d895c4486b12

    When I try to load my usercontrol having this rectange I get this exception-

    '_rectangle1' value cannot be assigned to property 'Name' of object 'System.Windows.Shapes.Rectangle'. Cannot register duplicate Name '_rectangle1' in this scope.  Error at object '_rectangle1', Line 1 Position 2088.

  • akjoshi -- Could you send me some sample code to take a look?

Page 1 of 1 (4 items)
Leave a Comment
  • Please add 2 and 6 and type the answer here:
  • Post