Change TextBlock.Inlines from Backgroundworker
本文关键字:Backgroundworker from Inlines TextBlock Change | 更新日期: 2023-09-27 18:37:15
有没有办法从后台工作者更改内联?
我尝试了以下方法:
private void test()
{
var rows = GetDataGridRows(dgVarConfig);
foreach (DataGridRow r in rows)
{
TextBlock tb = cMatchEx.GetCellContent(r) as TextBlock;
if (!syntaxWorker.IsBusy)
syntaxWorker.RunWorkerAsync(new KeyValuePair<TextBlock, String>(tb, tb.Text));
}
}
private void syntaxWorker_DoWork(object sender, DoWorkEventArgs e)
{
if (e.Argument == null)
Thread.Sleep(100);
else
{
KeyValuePair<TextBlock, String> kvp = (KeyValuePair<TextBlock, String>)e.Argument;
e.Result = new KeyValuePair<TextBlock, List<Run>>(kvp.Key, Syntax.Highlight(kvp.Value));
}
}
private void syntaxWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Result != null)
{
KeyValuePair<TextBlock, List<Run>> kvp = (KeyValuePair<TextBlock, List<Run>>)e.Result;
TextBlock tb = kvp.Key;
tb.Text = "";
kvp.Value.ForEach(x => tb.Inlines.Add(x));
}
}
和语法类:
public static class Syntax
{
static Regex subFormula = new Regex(@"'w+'(')");
static Regex sapFormula = new Regex(@"'w+'(([^)]+)')");
static Regex strings = new Regex(@"''[^']+''");
static Regex numerals = new Regex(@"'b[0-9'.]+'b");
static Regex characteristic = new Regex(@"(?:)?'w+(?:)?");
static Regex andOr = new Regex(@"( and )|( AND )|( or )|( OR )");
static Regex not = new Regex(@"(not )|(NOT )");
private static Brush[] colorArray;
public static List<Run> Highlight(String input)
{
colorArray = new Brush[input.Length];
for (int i = 0; i < input.Length; i++)
colorArray[i] = Brushes.Black;
//Reihenfolge beibehalten!!
assignColor(Brushes.Blue, characteristic.Matches(input));
assignColor(Brushes.Black, andOr.Matches(input));
assignColor(Brushes.Black, numerals.Matches(input));
assignColor(Brushes.Orange, strings.Matches(input));
assignColor(Brushes.DeepPink, subFormula.Matches(input));
assignColor(Brushes.Green, sapFormula.Matches(input));
assignColor(Brushes.Green, not.Matches(input));
int index = 0;
List<Run> runList = new List<Run>();
foreach (Char character in input)
{
runList.Add(new Run(character.ToString()) { Foreground = colorArray[index] });
index++;
}
colorArray = null;
return runList;
}
public static void Check(TextBlock textBlock)
{
}
private static void assignColor(Brush brush, MatchCollection matchCollection)
{
foreach (Match match in matchCollection)
{
int start = match.Index;
int end = start + match.Length;
for (int i = start; i < end; i++)
{
colorArray[i] = brush;
}
}
}
}
我总是收到此错误:The calling thread cannot access this object because a different thread owns it.
我尝试了许多不同的方法:返回进度更改的 runList,将静态语法类更改为普通类......但没有任何效果,它总是相同的错误。
我还尝试从后台工作者调用它..这意味着调用
List<Run> runList = Syntax.Highlight(kvp.Value);
this.Dispatcher.Invoke((Action)(() =>
{
runList.ForEach(x => publicRunList.Add(x));
}));
有人知道问题吗?
使用
tb.Dispatcher.Invoke(() => {
tb.Text = "";
kvp.Value.ForEach(x => tb.Inlines.Add(x));
});
而不是
tb.Text = "";
kvp.Value.ForEach(x => tb.Inlines.Add(x));
Gui 元素只能从 Gui 线程访问。使用 Dispatcher.Invoke
可确保调用的操作在其上运行。
您还将在 Syntax.Highlight
中创建Run
对象。您还必须在 Gui 线程上创建 Gui 元素。因此,您还应该将此调用包装在调度程序调用中:
e.Result = new KeyValuePair<TextBlock, List<Run>>(kvp.Key, Syntax.Highlight(kvp.Value));
这应该有效:
//this runs synchronously
kvp.Key.Dispatcher.Invoke(() => {
e.Result = new KeyValuePair<TextBlock, List<Run>>(kvp.Key, Syntax.Highlight(kvp.Value));
});
//this runs asynchronously
kvp.Key.Dispatcher.BeginInvoke((Action)(() => {
e.Result = new KeyValuePair<TextBlock, List<Run>>(kvp.Key, Syntax.Highlight(kvp.Value));
}));
这可能违背了您最初想要使用BackgroundWorker
的目的。我建议更改 Syntax.Highlight
的接口以返回带有字符串和突出显示颜色的元组列表,然后在 Gui 线程上创建Run
对象。
编辑:
正如Gopichandar所指出的,使用BeginInvoke
异步执行给定的操作,因此可以解决应用程序的冻结问题。不过,在将所有元素添加到 Gui 之前,仍然需要几秒钟。
在 WPF 中,只有 UI 元素所属的线程(即 UI 线程)可以与其通信。BackgroundWorker 的 DoWork 部分在不同的线程中执行,因此无法执行任何与 UI 相关的操作。同样的事情也适用于计时器而不是BackgroundWorkers。
但是,如果使用var worker = new BackgroundWorker {WorkerReportsProgress = true};
创建后台工作者,则可以为ProgressChanged
设置事件处理程序。在 _DoWork()
中,您可以说: (sender as BackgroundWorker).ReportProgress
,这将在原始线程中调用您的 ProgressChanged
事件处理程序,您可以在其中操作 UI 元素。
完整示例:http://www.wpf-tutorial.com/misc/multi-threading-with-the-backgroundworker/