How to link to specifc point within <remarks>?

Aug 20, 2008 at 10:22 PM

In the XML documentation of my C# project I've got some tables toward the end of the <remarks> section for a particular class, e.g. FooBar. I added an anchor just before that table like so:

    <para><a name="FeedbackCodes">The following table lists the feedback codes:</a></para>

A little higher up in the same <remarks> I have a link like this:

    (see <a href="#FeedbackCodes">Feedback codes</a>)

That works great as long as the resulting documentation is all on one page. Is there any way to link the "FeedbackCodes" anchor from other pages, e.g. the documentation of a method in another class? What I'm looking for is something like <see cref="T:FooBar#FeedbackCodes"> or some way of referencing page the anchor ends up on so I can use <a href="HowDoIFindThePageFooBarEndsUpOn.html#FeedbackCodes">

Is this possible? Or am I doing this totally wrong. I know how to link to other classes, properties, etc. but not how to link to specific spots within that documentation.


Aug 21, 2008 at 3:22 AM
Edited Aug 21, 2008 at 5:11 AM
>>Andrew: That works great as long as the resulting documentation is all on one page.
What you have done so far is purely HTML, there is no special compiler (C# or Sandcastle) feature used.

>>Andrew: Is this possible?
Now, what you want to archive, you can still without using the compiler features.

  1. The C# compiler will not allow you to use the anchor name "#..." in the links.
  2. The Sandcastle compiler will not resolve the "#..."
    (I have investigated this for the Conceptual help will need to confirm that for the Reference/API help).

So, the solution...I will suggest until the Sandcastle custom components (default or user provided once) can handle it, use the pure HTML.
That means you will  have to know the naming system of the pages involved.

Here is an example that will work, using purely HTML solution...

using System;

namespace ClassLibrary1
    /// <summary>
    /// Summary of Class2.
    /// </summary>
    /// <remarks>
    /// <para>
    /// Testing the use of links and anchors.
    /// </para>
    /// <para>
    /// There is an anchor <a name="FeedbackCodes">here</a>.
    /// </para>
    /// </remarks>
    public class Class2
using System; namespace ClassLibrary1 { /// <summary> /// Summary of Class1. /// </summary> /// <remarks> /// Jump to the other class, <a href="T_ClassLibrary1_Class2.htm#FeedbackCodes">Class2</a>. /// </remarks> public class Class1 { } }
Best regards,


Aug 21, 2008 at 3:24 AM
Edited Aug 21, 2008 at 3:27 AM
You can use an anchor tag and the generated page name plus the "#ID" suffix.  For example, if using GUID naming, you'd use the GUID name generated for the page (it's not actually a GUID but a hash in a GUID format so it will be constant unless the method signature changes).  You can look in the reflection.xml file after a build, find the member, and the filename will be listed there as an element.  An easier way is to view the help file, right click in the topic while viewing it and select Properties to get the page name from the address URL.  An example:

/// See <a href="html/6050981e-dc92-d345-7340-82ef98e899ed.htm#FeedbackCodes">Feedback codes</a>.

If you need to do the same thing in conceptual content it's much easier.  A custom ResolveConceptualLinksComponent is available built into the Sandcastle Help File Builder or available standalone that allows "#id" suffixes to be added to the target IDs in <link> elements.

Aug 21, 2008 at 4:59 PM
Paul, Eric, thanks for the replies. Sounds like I need to find out what the target page is named to make this work. I could put something like FIXTHISPAGEREFERENCELATER into my source and then search through the files at the end. It would be nice to automate this step.

If the GUID name is actually a hash, could I write a plugin that calculates the GUID for me? Generally speaking, these links will not be to members (in which case I'd use the "<see cref" mechanism but to specific points in the <remarks> or <summary> for a class. That's where I tend to put extra information for the overall use of the class.

I guess the other option would be to search through the files, build a table of all anchors and then fill those in another pass through the files. Should be pretty easy, actually.

Aug 21, 2008 at 7:11 PM
>>Andrew: If the GUID name is actually a hash, could I write a plugin that calculates the GUID for me?
You can look at the 
files to see how the naming is done. It contains a C# code for the naming.

>>Andrew: Should be pretty easy, actually.
I have plans to extend the current link component, still researching/collection information to better determine the requirements.
Hopefully, this need will be taken care of soon.

Dave of the DocProject also created a link component, I do not have idea on the issues solved by it,
you might wish to take a look.

Best regards,
Aug 21, 2008 at 7:39 PM
Edited Aug 21, 2008 at 7:39 PM
Hi Andrew, 

{Sandcastle Install Path}\ProductionTransforms\AddGuidFilenames.xsl contains the C# code for generating the GUID from the member IDs found in the reflection XML file.

You could use a custom tag in your XML documentation, like the following:

<mysee cref="M:Class.Member(System.String)" fragment="FeedbackCodes"/>

Add a reference in the presentation style's main_sandcastle.xsl transformation file to AddGuidFilenames.xsl using an xsl:import element or just copy the MSXSL code block into the file.

Then you can create a custom XSL template for the mysee element (search main_sandcastle.xsl for see[@cref] as an example) that uses the href value to generate a GUID by calling the imported C# code.  The template should generate a real HTML anchor using the GUID, with .htm and the specified fragment appended to the end.

The only problem with this approach is that you must enter the exact ID for the target API in the cref attribute.

Obviously you'll need some knowledge of XSL to get this working as well :)  Unfortunately I don't have time to write it myself right now, but if you like this approach let me know and I'll post it when I get some time (unless somebody else beats me to it ;).

- Dave
Aug 22, 2008 at 12:17 AM

Hi Dave,

Thanks for the suggestion - sounds like a good way to do it, I'll give it a try when I'm done with the actual documentation content. I also discovered how to use "friendly" names and I think it's workable to type in the exact name of the HTML file in the href attribute, especially if the file already exists from a previous build.



Aug 22, 2008 at 12:33 AM
Hi Paul, 

> Dave of the DocProject also created a link component

ResolveExternalLinksComponent was designed for configuring external links, so it wouldn't be appropriate to solve this issue.  Please continue with your plans to update ResolveReferenceLinksComponent  :)

- Dave
Aug 22, 2008 at 12:36 AM
Hi Andrew,

Using friendly names might be a better way, although it will typically suffer from builds breaking because file paths are too long.

- Dave