wpf中的默认的RichTextBox不支持内容及当前选中项的绑定,而在实际使用中却经常需要,这便使得View与VM无法更好的分离,在这里,我实现自定义的一个RichTextBox,可以直接绑定到VM中。具体代码如下:
public class MyRichTextBox : RichTextBox
{
private bool _isuioper = false;
public static readonly DependencyProperty ContentTextProperty = DependencyProperty.Register(
"ContentText", typeof (string), typeof (MyRichTextBox), new PropertyMetadata("", ContentTextChanged));
public string ContentText
{
get { return (string) GetValue(ContentTextProperty); }
set { SetValue(ContentTextProperty, value); }
}
private static void ContentTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var rich = d as MyRichTextBox;
if (null != rich && !rich._isuioper)
rich.ContentRange().Text = rich.ContentText;
}
public static readonly DependencyProperty ContentRtfProperty = DependencyProperty.Register(
"ContentRtf", typeof (string), typeof (MyRichTextBox), new PropertyMetadata("", ContentRtfChanged));
public string ContentRtf
{
get { return (string) GetValue(ContentRtfProperty); }
set { SetValue(ContentRtfProperty, value); }
}
private static void ContentRtfChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var rich = d as MyRichTextBox;
if (null != rich && !rich._isuioper)
rich.LoadContentRtf(rich.ContentRtf);
}
public static readonly DependencyProperty SelectedTextProperty = DependencyProperty.Register(
"SelectedText", typeof (string), typeof (MyRichTextBox), new PropertyMetadata("", SelectedTextChanged));
public string SelectedText
{
get { return (string) GetValue(SelectedTextProperty); }
set { SetValue(SelectedTextProperty, value); }
}
private static void SelectedTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var rich = d as MyRichTextBox;
if (null != rich && !rich._isuioper)
rich.SelectedRange().Text = rich.SelectedText;
}
public static readonly DependencyProperty SelectedRtfProperty = DependencyProperty.Register(
"SelectedRtf", typeof (string), typeof (MyRichTextBox), new PropertyMetadata("", SelectedRtfChanged));
public string SelectedRtf
{
get { return (string) GetValue(SelectedRtfProperty); }
set { SetValue(SelectedRtfProperty, value); }
}
private static void SelectedRtfChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var rich = d as MyRichTextBox;
if (null != rich && !rich._isuioper)
rich.LoadSelectedRtf(rich.SelectedRtf);
}
private TextRange ContentRange()
{
var start = this.Document.ContentStart;
var end = this.Document.ContentEnd;
return new TextRange(start, end);
}
private TextRange SelectedRange()
{
var start = Selection.Start;
var end = Selection.End;
return new TextRange(start, end);
}
private string GetContentRtf()
{
string rtf = string.Empty;
using (var ms = new MemoryStream())
{
ContentRange().Save(ms, DataFormats.Rtf);
ms.Seek(0, SeekOrigin.Begin);
var sr = new StreamReader(ms);
rtf = sr.ReadToEnd();
}
return rtf;
}
private void LoadContentRtf(string rtf)
{
if (string.IsNullOrEmpty(rtf))
{
ContentRange().Text = "";
return;
}
using (var ms = new MemoryStream())
{
using (var sw = new StreamWriter(ms))
{
sw.Write(rtf);
sw.Flush();
ms.Seek(0, SeekOrigin.Begin);
ContentRange().Load(ms, DataFormats.Rtf);
}
}
}
private string GetSelectedRtf()
{
string rtf = string.Empty;
using (var ms = new MemoryStream())
{
SelectedRange().Save(ms, DataFormats.Rtf);
ms.Seek(0, SeekOrigin.Begin);
var sr = new StreamReader(ms);
rtf = sr.ReadToEnd();
}
return rtf;
}
private void LoadSelectedRtf(string rtf)
{
if (string.IsNullOrEmpty(rtf))
{
SelectedRange().Text = "";
return;
}
using (var ms = new MemoryStream())
{
using (var sw = new StreamWriter(ms))
{
sw.Write(rtf);
sw.Flush();
ms.Seek(0, SeekOrigin.Begin);
SelectedRange().Load(ms, DataFormats.Rtf);
}
}
}
protected override void OnTextChanged(TextChangedEventArgs e)
{
base.OnTextChanged(e);
_isuioper = true;
ContentText = ContentRange().Text;
ContentRtf = GetContentRtf();
_isuioper = false;
}
protected override void OnSelectionChanged(RoutedEventArgs e)
{
base.OnSelectionChanged(e);
_isuioper = true;
SelectedText = SelectedRange().Text;
SelectedRtf = GetSelectedRtf();
_isuioper = false;
}
}
<Window x:Class="richtest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:richtest="clr-namespace:richtest"
Title="MainWindow" Height="463.434" Width="830.97">
<Grid>
<richtest:MyRichTextBox HorizontalAlignment="Left" Height="385" Margin="10,38,0,0" VerticalAlignment="Top" Width="224"
x:Name="rich">
<FlowDocument>
<Paragraph>
<Run Text="RichTextBox"/>
</Paragraph>
</FlowDocument>
</richtest:MyRichTextBox>
<TextBlock HorizontalAlignment="Left" Margin="255,50,0,0" TextWrapping="Wrap" Text="ContentText" VerticalAlignment="Top"/>
<TextBlock HorizontalAlignment="Left" Margin="255,84,0,0" TextWrapping="Wrap" Text="ContentRtf" VerticalAlignment="Top"/>
<TextBlock HorizontalAlignment="Left" Margin="255,245,0,0" TextWrapping="Wrap" Text="SelectedText" VerticalAlignment="Top"/>
<TextBlock HorizontalAlignment="Left" Margin="255,281,0,0" TextWrapping="Wrap" Text="SelectedRtf" VerticalAlignment="Top"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="362,43,0,0" TextWrapping="Wrap"
Text="{Binding ContentText,ElementName=rich,UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="451"/>
<TextBox HorizontalAlignment="Left" Height="147" Margin="362,77,0,0" TextWrapping="Wrap"
Text="{Binding ContentRtf, ElementName=rich, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="451"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="362,242,0,0" TextWrapping="Wrap"
Text="{Binding SelectedText, ElementName=rich, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="451"/>
<TextBox HorizontalAlignment="Left" Height="145" Margin="362,278,0,0" TextWrapping="Wrap"
Text="{Binding SelectedRtf, ElementName=rich, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top" Width="451"/>
</Grid>
</Window>
运行结果
本文介绍如何在WPF中解决默认RichTextBox不支持内容和选中项绑定的问题,通过自定义控件实现更好的MVVM分离。提供了一段具体的自定义代码,以实现与ViewModel的直接绑定。

2441

被折叠的 条评论
为什么被折叠?



