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.