C#、WPF -> GUI 在后台工作线程中更新时不应冻结

本文关键字:更新 线程 冻结 工作 后台 WPF GUI | 更新日期: 2023-09-27 18:37:24

这是我到目前为止的项目:

private void test()
    {
        var rows = GetDataGridRows(dgVarConfig);
        Dictionary<TextBlock, String> dic = new Dictionary<TextBlock, string>();
        foreach (DataGridRow r in rows)
        {
            TextBlock tb = cMatchEx.GetCellContent(r) as TextBlock;
            dic.Add(tb, tb.Text);
        }
        if (!syntaxWorker.IsBusy)
            syntaxWorker.RunWorkerAsync(dic);
    }

    private void syntaxWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        if (e.Argument == null)
            Thread.Sleep(100);
        else
        {
            Dictionary<TextBlock, String> dic = (Dictionary<TextBlock, String>)e.Argument;
            foreach (KeyValuePair<TextBlock, String> kvp in dic)
            {
                kvp.Key.Dispatcher.BeginInvoke(new Action(() =>
                {
                    kvp.Key.Inlines.Clear();
                    Syntax.Highlight(kvp.Value).ForEach(x => kvp.Key.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;
            }
        }
    }
}

使用此代码,gui 冻结约 2 秒。有没有办法逐步建立 gui 并避免任何冻结?看看它是如何建立的没有问题,只是冻结是一个问题。

希望有人知道如何解决这个问题。

C#、WPF -> GUI 在后台工作线程中更新时不应冻结

你可以像

这样将大部分工作移到调用之外:

一个小警告:我不完全确定您如何检索文本框的文本。 您可能需要为此执行单独的调用(请参阅代码中的注释)

public class RunInfo
{
    public string Content { get; set;}
    public Color foreground { get; set; }
    public RunInfo(string content)
    {
        Content = content;
    }
    public Run AsRun()
    {
       return new Run(Content){ Foreground = foreground };
    }
}

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<RunInfo> 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 RunInfo(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;
            }
        }
    }
}


private void syntaxWorker_DoWork(object sender, DoWorkEventArgs e)
{
    if (e.Argument == null)
        Thread.Sleep(100);
    else
    {
        Dictionary<TextBlock, String> dic = (Dictionary<TextBlock, String>)e.Argument;
        foreach (KeyValuePair<TextBlock, String> kvp in dic)
        {
            //i am unsure if this line will work. if it does not, you might need to do a separate dispatcher invoke in order to retreive the text from the textbox.
            List<RunInfo> runinfoObjects = Syntax.Highlight(kvp.Value); 
            kvp.Key.Dispatcher.BeginInvoke(new Action(() => 
            {
                kvp.Key.Inlines.Clear();
                //we'd run into problems here, since wpf won't allow us to add elements created in a background thread. since we now make the Run object inside the invoke, we should be fine.
                runinfoObjects.ForEach(x => kvp.Key.Inlines.Add(x.AsRun()));
            }));
        }
    }
}