如何在不使我的主表单卡住的情况下安全地提供我的功能

时间:2014-12-12 18:19:48

标签: c# wpf visual-studio-2010 visual-studio datagridviewcolumn

我制作了一个WPF应用程序,它有一个按钮来移动附加的一些文件 从一列到另一列的列单元格。我按的那一刻 按钮显示一个漂亮的动画并将所有文件移动到下一列的单元格。

但我真正的问题是,一旦我给我的函数color_check(), 我的申请被卡住了。我真的不知道为什么。在那儿 我能为此得到任何帮助吗?

代码:

 private void button3_Click(object sender, EventArgs e)
    {
        Hide();
        bool done = false;
        ThreadPool.QueueUserWorkItem((x) =>
        {
            using (var splashForm = new Form4())
            {
                splashForm.Show();
                while (!done)

                    Application.DoEvents();
                splashForm.Close();
            }
        });

        move(); //file moving function
        //color_check();  if i give this fn, my form stucks and comes to live after 10 - 20 sec
        done = true;
        MessageBox.Show("TEST FINISHED");
        Show();
    }

 public void color_check()  //this is my problem making fn
    {
        dataGridView1.Refresh();
         string strVal = ini.ReadValue("Action", "Doc-Controller");

        bool authenticated = true;

        if (authenticated == UserInCustomRole(strVal))
        {
            foreach (DataGridViewRow row in dataGridView1.Rows)
            {
                // Application.DoEvents(); 
                string fName1 = System.IO.Path.GetFileNameWithoutExtension(row.Cells[3].Value.ToString());
                string fName2 = System.IO.Path.GetFileNameWithoutExtension(row.Cells[4].Value.ToString());
                if (!string.IsNullOrEmpty(fName1) && !string.IsNullOrEmpty(fName2))
                {
                    var f1 = GetValue(fName1.ToCharArray()[fName1.Length - 2]) * 16 + GetValue(fName1.ToCharArray()[fName1.Length - 1]);
                    var f2 = GetValue(fName2.ToCharArray()[fName2.Length - 2]) * 16 + GetValue(fName2.ToCharArray()[fName2.Length - 1]);
                    //if (System.IO.Path.GetFileName(fName1) != System.IO.Path.GetFileName(fName2))
                    if (f1 > f2)
                    {
                        //MessageBox.Show(fName1);
                        DataGridViewCellStyle style = new DataGridViewCellStyle();
                        style.BackColor = Color.Yellow;
                        row.Cells[3].Style = style;
                    }
                    else if (f2 > f1)
                    {
                        //MessageBox.Show(fName1);
                        DataGridViewCellStyle style = new DataGridViewCellStyle();
                        style.BackColor = Color.Yellow;
                        row.Cells[4].Style = style;
                    }

                    if (f1 == f2)
                    {
                        DataGridViewCellStyle style = new DataGridViewCellStyle();
                        style.BackColor = Color.Plum;
                        row.Cells[4].Style = style;
                        row.Cells[3].Style = style;
                    }
                }
            }

    }

2 个答案:

答案 0 :(得分:2)

问题是您在button3_click()上调用的代码阻止了UI线程。这就是它冻结一段时间的原因 - 代码正在执行,一旦完成,UI线程就会再次响应。

解决此问题的方法是在另一个线程上异步执行操作。在.NET 4及更高版本中,您可以使用Tasks和async / await关键字来帮助您管理它。如果您使用的是早于.NET 4的版本,那么您将需要查看与您的.NET版本兼容的BackgroundWorker或其他线程选项。

请注意,如果要在异步方法中修改GUI,可能需要使用Dispatcher.Invoke()来安全地执行此操作。

以下是一些帮助您了解可用方法的链接

C# Blog on Understanding a simple async program

MSDN reference for async/await

Related StackOverflow question on how to use BackgroundWorkers

Related StackOverflow question on how to access the UI thread directly

答案 1 :(得分:1)

在普通的UI应用程序中,在GUI上运行的2个函数不会同时运行。否则会导致很多问题,这通常会导致程序崩溃。例如,可能有两个函数同时运行,每个函数检查相同的列表是否至少有一个元素,然后删除一个元素 - 因为它们同时运行,它们首先检查列表是否有1个元素。

这就是为什么GUI函数都在同一个线程中运行的原因,这意味着它们一次只能运行一个。当color_check运行时,其他功能不会运行。

您可以启动其他线程并对并行执行的线程进行操作,您可以加快color_check功能,例如将其分解为一次以较低优先级运行的部分,使用调度员

拿这个:

public void color_check()  //this is my problem making fn
{
    dataGridView1.Refresh();
    string strVal = ini.ReadValue("Action", "Doc-Controller");

    bool authenticated = true;

    if (authenticated == UserInCustomRole(strVal))
    {
        foreach (DataGridViewRow row in dataGridView1.Rows)
        {
           ProcessRow(row);
        }
    }
}

并将其更改为:

public void color_check()  //this is my problem making fn
{
    dataGridView1.Refresh();
    string strVal = ini.ReadValue("Action", "Doc-Controller");

    bool authenticated = true;

    if (authenticated == UserInCustomRole(strVal))
    {
        foreach (DataGridViewRow row in dataGridView1.Rows)
        {
           Dispatcher.BeginInvoke(DispatcherPriority.Background, ()=>{Process(row);});
        }
    }
}

在此代码中,Dispatcher.BeginInvoke告诉UI线程一旦找到时间就应该运行Process(row)。这可能导致等待执行的200个Process(row)调用。它仍然在UI线程上执行,一次只执行一件事。如果在完成前一百个之后发生鼠标点击,则GUI线程将首先完成第一个和第一个,然后处理鼠标点击,然后选择剩余的处理过程。

这种方法有一个缺点。通过允许在Process(row)的不同调用之间执行其他功能,您可能会得到令人惊讶的结果。特别是如果这些其他过程也改变了细胞样式。