我制作了一个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;
}
}
}
}
答案 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)
的不同调用之间执行其他功能,您可能会得到令人惊讶的结果。特别是如果这些其他过程也改变了细胞样式。