Я должен установить семейство шрифтов для следующего текста, который будет записан в RichTextBox. Я пытался установить это с...
<RichTextBox x:Name="RichTextEditor" MaxWidth="1000" SpellCheck.IsEnabled="True"
FontFamily="{Binding ElementName=TextFontComboBox, Path=SelectedItem}"
FontSize="{Binding ElementName=TextSizeComboBox, Path=SelectedValue}"
Width="Auto" Height="Auto" HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto" />
... но это изменило целый текст. Я предполагаю, что со свойством Selection могу ограничить изменение, которое будет применено только к выбранной области. Но как для следующего - еще напечатанный текст?
Чтобы установить FontFamily на основе позиции курсора, вам необходимо определить настраиваемый элемент управления со свойством зависимости, которое помогает вставить новый раздел Run путем переопределения метода OnTextInput.
Я включил большую часть кода, вам нужно изменить пространства имен, чтобы они соответствовали вашей среде разработки.
Код использует ViewModel для управления доступными шрифтами и управления изменением шрифта. Этот код является только прототипом и не решает проблем с фокусировкой между двумя элементами управления.
Чтобы использовать этот код:
1- Введите текст в RichTectBox.
2- Измените шрифт в ComboBox.
3- Вернитесь в RichTextBox.
4- Введите еще текст.
Вот настраиваемый элемент управления RichTextBox:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace RichTextboxFont.Views
{
public class RichTextBoxCustom : RichTextBox
{
public static readonly DependencyProperty CurrentFontFamilyProperty =
DependencyProperty.Register("CurrentFontFamily",
typeof(FontFamily), typeof
(RichTextBoxCustom),
new FrameworkPropertyMetadata(new FontFamily("Tahoma"),
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
new PropertyChangedCallback(OnCurrentFontChanged)));
public FontFamily CurrentFontFamily
{
get
{
return (FontFamily)GetValue(CurrentFontFamilyProperty);
}
set
{
SetValue(CurrentFontFamilyProperty, value);
}
}
private static void OnCurrentFontChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{}
protected override void OnTextInput(TextCompositionEventArgs e)
{
ViewModels.MainViewModel mwvm = this.DataContext as ViewModels.MainViewModel;
if ((mwvm != null) && (mwvm.FontChanged))
{
TextPointer textPointer = this.CaretPosition.GetInsertionPosition(LogicalDirection.Forward);
Run run = new Run(e.Text, textPointer);
run.FontFamily = this.CurrentFontFamily;
this.CaretPosition = run.ElementEnd;
mwvm.FontChanged = false;
}
else
{
base.OnTextInput(e);
}
}
}
}
Вот XAML:
<Window x:Class="RichTextboxFont.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:RichTextboxFont.Views"
xmlns:ViewModels="clr-namespace:RichTextboxFont.ViewModels"
Title="Main Window"
Height="400" Width="800">
<DockPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ComboBox ItemsSource="{Binding Path=Fonts}"
SelectedItem="{Binding Path=SelectedFont, Mode=TwoWay}"/>
<local:RichTextBoxCustom Grid.Row="1"
CurrentFontFamily="{Binding Path=SelectedFont, Mode=TwoWay}"
FontSize="30"/>
</Grid>
</DockPanel>
</Window>
Вот ViewModel: Если вы не используете модели представления, дайте мне знать, и я тоже добавлю код базового класса; в противном случае вам также может помочь google / stackoverflow.
using System.Collections.ObjectModel;
using System.Windows.Media;
namespace RichTextboxFont.ViewModels
{
public class MainViewModel : ViewModelBase
{
#region Constructor
public MainViewModel()
{
FontFamily f1 = new FontFamily("Georgia");
_fonts.Add(f1);
FontFamily f2 = new FontFamily("Tahoma");
_fonts.Add(f2);
}
private ObservableCollection<FontFamily> _fonts = new ObservableCollection<FontFamily>();
public ObservableCollection<FontFamily> Fonts
{
get
{
return _fonts;
}
set
{
_fonts = value;
OnPropertyChanged("Fonts");
}
}
private FontFamily _selectedFont = new FontFamily("Tahoma");
public FontFamily SelectedFont
{
get
{
return _selectedFont;
}
set
{
_selectedFont = value;
FontChanged = true;
OnPropertyChanged("SelectedFont");
}
}
private bool _fontChanged = false;
public bool FontChanged
{
get
{
return _fontChanged;
}
set
{
_fontChanged = value;
OnPropertyChanged("FontChanged");
}
}
#endregion
}
}
Вот код программной части окна, в котором я инициализирую ViewModel:
using System.Windows;
namespace RichTextboxFont.Views
{
public partial class MainView : Window
{
public MainView()
{
InitializeComponent();
this.DataContext = new ViewModels.MainViewModel();
}
}
}
Это не совсем тривиальный ответ.
Чтобы сделать встроенное форматирование текста в Rich TextBox, как вы хотите, вам придется изменить свойство Document в RichTextBox. Очень просто, что-то вроде этого будет работать
<RichTextBox >
<RichTextBox.Document>
<FlowDocument>
<Paragraph>
<Run>Something</Run>
<Run FontWeight="Bold">Something Else</Run>
</Paragraph>
</FlowDocument>
</RichTextBox.Document>
</RichTextBox>
Я думаю, вы можете создать пользовательский элемент управления, который создает новый блочный элемент и устанавливает нужные вам свойства шрифта на основе пользовательского ввода.
Например, если пользователь набирает что-то, а затем нажимает кнопку bold. Вы хотите обернуть предыдущий текст в пробел и создать новый элемент пробела, установив FontWeight на bold, тогда последующий текст будет обернут в полужирный пробел.
Опять же, это не тривиальное решение, но я не могу придумать другого способа достичь того, что вам нужно.
Есть гораздо более простой способ сделать это: реализовать панель инструментов для вашего RichTextBox.
В отличие от WinForms, RichTextBox в WPF по умолчанию не имеет панели инструментов, но ее очень легко создать самостоятельно. RichTextBox автоматически обрабатывает многие EditingCommands, поэтому нужно просто создать панель инструментов и несколько кнопок. Microsoft предоставила пример кода для этого в нижней части обзора RichTextBox на MSDN.
К сожалению, эти команды редактирования не включают установку свойства FontFace для выделения, хотя вы можете создать поле со списком на панели инструментов, которое может инициировать изменение с помощью обработчика событий в файле кода программной части.
Этот подход используется Грегором Проссом в этой статье CodePlex: WPF RichTextEditor
Проект комментируется на немецком языке, но сам исходный код написан очень четко. Код программной части, используемый для его селектора шрифтов ComboBox, выглядит следующим образом:
private void Fonttype_DropDownClosed(object sender, EventArgs e)
{
string fontName = (string)Fonttype.SelectedItem;
if (fontName != null)
{
RichTextControl.Selection.ApplyPropertyValue(System.Windows.Controls.RichTextBox.FontFamilyProperty, fontName);
RichTextControl.Focus();
}
}
Основная причина, по которой люди борются с выбором FontFace, заключается в том, что после выбора шрифта вы должны вернуть фокус на RichTextBox. Если пользователю приходится вручную нажимать вкладку или щелкать RichTextBox, создается новое выделение текста, и вы теряете выбранные параметры форматирования.
Один из ответов на этот вопрос StackOverflow обсуждает эту проблему. WPF Richtextbox FontFace/FontSize