As happens most often, taking the time to explain your problem sometimes gives you a fresh look at a possible solution. Here's what I figured out. Hopefully this will help others.
Even though the Run class is sealed, the Span class is not. I added my own DocVerse class inherited from Span which contains my VerseIndex property.
In my View I handle the Tapped event on the RichTextColumns control and using GetPosition I can determine the correct Run that was Tapped. I can then search through my DocVerse classes to see which one contains that Run, giving my my Tapped "verse".
There is an issue with the RichTextColumns class related to the GetPositionFromPoint call. The 1st column is represented by the RichTextBlock, while the following overflow columns are RichTextBlockOverflow controls. Here is the Tapped handler that finds the Tapped "verse" and changes the FontWeight.
private void RichTextColumns_Tapped(object sender, TappedRoutedEventArgs e)
{
RichTextColumns control = sender as RichTextColumns;
Point pTapped = e.GetPosition(e.OriginalSource as UIElement);
TextPointer tp = null;
if (e.OriginalSource is RichTextBlock) // tapped in the 1st column
{
tp = control.RichTextContent.GetPositionFromPoint(pTapped);
}
else if (e.OriginalSource is RichTextBlockOverflow) // tapped in an overflow column
{
tp = (e.OriginalSource as RichTextBlockOverflow).GetPositionFromPoint(pTapped);
}
if (tp != null)
{
// find out which DocVerse (inherits from Span) contains the Run that was tapped
Run r = tp.Parent as Run;
foreach (DocVerse v in control.Verses)
{
if (v.Inlines.Contains(r))
{
v.FontWeight = FontWeights.Bold;
Debug.WriteLine(v.VerseIndex);
}
}
}
}