Get the scroll position from a RichTextBox?
I've created a highlighting mechanism for a RichTextBox in Silverlight 4. It'll get character positions and draw rectangle(s) over the text.
The trouble I ha开发者_如何学JAVAve now is with scrolling on the RichTextBox. As I scroll all of my precious highlighting gets left behind. Is there any way I can add an event handler to a scroll event and/or a scrolling position of the RichTextBox? Or is there some better way in which I can link the position of the highlighting rectangles to the RichTextBox?
The trick would be to get what ever panel (I guess its a Canvas?) that you are overlaying the RichTextBox with to actually exist within the same ScrollViewer
that rich text exists in.
The following is very rough idea but should get you on the path to reasonable solution.
You can do this using a custom style for the RichTextBox
. The default style for this control can be found here.
Copy this style into a resource in your containing UserControl and point your RichTextBox
Style
property at it. So far nothing is different but now you can play about with the template. The relevant portion currently looks like this:-
<Border x:Name="MouseOverBorder" BorderThickness="1" BorderBrush="Transparent">
<ScrollViewer x:Name="ContentElement" Padding="{TemplateBinding Padding}" BorderThickness="0" IsTabStop="False" />
</Border>
Now we can tweak it like this:-
<Border x:Name="MouseOverBorder" BorderThickness="1" BorderBrush="Transparent">
<ScrollViewer Padding="{TemplateBinding Padding}" BorderThickness="0" IsTabStop="False">
<Grid>
<ContentControl x:Name="ContentElement" />
<Canvas x:Name="HighlightOverlay" />
</Grid>
</ScrollViewer>
</Border>
You'll note that we've moved the name "ContentElement" from the ScrollViewer
to the new ContentControl
. Having a FrameworkElement
called "ContentElement" is the only feature that the RichTextBox stipulates about its template.
Now overlaying this ContentControl
we can place a Canvas
where you can place your highlighting rectangles. If the user scrolls this RichTextBox
the whole Grid
containing both the Content and the Highlights will scroll together.
The only remaining trick is acquiring the "HighlightOverlay" so that you can add your rectangle to it. Here is some code that will grab it:-
private Canvas HightlightOverlay;
public MyUserControl()
{
InitializeComponent();
MyRichText.LayoutUpdated += MyRichText_LayoutUpdated;
}
void MyRichText_LayoutUpdated(object sender, EventArgs e)
{
HightlightOverlay = MyRichText.Descendents()
.OfType<Canvas>()
.FirstOrDefault(elem => elem.Name == "HighlightOverlay");
}
You will be wondering where the Descendents
method is coming from, it is here.
Anthony W Jones came up with a brilliant solution. There were just a couple tweaks to the XAML I had to make.
As suggested I started with this inside the template:
<Border x:Name="MouseOverBorder" BorderThickness="1" BorderBrush="Transparent">
<ScrollViewer Padding="{TemplateBinding Padding}" BorderThickness="0" IsTabStop="False">
<Grid>
<ContentControl x:Name="ContentElement" />
<Canvas x:Name="HighlightOverlay" />
</Grid>
</ScrollViewer>
</Border>
But the ContentControl messed things up somehow and you can't actually type into the RichTextBox anymore. Also, the scroll bars weren't showing up.
But I found the two changes necessary to make this work:
<Border x:Name="MouseOverBorder" BorderBrush="Transparent" BorderThickness="1">
<ScrollViewer BorderThickness="0" IsTabStop="False" Padding="{TemplateBinding Padding}" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Grid>
<Grid x:Name="ContentElement" />
<Canvas x:Name="HighlightOverlay" />
</Grid>
</ScrollViewer>
</Border>
Adding HorizontalScrollBarVisibility="Auto"
and VerticalScrollBarVisibility="Auto"
brought the scroll bars back, and simply using Grid
instead of the ContentControl
made the RichTextBox editable again.
精彩评论