我想建立一个应用程序,有一个WPF用户界面和做一些后台任务与文件转换。显示操作的进展,我使用TexBoxOutputter。
我已经将控制台输出链接到我的TexBoxOutputter并将两个线程与调度器链接。现在我可以在后台任务中使用Console.Writeline命令,以便写入UI,我现在尝试转换哪个文件。
这个过程一般工作良好。但现在的要求是在一个步骤中转换大约500个文件的数量。后台程序非常快,所以这是在大约30s用于整个500个文件。现在的问题是,如果我在每个文件后将文件的名称写入控制台,我的UI线程库存和崩溃,整个过程需要更长的时间。我的猜测是,原因是console.WriteLine超载我的UI线程。
那么,如果我想在我的UI上显示相同的功能,但以更稳定,至少更快的方式转换哪个文件,我需要改变什么?
下面是一些代码片段:TesxBox输出:
public class TextBoxOutputter : TextWriter
{
volatile TextBox textBox = null;
int count = 0;
public TextBoxOutputter(TextBox output)
{
textBox = output;
}
public override void Write(char value)
{
base.Write(value);
UpdateTextBox(value.ToString());
}
private void UpdateTextBox(string text)
{
if (textBox.Dispatcher.CheckAccess())
{
textBox.AppendText(text);
}
else
{
textBox.Dispatcher.BeginInvoke(new Action(() =>
{
textBox.AppendText(text);
count = count + 1;
//test Scroll down only after 30 lines added because otherwhise main UI thread will be locked.
if (count >= 30)
{
count = 0;
textBox.ScrollToEnd();
}
}));
}
}
public override Encoding Encoding
{
get { return System.Text.Encoding.UTF8; }
}
}
}
UI控制台链接到输出器:
outputter = new TextBoxOutputter(ConsoleOutput);
Console.SetOut(outputter);
线程:
void StartProcess(object sender, RoutedEventArgs e)
{
worker.WorkerReportsProgress = true;
worker.WorkerSupportsCancellation = true;
if (SourcePath != null)
{
worker = new BackgroundWorker();
worker.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker2_DoWork);
}
TheProgressbar.IsIndeterminate = true;
worker.RunWorkerAsync();
}
private Thread _thread = null;
private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
{
ThreadStart threadStart = new ThreadStart(StartConversion);
_thread = new Thread(threadStart);
_thread.SetApartmentState(ApartmentState.STA);
_thread.Start();
}
1条答案
按热度按时间hgqdbh6s1#
主要问题是
TextBox
的性能不佳。如果你需要输入和输出,你必须创建一个组合控件,其中包含一个
ListBox
用于输出,一个TextBox
用于输入。好处是ListBox
提供了UI虚拟化。添加一个项目应该比操作一个长的多行字符串更快。如果你覆盖了
ListBoxItem
的模板,你就可以删除交互行为(比如鼠标悬停效果)。这会让ListBox
看起来像TextBox
。这个想法是将
ListBox
堆叠在TextBox
之上。结果是一个经典的文本控制台,只有一行文本输入。当用户按下回车键时,您将输入添加到反向的(上下颠倒)ListBox
,然后清除TextBox
。结果是发送行向上移动,而输入行保持在底部。就像经典的控制台一样。下面的例子展示了这样一个简单的文本控制台。
TextConsole
能够在按下Enter键或通过SendInputCommand
(路由命令)发送输入(向上滚动)。它还允许将字符串的源集合绑定到TextConsole.ConsoleOutputSource
属性。这使您可以更新控制台,而无需发送显式用户输入(例如报告进度)。
TextConsole.cs
泛型.xaml
此外,你必须修复你的线程代码。你应该检查你用来转换文件的API是否公开了一个异步API,该API启用了自然的async/await以增强性能。
这样的API比多线程更受欢迎。下面的代码是修改后的原始代码版本,可以使用
TextConsole
控件。主窗口.xaml
MainWindow.xaml.cs
TextConsoleWriter.cs