zoukankan      html  css  js  c++  java
  • WPF中RichTextBox的研究

      最近在写一个类似文本编辑器的东西,有选择字体样式和大小的功能,但在设计的时候遇到了一些问题。

      如果需要设计像QQ聊天时那样的改变字体大小及样式的话(即选择一个字体样式或大小而下面的字体将全部改变),只要把RichTextBox和Combobox绑定就可以了。这样比较简单。不过WPF中的默认字体( System.Windows.Media.FontFamily)是没有中文字体的,所以我用了安装的字体( System.Drawing.FontFamily)。因此就需要自己来写这个类,同时需要添加System.Drawing的这个引用。同样那字号的话为了看起来明显可以挑一些来写一个新类。代码如下:

    View Code
    <Window x:Class="RichTextBoxDemo.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:RichTextBoxDemo"
            Title="MainWindow" Height="550" Width="900" WindowStartupLocation="CenterScreen">
        <Window.Resources>
            <local:FontFamilySource x:Key="fontFamilies" />
            <local:FontSizeSource x:Key="fontSizes" />
        </Window.Resources>
        <DockPanel>
            <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Margin="5, 10">
                <ComboBox x:Name="ComboBoxFontFamily" ItemsSource="{StaticResource fontFamilies}"  MinWidth="180" Margin="10,0" IsSynchronizedWithCurrentItem="True">
                    <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <Label Content="{Binding Name}" FontFamily="{Binding Name}" />
                        </DataTemplate>
                    </ComboBox.ItemTemplate>
                </ComboBox>
                <ComboBox x:Name="ComboBoxFontSize" ItemsSource="{StaticResource fontSizes}" MinWidth="100" IsSynchronizedWithCurrentItem="True"/>
            </StackPanel>
            <UniformGrid Rows="1">
                <RichTextBox  Padding="5,10" x:Name="RichTextBox1" FontFamily="{Binding Source={StaticResource fontFamilies},Path=/}"
                              FontSize="{Binding Source={StaticResource fontSizes},Path=/}" />
            </UniformGrid>
        </DockPanel>
    </Window>
    View Code
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Drawing;
    
    namespace RichTextBoxDemo {
        public partial class MainWindow : Window {
            public MainWindow() {
                InitializeComponent();
            }
        }
        public class FontFamilySource : List<System.Drawing.FontFamily> {
            public FontFamilySource() {
                this.AddRange(new System.Drawing.Text.InstalledFontCollection().Families.Select(p => p).ToList());
            }
        }
        public class FontSizeSource : List<double> {
            public FontSizeSource() {
                this.AddRange(Enumerable.Range(10, 62).Where(p => p % 4 == 0).Select(p => (double)p));
            }
        }
    }

      如果需要设计像WORD那样当改变字体的大小及样式时(即原来已写的字体大小不变,二从光标处继续写的字体变为改变的字体。同时还可以通过划出一段字来改变其字体),这时WPF中的设置就很不人性化,不能直接通过Selection或是对Paragraph很简单的设置字体,这样会出现当鼠标点到中间时,改变字体会迫使其他字体全部改变。只能通过TextChanged时的offset来判断位置。同时还需考虑是不是文档的开头或中间。最后才通过ApplyPropertyValue()来设置字体。代码如下:

    View Code
    <Window x:Class="RtbDemo.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:RtbDemo"
            Title="MainWindow" Height="550" Width="900" WindowStartupLocation="CenterScreen">
        <Window.Resources>
            <local:FontFamilySource x:Key="fontFamilies" />
            <local:FontSizeSource x:Key="fontSizes" />
        </Window.Resources>
        <DockPanel>
            <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" Margin="5, 10">
                <ComboBox x:Name="ComboBoxFontFamily" ItemsSource="{StaticResource fontFamilies}"  MinWidth="180" Margin="10,0" SelectionChanged="ComboBoxFontFamily_SelectionChanged">
                    <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <Label Content="{Binding Name}" FontFamily="{Binding Name}" />
                        </DataTemplate>
                    </ComboBox.ItemTemplate>
                </ComboBox>
                <ComboBox x:Name="ComboBoxFontSize" ItemsSource="{StaticResource fontSizes}" MinWidth="100" />
            </StackPanel>
            <UniformGrid Rows="1">
                <RichTextBox FontSize="24" Padding="5,10" x:Name="RichTextBox1" />
            </UniformGrid>
        </DockPanel>
    </Window>
    View Code
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using System.Drawing;
    
    namespace RtbDemo {
        public partial class MainWindow : Window {
            public MainWindow() {
                InitializeComponent();
                RichTextBox1.Focus();
    
                RichTextBox1.TextChanged += OnTextChanged;
                ComboBoxFontSize.SelectionChanged += ComboBoxFontSize_SelectionChanged;
                this.Loaded += OnLoaded;
            }
    
            void ComboBoxFontSize_SelectionChanged(object sender, SelectionChangedEventArgs e) {
                if (!RichTextBox1.Selection.IsEmpty) {
                    RichTextBox1.Selection.ApplyPropertyValue(RichTextBox.FontSizeProperty, ComboBoxFontSize.SelectedValue);
                }
                RichTextBox1.Focus();
            }
    
            private void ComboBoxFontFamily_SelectionChanged(object sender, SelectionChangedEventArgs e) {
                if (!RichTextBox1.Selection.IsEmpty) {
                    TextRange range = new TextRange(RichTextBox1.Selection.Start, RichTextBox1.Selection.End);
                    var v = ((System.Drawing.FontFamily)ComboBoxFontFamily.SelectedValue).Name.ToString();
                    range.ApplyPropertyValue(RichTextBox.FontFamilyProperty, v);
                }
            }
    
            private void OnLoaded(object sender, RoutedEventArgs e) {
                this.ComboBoxFontFamily.SelectedValue = (this.ComboBoxFontFamily.ItemsSource as FontFamilySource).FirstOrDefault(p => p.Name == "宋体");
                this.ComboBoxFontSize.SelectedValue = (this.ComboBoxFontSize.ItemsSource as FontSizeSource).FirstOrDefault(p => p.ToString() == "24");
            }
    
            private void OnTextChanged(object sender, TextChangedEventArgs e) {
                if (RichTextBox1.Selection.IsEmpty) {
                    foreach (var each in e.Changes) {
                        var start = RichTextBox1.Document.ContentStart;
                        for (int i = 0; i < each.AddedLength; ++i) {
                            var pos = start.GetPositionAtOffset(each.Offset + i + 1);
                            var ctx = pos.GetPointerContext(LogicalDirection.Backward);
                            if (ctx == TextPointerContext.ElementStart) {
                                var adjacent = pos.GetAdjacentElement(LogicalDirection.Backward);
                                if (adjacent.GetType() == typeof(Run)) {
                                    var r = adjacent as Run;
                                    r.FontSize = (double)ComboBoxFontSize.SelectedValue;
                                    System.Windows.Media.FontFamily fontFamily = new System.Windows.Media.FontFamily((ComboBoxFontFamily.SelectedValue as System.Drawing.FontFamily).Name);
                                    r.FontFamily = fontFamily;
                                }
                            } else if (ctx == TextPointerContext.Text) {
                                if (pos.Parent is Run) {
                                    var r = pos.Parent as Run;
                                    if (r.FontSize != (double)ComboBoxFontSize.SelectedValue) {
                                        RichTextBox1.Selection.Select(pos, pos.GetNextInsertionPosition(LogicalDirection.Backward));
                                        RichTextBox1.Selection.ApplyPropertyValue(RichTextBox.FontSizeProperty, ComboBoxFontSize.SelectedValue);
                                        RichTextBox1.Selection.Select(pos, pos);
                                    }
                                    System.Windows.Media.FontFamily fontFamily = new System.Windows.Media.FontFamily((ComboBoxFontFamily.SelectedValue as System.Drawing.FontFamily).Name);
                                    if (r.FontFamily != fontFamily) {
                                        RichTextBox1.Selection.Select(pos, pos.GetNextInsertionPosition(LogicalDirection.Backward));
                                        RichTextBox1.Selection.ApplyPropertyValue(RichTextBox.FontFamilyProperty, fontFamily);
                                        RichTextBox1.Selection.Select(pos, pos);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    
        public class FontFamilySource : List<System.Drawing.FontFamily> {
            public FontFamilySource() {
                this.AddRange(new System.Drawing.Text.InstalledFontCollection().Families.Select(p => p).ToList());
            }
        }
        public class FontSizeSource : List<double> {
            public FontSizeSource() {
                this.AddRange(Enumerable.Range(10, 62).Where(p => p % 4 == 0).Select(p => (double)p));
            }
        }
    }

     

  • 相关阅读:
    Stacks And Queues
    Programming Assignment 5: Burrows–Wheeler Data Compression
    Data Compression
    Regular Expressions
    Programming Assignment 4: Boggle
    Oracle 查询表的索引包含的字段
    pycharm
    Java文件:追加内容到文本文件
    okhttp 使用response.body().string()获取到的数据是一堆乱码
    彻底解决unable to find valid certification path to requested target
  • 原文地址:https://www.cnblogs.com/socialdk/p/2580623.html
Copyright © 2011-2022 走看看