I have created a very simple WPF Window consisting of a Grid containing one RichTextBox
and one ComboBox
. I use the ComboBox
for changing and looking up the font size of the RichTextBox
selection.
Here's the code-behind file of my XAML:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Add the font sizes.
for (var i = 1; i < 72; i++)
{
FontSize.Items.Add((double) i);
}
}
private void MyTextBox_SelectionChanged(object sender, RoutedEventArgs e)
{
// If the selection changes, update the font size in the ComboBox.
FontSize.SelectedValue = (double) MyTextBox.Selection.GetPropertyValue(TextBlock.FontSizeProperty);
}
private void FontSize_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// If the selected size changes, change the size of the selection in the RichTextBox.
if (FontSize.SelectedItem != null)
MyTextBox.Selection.ApplyPropertyValue(TextBlock.FontSizeProperty, FontSize.SelectedItem);
}
}
There are two things here:
MyTextBox_SelectionChanged
updates the ComboBox
with the font size of the selection.FontSize_SelectionChanged
changes the font size of the selection.You can see the problem below:
When I make a selection and change the font size, it changes perfectly. But the moment I click on another text with a different font size it changes back again.
What is causing this behavior?
Edit: Here's the XAML file:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ComboBox x:Name="FontSize" HorizontalAlignment="Left" VerticalAlignment="Top" Width="497" Margin="10,10,0,0" SelectionChanged="FontSize_SelectionChanged"/>
<RichTextBox x:Name="MyTextBox" HorizontalAlignment="Left" Height="273" VerticalAlignment="Top" Width="497" Margin="10,37,0,0" RenderTransformOrigin="0.358,0.48" SelectionChanged="MyTextBox_SelectionChanged">
<FlowDocument>
<Paragraph>
<Run Text="RichTextBox"/>
</Paragraph>
</FlowDocument>
</RichTextBox>
</Grid>
</Window>
Edit 2: Here's the short explanation of what I did when I was debugging it:
MyTextBox_SelectionChanged
, and one at FontSize_SelectionChanged
.MyTextBox_SelectionChanged
is called. The Selection.Text
is empty.FontSize_SelectionChanged
. But still the Selection.Text
is empty, but my older selection "Rich" returns back to the old font size.Edit 3: This problem is mentioned in Sams Teach Yourself WPF in 24 Hours first printing July 2008, page 135, "Making the Text Editor Work as Expected", item 9. I didn't understand the explanation there and created a short sample illustrating that specific problem.
What seems to be happening is that when you click to clear the selection, this causes your TextBox.SelectionChanged
event handler (MyTextBox_SelectionChanged
) to be invoked while the Selection
represents an empty selection (i.e., just an insertion point). Your handler sets the combo box's SelectedValue
, using the empty selection's font size, which is a perfectly reasonable thing to do even if the selection is empty. (The insertion point still has a font size.)
Changing the SelectedValue
of course causes your ComboBox.Selection
event handler (FontSize_SelectionChanged
) to run. And because that event handler has no easy way to distinguish between an event caused by the user selecting a new value, and the event being caused by your code changing the SelectedValue
property, it goes ahead and attempts to modify the selection's font size, which you probably don't want to be doing in this particular case.
Even so, you'd think it'd be OK, because the selection is empty, and you're just attempting to set its font size to be whatever its font size already is. But here's the weird thing: when you call ApplyPropertyValue
on this empty selection, it appears to set the FontSize
for the entire document.
So the effect is that when you click to clear the selection, your code sets the entire document's font size to be whatever the font size is at the point where you click.
I suspect that's a bug in ApplyPropertyValue
, because it only happens if the text you select initially was selected by dragging from left to right, starting at the very first character. Then again, it's not entirely clear what the behaviour is meant to be if you apply formatting to an empty selection. So perhaps this is more just a case of invoking undefined behaviour rather than hitting a definite bug in WPF.
In any case, a reasonable way to fix this is by modifying your combo box change handler:
if (FontSize.SelectedItem != null && !MyTextBox.Selection.IsEmpty)
{
MyTextBox.Selection.ApplyPropertyValue(
TextBlock.FontSizeProperty, FontSize.SelectedItem);
}
This only attempts to change the selection's font size if the selection is non-empty.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With