locked
how to customize XAML serialization in WPF designer RRS feed

  • Question

  • Hi to all!

    I have implemented a custom property value editor for Visual Studio WPF designer and stuck into one problem. My property editor edits my custom property type (say PropertyType) which is convertable to and from string. Property editor gets and sets the property's value in code, in ShowDialog method of DialogPropertyValueEditor class.

    So I have a xaml file with my custom control in it, and this control has a property of PropertyType. The value of this property is specified in XAML file as an attribute in a string representation. I select this control, go to the Properties window and edit this property with my custom property editor. Everything is OK till this moment, the property value is parsed successfully from the string attribute and passed to my property editor. But when I set the modified property's value in DialogPropertyValueEditor.ShowDialog, the WPF designer serializes this value to XAML as property element. It ignores the possibility of string conversion and loses some important data when serializing. I have tried introducing TypeConverter attribute on my PropertyType class, playing with System.ComponentModel.Design.Serialization namespace classes, but nothing works.

    The question is how can I get the WPF designer to serialize my property to attribute, using my custom string serialization?

     

    Friday, July 2, 2010 1:39 PM

All replies

  • Hi @Kiryushin Andrey

    I have spoken to one of our development team, and we think you should be able to use type converters to serialize the property back to a string. 

    It would help us to see a sample of the code & desired XAML you are trying to emit - if you would rather not post publicly feel free to drop me an email at mwthomas at microsoft dot com.

    Thanks

    Mark


    Mark Wilson-Thomas - Program Team - WPF & SL Designer for Visual Studio - posts are provided 'as-is'
    Friday, July 2, 2010 4:54 PM
  • Hi, Mark

    The project is rather large and interconnected, so I will show here only important code snippets. If you'll be unable to reproduce, I will extract the necessary code and send you the whole VS solution for reproducing problem.

    This is the type of the property being edited (marked with TypeConverterAttribute):

    [System.ComponentModel.TypeConverter(typeof(Path.Converter))]
    public sealed class Path : Lexem, GEst.ITree
    {
     internal LexemList innerList;
     private int entityID;
    
     public int EntityId
     {
    	get { ... }	
    	set { ... }
     }
     public Step this[int index]
     {
    	get { ... }
     }
    }
    

    The Path class contains an integer field (and property) EntityID and an internal collection of elements, which is accessible for reading through indexer and being edited by Add and Remove methods.

    This is the type converter (it is nested inside Path class):

    public class Converter : System.ComponentModel.TypeConverter
    {
    
     public override bool CanConvertFrom(
    	System.ComponentModel.ITypeDescriptorContext context,
    	Type sourceType)
     {
    	return Type.GetTypeCode(sourceType) == TypeCode.String;
     }
    
     public override bool CanConvertTo(
    	System.ComponentModel.ITypeDescriptorContext context,
    	Type destinationType)
     {
    	return Type.GetTypeCode(destinationType) == TypeCode.String;
     }
    
     public override object ConvertFrom(
    	System.ComponentModel.ITypeDescriptorContext context,
    	System.Globalization.CultureInfo culture, object value)
     {
    	// ... here goes string to Path conversion
     }
    
     public override object ConvertTo(
    	System.ComponentModel.ITypeDescriptorContext context,
    	System.Globalization.CultureInfo culture, object value, Type destinationType)
     {
    	// ... here goes Path to string conversion
     }
    }

    The Path class and its converter are contained in GEst.Common assembly. This assembly knows nothing about WPF or XAML, it is used on server side as well as on client side (not only for WPF clients).

    The GEst.UI.WPF assembly contains a control with a property of type Path:

    public class DbcTextBox : TextBox, IDataControl
    {
     public virtual Path DataPath
     {
    	get { return (Path)this.GetValue(DataPathProperty); }
    	set { this.SetValue(DataPathProperty, value); }
     }
    
     public static readonly DependencyProperty DataPathProperty =
    	DbcDp.DataPathProperty.AddOwner(typeof(DbcTextBox));
    }
    

    I also have a design-time assembly for this control, GEst.UI.WPF.Design. It contains an IProvideAttributeTable implementation:

    [assembly: ProvideMetadata(typeof(GEst.UI.WPF.Design.DesignMetadataProvider))]
    
    namespace GEst.UI.WPF.Design
    {
     public class DesignMetadataProvider : IProvideAttributeTable
     {
     public AttributeTable AttributeTable
     {
    	get
    	{
    	AttributeTableBuilder builder = new AttributeTableBuilder();
    	builder.AddCustomAttributes(
    		typeof(GEst.Expression.Path), 
    		PropertyValueEditor.CreateEditorAttribute(typeof(PathEditor)));
    	return builder.CreateTable();
    	}
     }
    }

    The PathEditor class inherits from Microsoft.Windows.Design.PropertyEditing.DialogPropertyValueEditor:

    public class PathEditor : DialogPropertyValueEditor
    {
     public PathEditor()
     {
    	this.InlineEditorTemplate = // here goes DataTemplate from resources;
     }
    
     public override void ShowDialog(
    	PropertyValue propertyValue, IInputElement commandSource)
     {
    	PathEditorControl control = new PathEditorControl();
    	control.Value = propertyValue.Value;
    	if (control.ShowDialog().GetValueOrDefault())
    	{
    		propertyValue.Value = control.Value;
    	}
     }
    }
    
    PathEditorControl is a window (inherited from System.Windows.Window) that provides a visual interface for editing Path instance.

    This is how the original XAML markup for DbcTextBox control looks:

    <dbc:DbcTextBox x:Name="_XML" DataPath="ENTITIES;XML" />
    

    When I go to Properties window, Visual Studio uses type converter to parse this string to Path object. I edit property value with my property editor and this is what I get:

     

    <dbc:DbcTextBox x:Name="_XML">
     <dbc:DbcTextBox.DataPath>
     <my:Path EntityId="1" />
     </dbc:DbcTextBox.DataPath>
    </dbc:DbcTextBox>
    

    The "my" prefix is added to the root element of the xaml to reference GEst.Expression.Path instance.

    So, when saving property value to xaml, WPF designer ignores existing TypeConverter and writes property value as xml element. In addition, only EntityId property is written, all the data in internal Path object's collection is lost.

    Please give me know if you need a whole project with all mentioned classes to reproduce this situation. I'll extract the code and create such a project if needed.

    Monday, July 5, 2010 9:56 AM
  • Hallo, Mark!

    I have sent you a mail with the small solution containing all the necessary code for reproducing the problem with XAML serialization. Hope you'll give me some advice about how to solve or workaround this problem.

    Thanks in advance,

    Kiryushin Andrey

    Tuesday, July 13, 2010 8:46 AM
  • While Mark is going to try the solution you have sent him, you may want to try defining the Path and PathtypeConverter in a different assembly from where you want to use it. In other words, put Path and PathTypeConverter in one project and reference that in another where you have your XAML. Let us know if that makes a difference.


    Marco Goertz \ Sr. Dev Lead \ WPF/SL Designer "Cider" \ Microsoft
    Thursday, July 15, 2010 3:21 PM
  • Hi Marco

    Unfortunately this is how it is done now. The Path class and its type converter are defined an a separate assembly from where XAML is located.

    Monday, July 19, 2010 10:06 AM
  • I know this is very old, and I hope you found a solution before this but in case you haven't I had a similar problem.  I found that if you create a non-public constructor for your class it will serialize as a string.  That is if you create this

    internal Path()
    {
    }

    It will use your type converter's string format.

    • Proposed as answer by petersj Wednesday, January 5, 2011 7:54 PM
    Wednesday, January 5, 2011 5:58 PM
  • hi.

    im interested in that issue.

    but cant apply your advice.

    what i must to do to get things work?

    internal constructor advice gives me error "Property value is not valid  " and  "cannot create as instance of Complex" when i choose value from combobox ComplexNumber in property window.



    i used this example

    http://msdn.microsoft.com/en-us/library/bb546926.aspx



    Monday, June 6, 2011 6:56 AM