【问题标题】:How to set RichTextBox Font for the next text to be written?如何为下一个要写入的文本设置 RichTextBox 字体?
【发布时间】:2016-10-31 03:13:58
【问题描述】:

我需要为下一个要写入 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 属性,我可以将更改限制为仅应用于所选区域。但是下一个尚未输入的文本如何处理?

【问题讨论】:

  • 您是否尝试提供如下效果:当用户按下粗体。然后键入文本时,键入的内容应该变为粗体,直到去除粗体效果?
  • 没错!与标准文本处理器中的相同。这是非常基本和显而易见的,遗憾的是 WPF 默认没有它!

标签: wpf xaml fonts richtextbox


【解决方案1】:

这并不是一个简单的答案。

要在 Rich TextBox 中按照您的需要进行内联文本格式化,您必须修改 RichTextBox 的 Document 属性。很简单,这样的事情会起作用

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

我认为您可以创建一个自定义控件来创建一个新的块元素并根据用户输入设置您需要的字体属性。

例如,如果用户键入内容然后按粗体。您可能希望将前面的文本换行并创建一个新的 run 元素,将 FontWeight 设置为粗体,然后后续文本将换行在粗体运行中。

同样,这不是一个简单的解决方案,但我想不出任何其他方法来完成您所追求的目标。

【讨论】:

    【解决方案2】:

    为了根据光标位置设置 FontFamily,您需要定义一个具有依赖属性的自定义控件,该依赖属性有助于通过覆盖 OnTextInput 方法插入新的运行部分。

    我包含了大部分代码,您需要修改命名空间以适应您的开发环境。

    代码使用 ViewModel 来管理可用字体并管理字体是否更改。 这段代码只是一个原型,不处理两个控件之间的聚焦问题。

    要使用此代码:
    1- 在 RichTectBox 中键入一些文本。
    2- 更改组合框中的字体。
    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>
    

    这是视图模型: 如果您不使用视图模型,请告诉我,我也会添加基类代码;否则,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 的 Window 代码隐藏:

    using System.Windows;
    
    namespace RichTextboxFont.Views
    {
      public partial class MainView : Window
      {
        public MainView()
        {
          InitializeComponent();
          this.DataContext = new ViewModels.MainViewModel();
        }
      }
    }
    

    【讨论】:

    • 我认为使用 MVVM 方法太复杂了。您可以使用后面代码中的事件处理程序在几行代码中解决这个问题。
    • 你给了我关键部分:重写 OnTextInput 方法。谢谢!
    【解决方案3】:

    有一个更简单的方法可以做到这一点:为您的 RichTextBox 实现一个工具栏。

    与 WinForms 不同,WPF 中的 RichTextBox 默认不附带工具栏,但自己创建一个非常容易。 RichTextBox 会自动处理许多EditingCommands,因此只需创建一个工具栏和一些按钮即可。微软在RichTextBox Overview on MSDN底部提供了这方面的示例代码。

    不幸的是,这些编辑命令不包括设置所选内容的 FontFace 属性,尽管您可以在工具栏上创建一个组合框,该组合框可以使用代码隐藏文件中的事件处理程序触发更改。

    这就是 Gregor Pross 在这篇 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

    【讨论】:

    • 这是最简单的部分。当存在要应用字体或其他格式属性的选定文本时。复杂的部分是没有选择时。
    • 你为我省去了很多麻烦。非常感谢!
    猜你喜欢
    • 2011-12-21
    • 1970-01-01
    • 1970-01-01
    • 2012-09-15
    • 2015-11-02
    • 2011-01-14
    • 2013-09-15
    • 1970-01-01
    相关资源
    最近更新 更多