Как установить RichTextBox Font для следующего текста, который будет написан? - PullRequest
12 голосов
/ 06 декабря 2009

Мне нужно установить семейство шрифтов для следующего текста, который будет написан в 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 я могу ограничить изменение, которое будет применено только к выбранной области. Но как насчет следующего, еще не набранного текста?

Ответы [ 3 ]

8 голосов
/ 24 августа 2010

Чтобы установить 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();
    }
  }
}
2 голосов
/ 27 августа 2010

Существует гораздо более простой способ сделать это: реализовать панель инструментов для вашего RichTextBox.

В отличие от WinForms, RichTextBox в WPF не поставляется с панелью инструментов по умолчанию, но создать ее самостоятельно очень просто. RichTextBox автоматически обрабатывает множество EditingCommands , так что это всего лишь вопрос создания панели инструментов и некоторых кнопок. Microsoft предоставила пример кода для этого в нижней части RichTextBox Overview на MSDN .

К сожалению, эти команды редактирования не включают установку свойства FontFace для выделения, хотя вы можете создать ComboBox на панели инструментов, который может инициировать изменение с помощью обработчика событий в файле codebehind.

Это подход, использованный в этой статье 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 . Если пользователь должен вручную нажать клавишу Tab или щелкнуть в RichTextBox, будет создан новый текст, и вы потеряете выбранные параметры форматирования.

В одном из ответов на этот вопрос StackOverflow обсуждается эта проблема. WPF Richtextbox FontFace / FontSize

0 голосов
/ 23 августа 2010

Это не совсем тривиальный ответ.

Чтобы выполнить встроенное форматирование текста в Rich TextBox так, как вам нужно, вам нужно изменить свойство Document RichTextBox. Очень просто, как-то так будет работать

<RichTextBox >
  <RichTextBox.Document>
    <FlowDocument>
      <Paragraph>
        <Run>Something</Run>
        <Run FontWeight="Bold">Something Else</Run>
      </Paragraph>
    </FlowDocument>
  </RichTextBox.Document>
</RichTextBox>  

Я думаю, вы могли бы создать пользовательский элемент управления, который создает новый элемент блока и устанавливает необходимые свойства шрифта на основе пользовательского ввода.

Например, если пользователь что-то печатает, то нажимает жирным шрифтом. Вы хотели бы обернуть предыдущий текст в серии и создать новый элемент серии, в котором для шрифта FontWeight будет выделен жирный шрифт, после чего последующий текст будет обернут жирным шрифтом.

Опять же, это не тривиальное решение, но я не могу придумать какой-либо другой способ добиться того, чего вы хотите.

...