Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XML Documentation for dependency properties

What is the best way to document a dependency property?

Should I put the xml documentation on the field:

/// <summary>Documentation goes here</summary>
public static readonly DependencyProperty NameProperty = 
        DependencyProperty.Register(...)

or on the property:

/// <summary>and/or here?</summary>
public string Name{ get{...} set{...} }

or do I really need to document (and maintain) both?

like image 849
Stefan Avatar asked Oct 29 '10 16:10

Stefan


People also ask

What are dependency properties?

A dependency property can reference a value through data binding. Data binding works through a specific markup extension syntax in XAML, or the Binding object in code. With data binding, determination of the final property value is deferred until run time, at which time the value is obtained from a data source.

How do you create a dependency property?

To create new dependency property we need to follow the below procedure, Declare and register dependency property. For registered property set value using SetValue method and get value using GetValue method. Write a method to handle change done on dependency property.

What is the difference between property and dependency property?

The primary difference between a dependency droperty and a standard clr property is that a dependency property can be the target of a binding. This allows you to tie the value of the property to a value provided by some other object.

How do I set default value for dependency property?

When you define a custom XAML dependency property, one of the things you do is specify the default value. You can do this by providing the default value directly: DependencyProperty. Register("MyProperty", propertyType, ownerType, new PropertyMetadata(defaultValue));


2 Answers

Ok, this is what I've come up with.

I use a special xml tag at the dependency properties that will be replaced by an xsl transformation. It would be possible to do it without it, but then Visual Studio issues a warning because the field appears undocumented.

/// <dpdoc />
public static readonly DependencyProperty PositionProperty = 
    DependencyProperty.Register(...)

The C# property is documented as usual, just make sure not to forget the value description.

/// <summary>Gets or sets the position of this element</summary>
/// <value>Position (in pixel) relative to the parent's upper left corner.</value>
/// <remarks><para>
/// If either the <c>x</c> or <c>y</c> component is <c>+inf</c> this indicates...
/// </para></remarks>
public Point Position{ get{...} set{...} }

Visual studio creates an xml file from those comments during building. With a little xsl transformation the dpdoc node is replaced by a modified version of the property documentation. The resulting xml file is the same as if we nicely documented the property identifier. It even includes a short note that there is an alternative way of accessing the variable:

/// <summary>Position (in pixel) relative to the parent's upper left corner.</summary>
/// <remarks><para>
/// If either the <c>x</c> or <c>y</c> component is <c>+inf</c> this indicates...
/// <para>
/// This dependency property can be accessed via the <see cref="Position"/> property.
/// </para>
/// </para></remarks>
public static readonly DependencyProperty PositionProperty = 
    DependencyProperty.Register(...)

That way, both API's have proper documentation and we don't need to duplicate the documentation in the code. The xsl transformation can be done in the post-build events or be integrated in the documentation generation process.

Here's the xsl:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:template match="//dpdoc">
        <xsl:variable name="propertyName" select="concat('P:', substring(../@name,3,string-length(../@name)-10))" />
        <summary>
            <xsl:apply-templates select="//member[@name=$propertyName]/value/node()"/>
        </summary>
        <xsl:apply-templates select="//member[@name=$propertyName]/*[not(self::remarks)][not(self::summary)][not(self::value)]"/>
        <remarks>
            <xsl:apply-templates select="//member[@name=$propertyName]/remarks/node()"/>
            <para>
                This dependency property can be accessed via the
                <see>
                    <xsl:attribute name="cref"><xsl:value-of select="$propertyName"/></xsl:attribute>
                </see>
                property.
            </para>
        </remarks>
    </xsl:template>
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Why I want to have it that way:

  • Both the property identifier (the DependencyProperty instance) and the property, are public and can therefore legally be used to access the property. Thous we have two APIs to the same logical variable.
  • Code documentation should describe what is not already there to see. In this context it should describe the meaning of the property and its value and how to use it correctly. Since both, property identifier and the c# property, reference the same logical variable, they have the same meaning.
  • The user can freely choose one of the two ways to access the logical variable, and musn't be aware of the other. Thous both must be documented properly.
  • Copy-pasting code comments is just as bad as copy-pasting code.
like image 89
Stefan Avatar answered Sep 22 '22 17:09

Stefan


You should document and maintain both. One is the dependency property, the other is a regular property that just happens to be implemented as accessing that dependency property. They are not the same thing and require separate documentation.

like image 45
Jeff Yates Avatar answered Sep 24 '22 17:09

Jeff Yates