淺談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
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...