淺談WPF之利用RichTextBox實現富文本編輯器

来源:https://www.cnblogs.com/hsiang/p/18020115
-Advertisement-
Play Games

在實際應用中,富文本隨處可見,如留言板,聊天軟體,文檔編輯,特定格式內容等,在WPF開發中,如何實現富文本編輯呢?本文以一個簡單的小例子,簡述如何通過RichTextBox實現富文本編輯功能,主要實現複製,剪切,粘貼,撤銷,重做,保存,打開,文本加粗,斜體,下劃線,刪除線,左對齊,居中對齊,右對齊,... ...


在實際應用中,富文本隨處可見,如留言板,聊天軟體,文檔編輯,特定格式內容等,在WPF開發中,如何實現富文本編輯呢?本文以一個簡單的小例子,簡述如何通過RichTextBox實現富文本編輯功能,主要實現複製,剪切,粘貼,撤銷,重做,保存,打開,文本加粗,斜體,下劃線,刪除線,左對齊,居中對齊,右對齊,兩端對齊,縮進,減少縮進,項目符號,數字元號,上標,下標,背景色,前景色,圖片,列印等功能,僅供學習分享使用,如有不足之處,還請指正。

 

什麼是RichTextBox?

 

使用RichTextBox可以顯示或編輯流內容,如文本,圖片,表格等,TextBox和RichTextBox都可以用於編輯文本,但使用場景不同。如果是單純的無格式的純文本,建議使用TextBox;如果是需要編輯帶格式的文本、圖像、表格或其他多種格式的內容時,RichTextBox 是更好的選擇。

 

什麼是流內容和流文檔?

 

通常情況下,所有在富文本編輯器中呈現的內容,都是流內容(FlowContent),而為了呈現流內容的構建塊,稱為流內容元素(Element)。不同的流內容元素,組成了流文檔(FlowDocument),RichTextBox是流文檔的托管對象之一。

流文檔旨在根據視窗大小、設備解析度和其他環境變數來“重排內容”。 此外,流文檔還具有很多內置功能,包括搜索、能夠優化可讀性的查看模式以及更改字體大小和外觀的功能。 當易讀性是文檔的主要使用要求時,最適合使用流文檔。

 

涉及知識點

 

在通過RichTextBox實現富文本編輯器時,涉及到的知識點如下所示:

根據流內容的用途,可分為兩個重要類別:

  1. Block 派生類:也稱為“Block 內容元素”,或簡稱為“Block 元素”。 繼承自 Block 的元素可用於將元素分組到一個公用父級下,或將公用屬性應用於某個組。

  2. Inline 派生類:也稱為“Inline 內容元素”,或簡稱為“Inline 元素”。 繼承自 Inline 的元素要麼包含在 Block 元素中,要麼包含在另一個 Inline 元素中。 Inline 元素通常用作在屏幕上呈現的內容的直接容器。 例如,Paragraph(Block 元素)可包含 Run(Inline 元素),而 Run 實際包含在屏幕上呈現的文本。

在實現富文本編輯器時,需要用到圖標實現,主要內容如下:

  1. 在本示例中圖標主要通過自定義路徑Path實現,其中Data屬性是Geometry類型,用於接收自定以的圖形。而用到的圖標類型數據,可以通過iconfont官網進行獲取。
  2. 在本示例中,用到很多圖標,為了統一管理,創建資源字典,圖標數據作為一種資源引入。

操作流文檔時,常見使用到的類,如下所示:

 

創建RichTextBox

 

RichTextBox托管流文檔對象,流文檔包含流內容,包括文本,段落,圖像,表格,等內容,創建語法如下所示:

<RichTextBox x:Name="richTextBox" AcceptsTab="True" Grid.Row="1" BorderThickness="1" BorderBrush="LightBlue" Margin="2" Padding="2" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Auto">
	<RichTextBox.Document>
		<FlowDocument>
			<Paragraph>
				I am a sunny boy. My name is xxxx. I am from xxxx Primary School. I am over 1.5 meters old when I just turned 12. Alas, I may be a little fat because of eating too much sugar. A pair of pretty big eyes are inlaid under the dark hair and curved eyebrows. There is also a thin mouth.
			</Paragraph>
			<Paragraph>
				I like to play computer games. I play online whenever I have time, and my mother scolds me all day. I also like reading. Once, when I went to the library to read, I was fascinated by it. I was immersed in the ocean of knowledge and didn't remember to go home for dinner. I didn't want to leave until the library closed. I also like to play basketball. Every Saturday and Sunday, I will invite some friends to play basketball for a few hours.
			</Paragraph>
			<Paragraph>
				My advantage is that I love to move. Every morning I go outside to exercise, run, play the horizontal bar, etc. My math scores are also very good, but my Chinese and English scores are average, so my face is always filled with joy. My shortcoming is that I can't play table tennis, and I don't know what is going on. I just don't like it. This is me. If your hobbies are the same as mine, you can find me.
			</Paragraph>
			<Paragraph>
				thank you.
			</Paragraph>
		</FlowDocument>
	</RichTextBox.Document>
</RichTextBox>

 

編輯命令

 

為了方便起見,WPF 提供由 ApplicationCommands、MediaCommands、ComponentCommands、NavigationCommands 和 EditingCommands 組成的常用命令庫,你也可以定義自己的命令。在實現富文本編輯器時,用到的命令主要有三種:

  1. ApplicationCommands,主要是應用程式中常見的命令,如:複製Copy,剪切Cut,粘貼Paste,重做Redo,撤銷Undo等。
  2. EditingCommands 提供了一組常見的編輯相關的命令,如:加粗Bold,斜體Italic,下劃線UnderLine,左對齊,右對齊,居中對齊,兩端對齊,縮進,減少縮進,項目符號,數字元號等。
  3. 自定義命令,預設RichTextBox並沒有提供相應的命令,所以需要根據功能自行定義,如:背景色,前景色,列印,打開,保存,上標,下標,圖像等。

 

編輯命令頁面佈局和綁定

 

使用WPF自帶的命令,需要指定Command和CommandTarget兩個屬性,否則將不起作用。其中Command直接使用Commnad="命令名稱",CommandTarget=“{Binding ElementName=控制項名稱}”的格式進行綁定。

自定義命令,需要通過Command="{Binding 命令名稱}"的格式進行綁定。具體如下所示:

<StackPanel Orientation="Horizontal" Grid.Row="0">
	<Button ToolTip="打開" Command="{Binding OpenCommand}">
		<Path Data="{StaticResource icon_open}" Stretch="Fill" Fill="#1296db"></Path>
	</Button>
	<Button ToolTip="保存" Command="{Binding SaveCommand}">
		<Path Data="{StaticResource icon_save}" Stretch="Fill" Fill="#1296db"></Path>
	</Button>
	<GridSplitter Width="1" Margin="3 2 3 2" Background="LightGray" IsEnabled="False"></GridSplitter>
	<Button ToolTip="剪切" Command="ApplicationCommands.Cut" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_cut}" Stretch="Fill" Fill="Black"></Path>
	</Button>
	<Button ToolTip="複製" Command="ApplicationCommands.Copy" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_copy}" Stretch="Fill" Fill="#1296db"></Path>
	</Button>
	<Button ToolTip="粘貼" Command="ApplicationCommands.Paste" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_paste}" Stretch="Fill" Fill="#1296db"></Path>
	</Button>
	<Button ToolTip="撤銷" Command="ApplicationCommands.Undo" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_undo}" Stretch="Fill" Fill="#8a8a8a"></Path>
	</Button>
	<Button ToolTip="重做" Command="ApplicationCommands.Redo" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_redo}" Stretch="Fill" Fill="#8a8a8a"></Path>
	</Button>
	<GridSplitter Width="1" Margin="3 2 3 2" Background="LightGray" IsEnabled="False"></GridSplitter>
	<Button ToolTip="加粗" Command="EditingCommands.ToggleBold" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_bold}" Stretch="Fill" Fill="Black"></Path>
	</Button>
	<Button ToolTip="斜體" Command="EditingCommands.ToggleItalic" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_italic}" Stretch="Fill" Fill="LightGray"></Path>
	</Button>
	<Button ToolTip="下劃線" Command="EditingCommands.ToggleUnderline" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_underline}" Stretch="Fill" Fill="Gray"></Path>
	</Button>
	<Button ToolTip="刪除線" Command="{Binding SettingCommand}" CommandParameter="StrikeLine">
		<Path Data="{StaticResource icon_strikeline}" Stretch="Fill" Fill="Black"></Path>
	</Button>
	<Button ToolTip="左對齊" Command="EditingCommands.AlignLeft" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_left}" Stretch="Fill" Fill="Black" Stroke="LimeGreen"></Path>
	</Button>
	<Button ToolTip="居中對齊" Command="EditingCommands.AlignCenter" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_center}" Stretch="Fill" Fill="Black" Stroke="LimeGreen"></Path>
	</Button>
	<Button ToolTip="右對齊" Command="EditingCommands.AlignRight" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_right}" Stretch="Fill" Fill="Black" Stroke="LimeGreen"></Path>
	</Button>
	<Button ToolTip="兩端對齊" Command="EditingCommands.AlignJustify" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_justify}" Stretch="Fill" Fill="Black" Stroke="LimeGreen"></Path>
	</Button>
	<Button ToolTip="縮進" Command="EditingCommands.IncreaseIndentation" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_addident}" Stretch="Fill" Fill="DimGray"></Path>
	</Button>
	<Button ToolTip="減少縮進" Command="EditingCommands.DecreaseIndentation" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_lessident}" Stretch="Fill" Fill="DimGray"></Path>
	</Button>
	<Button ToolTip="項目編號" Command="EditingCommands.ToggleBullets" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_bullets}" Stretch="Fill" Fill="DimGray"></Path>
	</Button>
	<Button ToolTip="數字編號" Command="EditingCommands.ToggleNumbering" CommandTarget="{Binding ElementName=richTextBox}">
		<Path Data="{StaticResource icon_numbering}" Stretch="Fill" Fill="DimGray"></Path>
	</Button>
	<Button ToolTip="上標" Command="{Binding SettingCommand}" CommandParameter="Super">
		<Path Data="{StaticResource icon_upper}" Stretch="Fill" Fill="CadetBlue"></Path>
	</Button>
	<Button ToolTip="下標" Command="{Binding SettingCommand}" CommandParameter="Sub">
		<Path Data="{StaticResource icon_down}" Stretch="Fill" Fill="CadetBlue"></Path>
	</Button>
	<GridSplitter Width="1" Margin="3 2 3 2" Background="LightGray" IsEnabled="False"></GridSplitter>

	<Grid Background="White" Width="42" Height="30" Margin="3">
		<ComboBox Width="42" Height="30" BorderThickness="0" HorizontalAlignment="Left" VerticalAlignment="Center" SelectedIndex="0" BorderBrush="White" Background="White" Name="combBackground">
			<ComboBoxItem Background="#000000" Content="#000000"></ComboBoxItem>
			<ComboBoxItem Background="#FF0000" Content="#FF0000"></ComboBoxItem>
			<ComboBoxItem Background="#00FF00" Content="#00FF00"></ComboBoxItem>
			<ComboBoxItem Background="#0000FF" Content="#0000FF"></ComboBoxItem>
			<ComboBoxItem Background="#00AA00" Content="#00AA00"></ComboBoxItem>
			<ComboBoxItem Background="#AA0000" Content="#AA0000"></ComboBoxItem>
			<ComboBoxItem Background="#0000AA" Content="#0000AA"></ComboBoxItem>
			<ComboBoxItem Background="#AA00CC" Content="#AA00CC"></ComboBoxItem>
			<ComboBoxItem Background="#00BBCC" Content="#00BBCC"></ComboBoxItem>
			<ComboBoxItem Background="#555555" Content="#555555"></ComboBoxItem>
			<ComboBoxItem Background="#AAAAAA" Content="#AAAAAA"></ComboBoxItem>
			<ComboBoxItem Background="#BBBBBB" Content="#BBBBBB"></ComboBoxItem>
			<ComboBoxItem Background="#CCCCCC" Content="#CCCCCC"></ComboBoxItem>
			<ComboBoxItem Background="#DDDDDD" Content="#DDDDDD"></ComboBoxItem>
			<ComboBoxItem Background="#EEEEEE" Content="#EEEEEE"></ComboBoxItem>
			<ComboBoxItem Background="#FFFFFF" Content="#FFFFFF"></ComboBoxItem>
			<i:Interaction.Triggers>
				<i:EventTrigger EventName="SelectionChanged">
					<i:InvokeCommandAction Command="{Binding BgColorCommand}" CommandParameter="{Binding ElementName=combBackground, Path=SelectedItem}"/>
				</i:EventTrigger>
			</i:Interaction.Triggers>
		</ComboBox>
		<Button ToolTip="背景色" Width="30" Height="30" Padding="0" Margin="0" HorizontalAlignment="Left" VerticalAlignment="Center">
			<Path Data="{StaticResource icon_background}" Stretch="Fill"  Fill="{Binding ElementName=combBackground, Path=SelectedItem.Background}"  ></Path>
		</Button>
	</Grid>
	<Grid Background="White" Width="42" Height="30" Margin="3">
		<ComboBox Width="42" Height="30" BorderThickness="0" HorizontalAlignment="Left" VerticalAlignment="Center" SelectedIndex="0" BorderBrush="White" Background="White" Name="combForeground">
			<ComboBoxItem Background="#000000" Content="#000000"></ComboBoxItem>
			<ComboBoxItem Background="#FF0000" Content="#FF0000"></ComboBoxItem>
			<ComboBoxItem Background="#00FF00" Content="#00FF00"></ComboBoxItem>
			<ComboBoxItem Background="#0000FF" Content="#0000FF"></ComboBoxItem>
			<ComboBoxItem Background="#00AA00" Content="#00AA00"></ComboBoxItem>
			<ComboBoxItem Background="#AA0000" Content="#AA0000"></ComboBoxItem>
			<ComboBoxItem Background="#0000AA" Content="#0000AA"></ComboBoxItem>
			<ComboBoxItem Background="#AA00CC" Content="#AA00CC"></ComboBoxItem>
			<ComboBoxItem Background="#00BBCC" Content="#00BBCC"></ComboBoxItem>
			<ComboBoxItem Background="#555555" Content="#555555"></ComboBoxItem>
			<ComboBoxItem Background="#AAAAAA" Content="#AAAAAA"></ComboBoxItem>
			<ComboBoxItem Background="#BBBBBB" Content="#BBBBBB"></ComboBoxItem>
			<ComboBoxItem Background="#CCCCCC" Content="#CCCCCC"></ComboBoxItem>
			<ComboBoxItem Background="#DDDDDD" Content="#DDDDDD"></ComboBoxItem>
			<ComboBoxItem Background="#EEEEEE" Content="#EEEEEE"></ComboBoxItem>
			<ComboBoxItem Background="#FFFFFF" Content="#FFFFFF"></ComboBoxItem>
			<i:Interaction.Triggers>
				<i:EventTrigger EventName="SelectionChanged">
					<i:InvokeCommandAction Command="{Binding ForeColorCommand}" CommandParameter="{Binding ElementName=combForeground, Path=SelectedItem}"/>
				</i:EventTrigger>
			</i:Interaction.Triggers>
		</ComboBox>
		<Button ToolTip="前景色" Width="30" Height="30" Padding="0" Margin="0" HorizontalAlignment="Left" VerticalAlignment="Center">
			<Path Data="{StaticResource icon_foreground}" Stretch="Fill"  Fill="{Binding ElementName=combForeground, Path=SelectedItem.Background}"  ></Path>
		</Button>
	</Grid>
	<Button ToolTip="圖像" Command="{Binding SettingCommand}" CommandParameter="Image">
		<Path Data="{StaticResource icon_img}" Stretch="Fill" Fill="Goldenrod"></Path>
	</Button>
	<Button ToolTip="列印" Command="{Binding SettingCommand}" CommandParameter="Print">
		<Path Data="{StaticResource icon_print}" Stretch="Fill" Fill="Tomato"></Path>
	</Button>
	
</StackPanel>

 

自定義命令

 

在本示例中,後臺命令使用和屬性綁定,使用CommunityToolkit.Mvvm庫實現。後臺實現業務主要分為三種:

1. 打開,保存命令

打開,保存主要實現對RichTextBox中的流文檔對象的序列化和反序列化,具體如下所示:

private IRelayCommand saveCommand;

public IRelayCommand SaveCommand
{
	get
	{
		if (saveCommand == null)
		{
			saveCommand = new RelayCommand(Save);
		}
		return saveCommand;
	}
}

private void Save()
{
	SaveFileDialog saveFileDialog = new SaveFileDialog();
	saveFileDialog.Title = "請選擇要保存的路徑";
	saveFileDialog.Filter = "富文本格式|*.xaml";
	bool? flag = saveFileDialog.ShowDialog();
	if (flag == true)
	{
		string _fileName=saveFileDialog.FileName;
		TextRange range;
		FileStream fStream;
		range = new TextRange(this.richTextBox.Document.ContentStart, this.richTextBox.Document.ContentEnd);
		fStream = new FileStream(_fileName, FileMode.Create);
		range.Save(fStream, DataFormats.XamlPackage);
		fStream.Close();
	}
}

private IRelayCommand openCommand;

public IRelayCommand OpenCommand
{
	get
	{
		if (openCommand == null)
		{
			openCommand = new RelayCommand(Open);
		}
		return openCommand;
	}
}

private void Open()
{
	TextRange range;
	FileStream fStream;
	OpenFileDialog openFileDialog = new OpenFileDialog();
	openFileDialog.Title = "請選擇要載入的文件";
	openFileDialog.Filter = "富文本格式|*.xaml";
	bool? flag = openFileDialog.ShowDialog();
	if (flag == true)
	{
		string _fileName = openFileDialog.FileName;
		if (File.Exists(_fileName))
		{
			range = new TextRange(this.richTextBox.Document.ContentStart, this.richTextBox.Document.ContentEnd);
			fStream = new FileStream(_fileName, FileMode.OpenOrCreate);
			range.Load(fStream, DataFormats.XamlPackage);
			fStream.Close();
		}
	}
}

 

顏色設置命令

 

顏色設置,主要用於將用戶選擇的顏色,賦值給用於選擇的流內容元素對象。如下所示:

private IRelayCommand<object> bgColorCommand;

public IRelayCommand<object> BgColorCommand
{
	get
	{
		if(bgColorCommand == null)
		{
			bgColorCommand = new RelayCommand<object>(BgColor);
		}
		return bgColorCommand;
	}
}

private void BgColor(object obj)
{
	if (obj == null)
	{
		return;
	}
	var item = obj as ComboBoxItem;
	if (item != null)
	{
		var color = item.Background;
		var buttonType = "Background";
		SetColor(buttonType, color);
	}
}

private IRelayCommand<object> foreColorCommand;

public IRelayCommand<object> ForeColorCommand
{
	get
	{
		if (foreColorCommand == null)
		{
			foreColorCommand = new RelayCommand<object>(ForeColor);
		}
		return foreColorCommand;
	}
}

private void ForeColor(object obj)
{
	if (obj == null)
	{
		return;
	}
	var item = obj as ComboBoxItem;
	if (item != null)
	{
		var color = item.Background;
		var buttonType = "Foreground";
		SetColor(buttonType, color);
	}
}

private void SetColor(string buttonType, Brush brush)
{
	var textSelection = this.richTextBox.Selection;
	if (textSelection == null)
	{
		return;
	}
	if (buttonType == "Background")
	{
		var propertyValue = textSelection.GetPropertyValue(TextElement.BackgroundProperty);
		var bgBrush = (Brush)propertyValue;
		if (bgBrush == brush)
		{
			textSelection.ApplyPropertyValue(TextElement.BackgroundProperty, Colors.White);
		}
		else
		{
			textSelection.ApplyPropertyValue(TextElement.BackgroundProperty, brush);
		}
	}
	if (buttonType == "Foreground")
	{
		var propertyValue = textSelection.GetPropertyValue(TextElement.ForegroundProperty);
		var foreground = (Brush)propertyValue;
		if (foreground == brush)
		{
			textSelection.ApplyPropertyValue(TextElement.ForegroundProperty, Colors.Black);
		}
		else
		{
			textSelection.ApplyPropertyValue(TextElement.ForegroundProperty, brush);
		}
	}
}

 

3. 其他設置命令

 

其他設置命令,如刪除線,上標,下標,圖像插入,列印等命令,如下所示:

private IRelayCommand<string> settingCommand;

public IRelayCommand<string> SettingCommand
{
	get
	{
		if(settingCommand == null)
		{
			settingCommand = new RelayCommand<string>(Setting);
		}
		return settingCommand;
	}
}

private void Setting(string buttonType)
{
	var textSelection = this.richTextBox.Selection;
	if (textSelection == null)
	{
		return;
	}
	if (buttonType == "StrikeLine")
	{
		var propertyValue = textSelection.GetPropertyValue(Inline.TextDecorationsProperty);
		var textDecorationCollection = (TextDecorationCollection)propertyValue;
		if (textDecorationCollection == TextDecorations.Strikethrough)
		{
			textSelection.ApplyPropertyValue(Inline.TextDecorationsProperty, null);
		}
		else
		{
			textSelection.ApplyPropertyValue(Inline.TextDecorationsProperty, TextDecorations.Strikethrough);
		}
	}else if (buttonType == "Super")
	{
		var propertyValue = textSelection.GetPropertyValue(Inline.BaselineAlignmentProperty);
		var supper = (BaselineAlignment)propertyValue;
		if (supper == BaselineAlignment.Superscript)
		{
			textSelection.ApplyPropertyValue(Inline.BaselineAlignmentProperty, BaselineAlignment.Top);
		}
		else
		{
			textSelection.ApplyPropertyValue(Inline.BaselineAlignmentProperty, BaselineAlignment.Superscript);
		}
	}
	else if(buttonType == "Sub")
	{
		var propertyValue = textSelection.GetPropertyValue(Inline.BaselineAlignmentProperty);
		var sub = (BaselineAlignment)propertyValue;
		if (sub == BaselineAlignment.Subscript)
		{
			textSelection.ApplyPropertyValue(Inline.BaselineAlignmentProperty, BaselineAlignment.Top);
		}
		else
		{
			textSelection.ApplyPropertyValue(Inline.BaselineAlignmentProperty, BaselineAlignment.Subscript);
		}
	}
	else if (buttonType == "Image")
	{
		OpenFileDialog openFileDialog = new OpenFileDialog();
		openFileDialog.Title = "請選擇需要插入的圖片";
		openFileDialog.Filter = "圖片文件|*.png";
		bool? flag = openFileDialog.ShowDialog();
		if (flag ==true)
		{
			var fileName = openFileDialog.FileName;
			var img = new Image() { Source = new BitmapImage(new Uri(fileName)), Stretch = Stretch.Uniform, Width = this.richTextBox.ActualWidth - 50 };
			var imgContainer = new BlockUIContainer(img);
			this.richTextBox.CaretPosition.InsertParagraphBreak();
			this.richTextBox.Document.Blocks.InsertBefore(this.richTextBox.CaretPosition.Paragraph, imgContainer);
		}
	}
	else if(buttonType == "Print")
	{
		PrintDialog pd = new PrintDialog();
		if ((pd.ShowDialog() == true))
		{
			//use either one of the below
			pd.PrintVisual(this.richTextBox as Visual, "列印富文本1");
			pd.PrintDocument((((IDocumentPaginatorSource)this.richTextBox.Document).DocumentPaginator), "列印富文本2");
		}
	}
}

 

示例截圖

 

主要實現複製,剪切,粘貼,撤銷,重做,保存,打開,文本加粗,斜體,下劃線,刪除線,左對齊,居中對齊,右對齊,兩端對齊,縮進,減少縮進,項目符號,數字元號,上標,下標,背景色,前景色,圖片,列印等功能,效果如下:

 

源碼下載

 

關於源碼下載,可關註公眾號,回覆WPFRICH進行下載,如下所示:

 

參考文獻

 

流文檔介紹:https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/advanced/flow-document-overview?view=netframeworkdesktop-4.8

RichTextBox介紹:https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/controls/richtextbox-overview?view=netframeworkdesktop-4.8

ApplicationCommands介紹:https://learn.microsoft.com/zh-cn/dotnet/api/system.windows.input.applicationcommands?view=windowsdesktop-8.0

EditingCommands介紹:https://learn.microsoft.com/zh-cn/dotnet/api/system.windows.documents.editingcommands?view=windowsdesktop-8.0

以上就是【淺談WPF之利用RichTextBox實現富文本編輯器】的全部內容。


作者:小六公子
出處:http://www.cnblogs.com/hsiang/
本文版權歸作者和博客園共有,寫文不易,支持原創,歡迎轉載【點贊】,轉載請保留此段聲明,且在文章頁面明顯位置給出原文連接,謝謝。
關註個人公眾號,定時同步更新技術及職場文章


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • API介面是一種讓不同系統之間實現數據交互的工具,它可以實現不同系統之間的數據共用和數據傳遞。全國今日油價API介面是一項非常有用的介面,它可以提供最新的全國各省汽油和柴油價格信息。本文將為大家介紹全國今日油價API介面的使用方法,並提供相應代碼說明。 介面名稱:全國今日油價API介面介面地址:ht ...
  • 當我們在編寫代碼時,經常會遇到需要管理資源的情況,比如打開和關閉文件,如果遇到了一些異常情況,我們需要關閉資源,不然會導致資源泄露,雖然我們可以通過手動的方式來關閉,但如果有多個異常情況需要考慮的話,萬一不小心漏了一處,就芭比Q了。所以,如果有一種更加優雅的方式來處理資源泄露的問題,那必定是非常ni ...
  • 拓展閱讀 sensitive-word-admin v1.3.0 發佈 如何支持分散式部署? sensitive-word-admin 敏感詞控台 v1.2.0 版本開源 sensitive-word 基於 DFA 演算法實現的高性能敏感詞工具介紹 更多技術交流 業務背景 如果我們的敏感詞部署之後,不 ...
  • Java 方法 簡介 方法是一塊僅在調用時運行的代碼。您可以將數據(稱為參數)傳遞到方法中。方法用於執行特定的操作,它們也被稱為函數。 使用方法的原因 重用代碼:定義一次代碼,多次使用。 提高代碼的結構化和可讀性。 將代碼分解成更小的模塊,易於維護和理解。 創建方法 方法必須在類內聲明。它的定義包括 ...
  • 前言我個人對三維渲染領域的開發有著濃厚的興趣,儘管並未在相關行業工作過,我的瞭解還很片面。去年,在與群友聊天時,他們推薦了一本《Unity Shader入門精要》,說適合像我這樣想自學的新人,於是我打開了通往新世界的大門。這本書涵蓋了很多基礎的渲染知識,如光照、陰影、各種風格的渲染等等。對於有興趣的 ...
  • Gif演示 分解步驟 1,使用組件DataGridView 2,使用DataSource來控製表格展示的數據來源(註意:來源需要是DataTable類型) 3,需要用到非同步線程。如果是不控制數據源的話,需要使用UI安全線程;(使用Control.Invoke或Control.BeginInvoke方 ...
  • 今天同事發開中遇到了一個代碼性能優化的問題,原本需求是:從一個資料庫中查詢某個表數據,存放到datatable中,然後遍歷datatable,看這些數據在另一個資料庫的表中是否存在,存在的話就要更新,不存在就要插入。 就這個需求本身來說很簡單,但是隨著數據量的增大,之前通過迴圈遍歷的方式就出現了性能 ...
  • 網關: 一:apisix doc:https://apisix.apache.org/zh/docs/apisix/getting-started/README/ github:https://github.com/apache/apisix 二:Kong github:https://github ...
一周排行
    -Advertisement-
    Play Games
  • PasteSpider是什麼? 一款使用.net編寫的開源的Linux容器部署助手,支持一鍵發佈,平滑升級,自動伸縮, Key-Value配置,項目網關,環境隔離,運行報表,差量升級,私有倉庫,集群部署,版本管理等! 30分鐘上手,讓開發也可以很容易的學會在linux上部署你得項目! [從需求角度介 ...
  • SQLSugar是什麼 **1. 輕量級ORM框架,專為.NET CORE開發人員設計,它提供了簡單、高效的方式來處理資料庫操作,使開發人員能夠更輕鬆地與資料庫進行交互 2. 簡化資料庫操作和數據訪問,允許開發人員在C#代碼中直接操作資料庫,而不需要編寫複雜的SQL語句 3. 支持多種資料庫,包括但 ...
  • 在C#中,經常會有一些耗時較長的CPU密集型運算,因為如果直接在UI線程執行這樣的運算就會出現UI不響應的問題。解決這類問題的主要途徑是使用多線程,啟動一個後臺線程,把運算操作放在這個後臺線程中完成。但是原生介面的線程操作有一些難度,如果要更進一步的去完成線程間的通訊就會難上加難。 因此,.NET類 ...
  • 一:背景 1. 講故事 前些天有位朋友在微信上丟了一個崩潰的dump給我,讓我幫忙看下為什麼出現了崩潰,在 Windows 的事件查看器上顯示的是經典的 訪問違例 ,即 c0000005 錯誤碼,不管怎麼說有dump就可以上windbg開幹了。 二:WinDbg 分析 1. 程式為誰崩潰了 在 Wi ...
  • CSharpe中的IO+NPOI+序列化 文件文件夾操作 學習一下常見的文件、文件夾的操作。 什麼是IO流? I:就是input O:就是output,故稱:輸入輸出流 將數據讀入記憶體或者記憶體輸出的過程。 常見的IO流操作,一般說的是[記憶體]與[磁碟]之間的輸入輸出。 作用 持久化數據,保證數據不再 ...
  • C#.NET與JAVA互通之MD5哈希V2024 配套視頻: 要點: 1.計算MD5時,SDK自帶的計算哈希(ComputeHash)方法,輸入輸出參數都是byte數組。就涉及到字元串轉byte數組轉換時,編碼選擇的問題。 2.輸入參數,字元串轉byte數組時,編碼雙方要統一,一般為:UTF-8。 ...
  • CodeWF.EventBus,一款靈活的事件匯流排庫,實現模塊間解耦通信。支持多種.NET項目類型,如WPF、WinForms、ASP.NET Core等。採用簡潔設計,輕鬆實現事件的發佈與訂閱。通過有序的消息處理,確保事件得到妥善處理。簡化您的代碼,提升系統可維護性。 ...
  • 一、基本的.NET框架概念 .NET框架是一個由微軟開發的軟體開發平臺,它提供了一個運行時環境(CLR - Common Language Runtime)和一套豐富的類庫(FCL - Framework Class Library)。CLR負責管理代碼的執行,而FCL則提供了大量預先編寫好的代碼, ...
  • 本章將和大家分享在ASP.NET Core中如何使用高級客戶端NEST來操作我們的Elasticsearch。 NEST是一個高級別的Elasticsearch .NET客戶端,它仍然非常接近原始Elasticsearch API的映射。所有的請求和響應都是通過類型來暴露的,這使得它非常適合快速上手 ...
  • 參考delphi的代碼更改為C# Delphi 檢測密碼強度 規則(仿 google) 仿 google 評分規則 一、密碼長度: 5 分: 小於等於 4 個字元 10 分: 5 到 7 字元 25 分: 大於等於 8 個字元 二、字母: 0 分: 沒有字母 10 分: 全都是小(大)寫字母 20 ...