目录
二、尝试二:使用string和FlowDocument相互转化方式
前言
RichTextBox无法在MVVM模式绑定属性,使其根据输入和赋值的内容变化。按照网上经验做了以下尝试,全以失败告终,并且每种方式的缺点各不同。如果大家都成功的案例,欢迎留言交流。
一、尝试一:使用DocumentXaml
参考网址:
Richtextbox wpf绑定 | 那些遇到过的问题
失败原因:CurrentAlarmInputInfoStr为string类型,无法正常绑定属性,即赋值后页面无显示且页面输入后CurrentAlarmInputInfoStr值不更新。
<!--Xaml文件-->
<RichTextBox RichTextBoxHelper1:RichTextBoxHelper.DocumentXaml="{Binding CurrentAlarmInputInfoStr}" />
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.Documents;
namespace Dev_SING.Infrastructure.Controls.RichTextBox
{
public class RichTextBoxHelper : DependencyObject
{
public static string GetDocumentXaml(DependencyObject obj)
{
return (string)obj.GetValue(DocumentXamlProperty);
}
public static void SetDocumentXaml(DependencyObject obj, string value)
{
obj.SetValue(DocumentXamlProperty, value);
}
public static readonly DependencyProperty DocumentXamlProperty =
DependencyProperty.RegisterAttached(
"DocumentXaml",
typeof(string),
typeof(RichTextBoxHelper),
new FrameworkPropertyMetadata
{
BindsTwoWayByDefault = true,
PropertyChangedCallback = (obj, e) =>
{
var richTextBox = (RichTextBox)obj;
// Parse the XAML to a document (or use XamlReader.Parse())
var xaml = GetDocumentXaml(richTextBox);
var doc = new FlowDocument();
var range = new TextRange(doc.ContentStart, doc.ContentEnd);
range.Load(new MemoryStream(Encoding.UTF8.GetBytes(xaml)),
DataFormats.Xaml);
// Set the document
richTextBox.Document = doc;
// When the document changes update the source
range.Changed += (obj2, e2) =>
{
if (richTextBox.Document == doc)
{
MemoryStream buffer = new MemoryStream();
range.Save(buffer, DataFormats.Xaml);
SetDocumentXaml(richTextBox,
Encoding.UTF8.GetString(buffer.ToArray()));
}
};
}
});
}
}
二、尝试二:使用string和FlowDocument相互转化方式
参考网址:WPF RichTextBox·绑定数据_wpf textbox绑定数据-CSDN博客
失败原因:可以正常绑定属性读写内容,但是我这里绑定的是一个弹框的内容,用这种方式只能打开一次窗口,第二次及以后都无法打开。没有代码报错和其他问题,不知道为什么会影响第二个窗口打开。
1.BinBindableRichTextBox类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
namespace Dev_SING.Infrastructure.Controls.RicheTextBox
{
public class BindableRichTextBox : RichTextBox
{
public new FlowDocument Document
{
get { return (FlowDocument)GetValue(DocumentProperty); }
set { SetValue(DocumentProperty, value); }
}
// Using a DependencyProperty as the backing store for Document. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DocumentProperty =
DependencyProperty.Register("Document", typeof(FlowDocument), typeof(BindableRichTextBox), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnDucumentChanged)));
private static void OnDucumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
RichTextBox rtb = (RichTextBox)d;
rtb.Document = (FlowDocument)e.NewValue;
}
}
}
2.在Xmal中添加控件,CurrentAlarmInputInfo为FlowDocument类型。
<RichTextBoxHelper1:BindableRichTextBox Document="{Binding CurrentAlarmInputInfo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
3.ViewModel
private FlowDocument currentAlarmInputInfo = new FlowDocument();
public FlowDocument CurrentAlarmInputInfo { get => currentAlarmInputInfo; set { currentAlarmInputInfo = value; OnPropertyChanged(() => CurrentAlarmInputInfo); } }
4.将字符串转换成FlowDocument
/// <summary>
/// 将字符串转换成FlowDocument
/// </summary>
/// <param name="str">原始字符串</param>
/// <param name="fld">要被赋值的Flowdocument</param>
/// <param name="par">要添加到Flowdocument里的Paragraph</param>
public void StrToFlDoc(string str, Paragraph par)
{
//Paragraph par = new Paragraph();
//当递归结束以后,也就是长度为0的时候,就跳出
if (str.Length <= 0)
{
CurrentAlarmInputInfo.Blocks.Add(par);
return;
}
//如果字符串里不存在[时,则直接添加内容
if (!str.Contains('['))
{
par.Inlines.Add(new Run(str));
str = str.Remove(0, str.Length);
StrToFlDoc(str, par);
}
else
{
//设置字符串长度
int strLength = str.Length;
par.Inlines.Add(new Run(GetTextByRegex(str)));
str = str.Remove(0, GetTextByRegex(str).Length);
StrToFlDoc(str, par);
}
}
/// <summary>
/// 获取文本信息
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
private string GetTextByRegex(string str)
{
string text = Regex.Match(str, "^.*?(?=\\[)").Value;
return text;
}
5.将Document里的值都换成String
/// <summary>
/// 将Document里的值都换成String
/// </summary>
public string GetSendMessage(FlowDocument fld)
{
if (fld == null)
{
return string.Empty;
}
string resutStr = string.Empty;
foreach (var root in fld.Blocks)
{
foreach (var item in ((Paragraph)root).Inlines)
{
if (item is Run)
{
resutStr += ((Run)item).Text;
}
}
}
return resutStr;
}
三、使用嵌套Run方式
失败原因:CurrentAlarmInputInfoStr为string类型,正常绑定读写属性。存在一个问题,在第一次输入内容保存后,下次RichTextBox被赋值上次的已保存的内容可以正常显示,但是再进行修改的时候,必须将RichTextBox全部内容删除输入才可以写入CurrentAlarmInputInfoStr,否则只修改一部分内容继续编辑的话CurrentAlarmInputInfoStr还是上次保存的内容,未改变。
1.Xaml
<RichTextBox x:Name="AlarmInputRichTB">
<FlowDocument>
<Paragraph>
<Run Text="{Binding CurrentAlarmInputInfoStr,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</Paragraph>
</FlowDocument>
</RichTextBox>