views:

77

answers:

1

I am creating a class that inherits from System.Windows.Documents.Paragraph and adds a new collection property. Here is a very simplified representation of that class:

public class ExtendedParagraph : Paragraph
{
    public Dictionary<string, string> Attributes { get; set; }
}

I need to create and populate an instance of the above class from within Xaml, which requires a markup syntax that allows the content of the paragraph and the members of its Attributes collection to be declared separately.

Since the Paragraph class is decorated with the attribute [ContentProperty("Inlines")], I assume I need to explicitly populate the Inlines and the Attributes collections. Based on the Xaml syntax I have seen used to solve similar challenges elsewhere, I envisage something like this:

<ExtendedParagraph xmlns="clr-namespace:MyNamespace">
    <ExtendedParagraph.Inlines>

        This is where the paragraph content goes

    </ExtendedParagraph.Inlines>
    <ExtendedParagraph.Attributes>

        This is where the members of the Attributes property are declared 

    </ExtendedParagraph.Attributes>
</ExtendedParagraph>

However, this approach presents two problems:

[1] When the above Xaml is parsed using XamlReader, it fails with the message "ExtendedParagraph.Inlines property has already been set and can only be set once"

[2] I am not sure what markup I should use to declare instances of KeyValuePair within the Attributes element.

I hope somebody can point me in the right direction.

Many thanks, Tim

Edit - I have found the answer to question [1]. It simply entails declaring the Attributes collection (using property element syntax) first, followed by the content of the Paragraph:

<ExtendedParagraph xmlns="clr-namespace:MyNamespace">
    <ExtendedParagraph.Attributes>

        This is where the members of the Attributes property are declared 

    </ExtendedParagraph.Attributes>
    This is where the paragraph content goes
</ExtendedParagraph>

However, declaratively adding members to a Dictionary<TKey, TValue> is proving more difficult. I found a few clues in this post, but I haven't yet achieved a working result. Your ideas are still welcome.

+1  A: 

I'm not sure whether it's OK to answer my own question but, since nobody else seems to know, I'll share the solution I have adopted.

Apparently, support for generics in Xaml is limited, which means there is no native Xaml machamism to populate a Dictionary<TKey, TValue> (or any other generic collection class).

However, as this article describes, it is possible to create a custom markup extension class and, once configured to suit the collection member type, it will successfully populate a collection property declaratively:

<ExtendedParagraph.Attributes>
    <generic:DictionaryOfT TypeArgument="sys:String">
        <generic:DictionaryOfT.Items>
            <sys:String x:Key="String1">Hello</sys:String>
            <sys:String x:Key="String2">World</sys:String>
        </generic:DictionaryOfT.Items>
    </generic:DictionaryOfT>
</ExtendedParagraph.Attributes>
Tim Coulter