Reputation: 2795
When you use the FontFamily property of the RichTextBox it changes the FontFamily of the whole content inside the FlowDocument. The same way you can Execute a command like EditingCommands.ToggleBold, where it only changes the word under the caret or just the new text to be written, there should be a way to do the same thing with the FontsFamilies, and Color.
Upvotes: 4
Views: 11879
Reputation: 286
Here is what i used to avoid overriding the richtextbox. This allows you to change to style of the selection if there is one, or change the style of the 'to be added' text after the caret. Hope it helps.
public static void SetFontSize(RichTextBox target, double value)
{
// Make sure we have a richtextbox.
if (target == null)
return;
// Make sure we have a selection. Should have one even if there is no text selected.
if (target.Selection != null)
{
// Check whether there is text selected or just sitting at cursor
if (target.Selection.IsEmpty)
{
// Check to see if we are at the start of the textbox and nothing has been added yet
if (target.Selection.Start.Paragraph == null)
{
// Add a new paragraph object to the richtextbox with the fontsize
Paragraph p = new Paragraph();
p.FontSize = value;
target.Document.Blocks.Add(p);
}
else
{
// Get current position of cursor
TextPointer curCaret = target.CaretPosition;
// Get the current block object that the cursor is in
Block curBlock = target.Document.Blocks.Where
(x => x.ContentStart.CompareTo(curCaret) == -1 && x.ContentEnd.CompareTo(curCaret) == 1).FirstOrDefault();
if (curBlock != null)
{
Paragraph curParagraph = curBlock as Paragraph;
// Create a new run object with the fontsize, and add it to the current block
Run newRun = new Run();
newRun.FontSize = value;
curParagraph.Inlines.Add(newRun);
// Reset the cursor into the new block.
// If we don't do this, the font size will default again when you start typing.
target.CaretPosition = newRun.ElementStart;
}
}
}
else // There is selected text, so change the fontsize of the selection
{
TextRange selectionTextRange = new TextRange(target.Selection.Start, target.Selection.End);
selectionTextRange.ApplyPropertyValue(TextElement.FontSizeProperty, value);
}
}
// Reset the focus onto the richtextbox after selecting the font in a toolbar etc
target.Focus();
}
Upvotes: 2
Reputation: 2795
Maybe not the neatest solution but the you can inherit from the RichTextBox and add some behavior
Declare your own Font Properties so you can bind them later with a List of Fonts
public class CustomControl1 : RichTextBox
{
public static readonly DependencyProperty CurrentFontFamilyProperty =
DependencyProperty.Register("CurrentFontFamily", typeof(FontFamily), typeof (CustomControl1), new FrameworkPropertyMetadata(new FontFamily("Tahoma"), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,new PropertyChangedCallback(OnCurrentFontChanged)));
}
Override the OnTextInput. You can't subscribe to this event on the RichTextBox has built-in handling for the bubbling of KeyDown and KeyUp and between them the TextInput is generated
protected override void OnTextInput(TextCompositionEventArgs e)
{
if (fontchanged)
{
TextPointer tp = this.CaretPosition.GetInsertionPosition(LogicalDirection.Forward);
Run r = new Run(e.Text, tp);
r.FontFamily = CurrentFontFamily;
r.Foreground = CurrentForeground;
this.CaretPosition = r.ElementEnd;
fontchanged = false;
}
else
base.OnTextInput(e);
}
if your CurrentFontProperty has changed get the caret position and create a new Run with the new Text Input and set the FontFamily = CurrentFontFamily. You could also change the whole word if the carret is over a word, this article might be interesting to spot the word Navigate Words in RichTextBox.
Upvotes: 4
Reputation: 37850
You'd use a RUN inside of the RichTextBox, something like:
<RichTextBox>
<Run FontFamily="Arial">My Arial Content</Run>
<Run FontFamily="Times" FontWeight="Bold">My bolded Times content</Run>
<Run>My Content that inherits Font From the RTB</Run>
</RichTextBox>
Ok, This gets to play with some low-level doo hickies. But here we go:
First, add a few ToggleButtons and a RichTextBox to a XAML Form. In the Rich Text Box, you'll give it a few Command Bindings in order to let the system know that everything works together.
Here's the XAML:
<RichTextBox Height="119" Name="RichTextBox1" Width="254" >
<RichTextBox.CommandBindings>
<CommandBinding Command="EditingCommands.ToggleBold" CanExecute="CommandBinding_CanExecute" ></CommandBinding>
<CommandBinding Command="EditingCommands.ToggleItalic" CanExecute="CommandBinding_CanExecute" ></CommandBinding>
</RichTextBox.CommandBindings>
</RichTextBox>
<ToggleButton MinWidth="40" Command="EditingCommands.ToggleBold" Height="23" HorizontalAlignment="Left" Name="Button1" VerticalAlignment="Top" Width="75" CommandTarget="{Binding ElementName=RichTextBox1}" >Bold</ToggleButton>
<ToggleButton MinWidth="40" Command="EditingCommands.ToggleBold" Height="23" HorizontalAlignment="Left" Name="Button2" VerticalAlignment="Top" Width="75" CommandTarget="{Binding ElementName=RichTextBox1}" >Italics</ToggleButton>
Now, what's there is a RichTextbox, and two toggle buttons, and the togglebuttons are related to the commandbindings to ToggleBold/ToggleItalics individually.
In the CODE side, I have these two methods:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
End Sub
Private Sub CommandBinding_CanExecute(ByVal sender As System.Object, ByVal e As System.Windows.Input.CanExecuteRoutedEventArgs)
e.CanExecute = True
End Sub
The BUTTON CLICK event handler is there because a button needs the event handler to be usable.
The CanExecute tells the button if the value is available for bolding or not (for example, you could check the length, and not attempt to bold if the RTB is empty).
Now, for really low-level control of things, you're going to have to be doing things in the RichTextFormat. Follow this link to find out more about that.
Upvotes: 1