C# STA线程、Rtf到HTML转换器问题
我正在使用尝试将我的Rtf文本从UI中的C# STA线程、Rtf到HTML转换器问题,c#,wpf,multithreading,mvvm,C#,Wpf,Multithreading,Mvvm,我正在使用尝试将我的Rtf文本从UI中的RichTextBox转换为Html。我的解决方案中有两个项目:用MVVM编写的UI和应用程序-IsesTextEditor和链接中提供的预写转换器-MarkupConverter my view中的btn绑定到my view模型中的命令,该命令将RichTextBox文本传递到ConvertRtfToHtml方法中,如示例所示: private string ConvertRtfToHtml(string PastedText) {
RichTextBox
转换为Html。我的解决方案中有两个项目:用MVVM编写的UI和应用程序-IsesTextEditor
和链接中提供的预写转换器-MarkupConverter
my view中的btn绑定到my view模型中的命令,该命令将RichTextBox文本传递到ConvertRtfToHtml方法中,如示例所示:
private string ConvertRtfToHtml(string PastedText)
{
var thread = new Thread(ConvertRtfInSTAThread);
var threadData = new ConvertRtfThreadData { RtfText = PastedText };
thread.SetApartmentState(ApartmentState.STA);
thread.Start(threadData);
thread.Join();
return threadData.HtmlText;
}
private void ConvertRtfInSTAThread(object rtf)
{
var threadData = rtf as ConvertRtfThreadData;
threadData.HtmlText = markupConverter.ConvertRtfToHtml(threadData.RtfText);
}
private class ConvertRtfThreadData
{
public string RtfText { get; set; }
public string HtmlText { get; set; }
}
然后,MarkupConverter.ConvertRtfToHtml
方法调用ConvertRtfToXaml
,该方法实例化一个新的RichTextBox
对象:
public static class RtfToHtmlConverter
{
private const string FlowDocumentFormat = "<FlowDocument>{0}</FlowDocument>";
public static string ConvertRtfToHtml(string rtfText)
{
var xamlText = string.Format(FlowDocumentFormat, ConvertRtfToXaml(rtfText));
return HtmlFromXamlConverter.ConvertXamlToHtml(xamlText, false);
}
private static string ConvertRtfToXaml(string rtfText)
{
var richTextBox = new RichTextBox();
if (string.IsNullOrEmpty(rtfText)) return "";
var textRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
using (var rtfMemoryStream = new MemoryStream())
{
using (var rtfStreamWriter = new StreamWriter(rtfMemoryStream))
{
rtfStreamWriter.Write(rtfText);
rtfStreamWriter.Flush();
rtfMemoryStream.Seek(0, SeekOrigin.Begin);
textRange.Load(rtfMemoryStream, DataFormats.Rtf);
}
}
using (var rtfMemoryStream = new MemoryStream())
{
textRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
textRange.Save(rtfMemoryStream, DataFormats.Xaml);
rtfMemoryStream.Seek(0, SeekOrigin.Begin);
using (var rtfStreamReader = new StreamReader(rtfMemoryStream))
{
return rtfStreamReader.ReadToEnd();
}
}
}
}
公共静态类RtfToHtmlConverter
{
私有常量字符串FlowDocumentFormat=“{0}”;
公共静态字符串转换器RTFTOHTML(字符串rtfText)
{
var xamlText=string.Format(FlowDocumentFormat,ConvertRtfToXaml(rtfText));
返回HtmlFromXamlConverter.ConvertXamlToHtml(xamlText,false);
}
专用静态字符串转换器RTFTOXAML(字符串rtfText)
{
var richTextBox=新的richTextBox();
if(string.IsNullOrEmpty(rtfText))返回“”;
var textRange=new textRange(richTextBox.Document.ContentStart,richTextBox.Document.ContentEnd);
使用(var rtfMemoryStream=new MemoryStream())
{
使用(var rtfStreamWriter=newstreamwriter(rtfMemoryStream))
{
rtfStreamWriter.Write(rtfText);
rtfStreamWriter.Flush();
rtfMemoryStream.Seek(0,SeekOrigin.Begin);
加载(rtfMemoryStream,DataFormats.Rtf);
}
}
使用(var rtfMemoryStream=new MemoryStream())
{
textRange=新的textRange(richTextBox.Document.ContentStart,richTextBox.Document.ContentEnd);
保存(rtfMemoryStream,DataFormats.Xaml);
rtfMemoryStream.Seek(0,SeekOrigin.Begin);
使用(var rtfStreamReader=newstreamreader(rtfMemoryStream))
{
返回rtfStreamReader.ReadToEnd();
}
}
}
}
在创建RichTextBox
对象时,我得到了一个调用线程无法访问此对象,因为它是另一个线程拥有的。
异常
有人能建议解决这个问题吗?我确信这是一个相对简单的线程问题,但我是一个初级开发人员&在线程或STA方面没有太多经验…例外情况是,将GUI相关代码从工作线程移动到GUI线程 请参考,我从中复制了一些文本:
与用户界面的框架一样,与许多Windows窗体一样,WPF也强制使用单个线程模型,这意味着您只能访问创建它的指定派生DispatcherObject线程。在实现ISynchronizeInvoke接口的Windows窗体控件中,此接口公开了一组方法,如Invoke和BeginInvoke,以强制执行协定公共线程同步,我们可以使用这些方法从另一个线程访问控件。在WPF中,我们也有这类操作,但是这些操作涉及到一个名为Dispatcher的类,Dispatcher WPF是允许这种线程同步模型的方法。要在不是主UI线程的线程上使用WPF控件,您需要做一些准备,比如启动和完成WPF Dispatcher循环 我已经用我之前发布的一些帮助代码编写了一个示例应用程序,展示了如何做到这一点 这是一个控制台应用程序,不过您应该能够在任何其他执行环境中使用
RunOnWpfThreadAsync(()=>ConvertRtfToXaml(RTF)).Result
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Threading;
namespace ConsoleApplication_22717365
{
// by Noseratio - https://stackoverflow.com/q/22717365/1768303
public class Program
{
const string RTF = @"{\rtf1\ansi{\fonttbl\f0\fswiss Helvetica;}\f0\pard This is some {\b bold} text.\par}";
static void Main()
{
var xaml = RunOnWpfThreadAsync(() => ConvertRtfToXaml(RTF)).Result;
Console.WriteLine(xaml);
}
// http://code.msdn.microsoft.com/windowsdesktop/Converting-between-RTF-and-aaa02a6e
private static string ConvertRtfToXaml(string rtfText)
{
var richTextBox = new RichTextBox();
if (string.IsNullOrEmpty(rtfText)) return "";
var textRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
using (var rtfMemoryStream = new MemoryStream())
{
using (var rtfStreamWriter = new StreamWriter(rtfMemoryStream))
{
rtfStreamWriter.Write(rtfText);
rtfStreamWriter.Flush();
rtfMemoryStream.Seek(0, SeekOrigin.Begin);
textRange.Load(rtfMemoryStream, DataFormats.Rtf);
}
}
using (var rtfMemoryStream = new MemoryStream())
{
textRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
textRange.Save(rtfMemoryStream, DataFormats.Xaml);
rtfMemoryStream.Seek(0, SeekOrigin.Begin);
using (var rtfStreamReader = new StreamReader(rtfMemoryStream))
{
return rtfStreamReader.ReadToEnd();
}
}
}
// https://stackoverflow.com/a/22626704/1768303
public static async Task<TResult> RunOnWpfThreadAsync<TResult>(Func<Task<TResult>> funcAsync)
{
var tcs = new TaskCompletionSource<Task<TResult>>();
Action startup = async () =>
{
// this runs on the WPF thread
var task = funcAsync();
try
{
await task;
}
catch
{
// propagate exception with tcs.SetResult(task)
}
// propagate the task (so we have the result, exception or cancellation)
tcs.SetResult(task);
// request the WPF tread to end
// the message loop inside Dispatcher.Run() will exit
System.Windows.Threading.Dispatcher.ExitAllFrames();
};
// the WPF thread entry point
ThreadStart threadStart = () =>
{
// post the startup callback
// it will be invoked when the message loop starts pumping
System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(
startup, DispatcherPriority.Normal);
// run the WPF Dispatcher message loop
System.Windows.Threading.Dispatcher.Run();
};
// start and run the STA thread
var thread = new Thread(threadStart);
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
try
{
// propagate result, exception or cancellation
return await tcs.Task.Unwrap().ConfigureAwait(false);
}
finally
{
// make sure the thread has fully come to an end
thread.Join();
}
}
// a wrapper to run synchronous code
public static Task<TResult> RunOnWpfThreadAsync<TResult>(Func<TResult> func)
{
return RunOnWpfThreadAsync(() => Task.FromResult(func()));
}
}
}
使用系统;
使用System.IO;
使用系统线程;
使用System.Threading.Tasks;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Documents;
使用System.Windows.Threading;
命名空间控制台应用程序\u 22717365
{
//按比例—https://stackoverflow.com/q/22717365/1768303
公共课程
{
常量字符串RTF=@“{\rtf1\ansi{\fonttbl\f0\fswiss Helvetica;}\f0\pard这是一些{\b bold}文本。\par}”;
静态void Main()
{
var xaml=RunOnWpfThreadAsync(()=>ConvertRtfToXaml(RTF))。结果;
控制台写入线(xaml);
}
// http://code.msdn.microsoft.com/windowsdesktop/Converting-between-RTF-and-aaa02a6e
专用静态字符串转换器RTFTOXAML(字符串rtfText)
{
var richTextBox=新的richTextBox();
if(string.IsNullOrEmpty(rtfText))返回“”;
var textRange=new textRange(richTextBox.Document.ContentStart,richTextBox.Document.ContentEnd);
使用(var rtfMemoryStream=new MemoryStream())
{
使用(var rtfStreamWriter=newstreamwriter(rtfMemoryStream))
{
rtfStreamWriter.Write(rtfText);
rtfStreamWriter.Flush();
rtfMemoryStream.Seek(0,SeekOrigin.Begin);
加载(rtfMemoryStream,DataFormats.Rtf);
}
}
使用(var rtfMemoryStream=new MemoryStream())
{
textRange=新的textRange(richTextBox.Document.ContentStart,richTextBox.Document.ContentEnd);
保存(rtfMemoryStream,DataFormats.Xaml);
rtfMemoryStream.Seek(0,SeekOrigin.Begin);
使用(var rtfStreamReader=newstreamreader(rtfMemoryStream))
{
返回rtfStreamReader.ReadToEnd();
}
}
}
// https://stackoverflow.com/a/22626704/1768303
公共静态异步任务RunOnWpfThreadAsync(Func-funcAsync)
{
var tcs=new TaskCompletionSource();
操作启动=异步()=>
{
//这在WPF线程上运行
var task=funcAsync();
尝试
{