문제

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.

도움이 되었습니까?

해결책

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>
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top