listView的交叉线程问题
本文关键字:线程 问题 listView | 更新日期: 2023-09-27 17:49:51
好的,在每个人发布重复的帖子之前,让我告诉你,我已经看过所有其他的帖子,我仍然丢失了一些说使用委托或后台工作器等…但我如何使这个线程安全,我想删除自己的线程上的文件。
这里是我正在使用的代码。
private void button1_Click(object sender, EventArgs e)
{
cleanFiles.RunWorkerAsync();
}
private void cleanFiles_DoWork(object sender, DoWorkEventArgs e)
{
if (listView1.CheckedItems.Count != 0)
{
// If so, loop through all checked files and delete.
for (int x = 0; x <= listView1.CheckedItems.Count - 1; x++)
{
string tempDirectory = Path.GetTempPath();
foreach (ListViewItem item in listView1.CheckedItems)
{
string fileName = item.Text;
string filePath = Path.Combine(tempDirectory, fileName);
try
{
File.Delete(filePath);
}
catch (Exception)
{
//ignore files being in use
}
}
}
PaintListView(tFile);
MessageBox.Show("Files removed");
toolStripStatusLabel1.Text = ("Ready");
}
else
{
MessageBox.Show("Please put a check by the files you want to delete");
}
}
正如Reed提到的,除了UI线程本身,你不能从其他线程访问UI元素。因此,你需要传递一个委托Control.Invoke()
来与UI线程一起执行,像这样
试
private void cleanFiles_DoWork(object sender, DoWorkEventArgs e)
{
if (listView1.CheckedItems.Count != 0)
{
// If so, loop through all checked files and delete.
for (int x = 0; x <= listView1.CheckedItems.Count - 1; x++)
{
string tempDirectory = Path.GetTempPath();
foreach (ListViewItem item in listView1.CheckedItems)
{
string fileName = item.Text;
string filePath = Path.Combine(tempDirectory, fileName);
try
{
File.Delete(filePath);
}
catch (Exception)
{
//ignore files being in use
}
}
}
PaintListViewAndSetLabel();
}
else
{
ShowMessageBox();
}
}
private void ShowMessageBox()
{
if(InvokeRequired)
{
this.Invoke(new Action(ShowMessageBox), new object[0]);
return;
}
MessageBox.Show("Please put a check by the files you want to delete");
}
private void PaintListViewAndSetLabel()
{
if (InvokeRequired)
{
this.Invoke(new Action(PaintListViewAndSetLabel),new object[0]);
return;
}
PaintListView(tFile);
MessageBox.Show("Files removed");
toolStripStatusLabel1.Text = ("Ready");
}
问题是你不能直接从后台线程访问ListView (listView1
)的任何属性(即:cleanFiles_DoWork
方法中的任何内容)。用户界面控件不能在用户界面线程以外的任何线程上访问。
相反,你应该在调用DoWork之前制作一个要"清理"的项目列表,并通过RunWorkerAsync重载传递给一个对象,并通过DoWorkEventArgs.Argument在你的方法中检索它。
这将允许你传递一个项目列表来处理,在后台处理它们,然后当你完成时更新你的列表。
使用来自后台worker的控件是个坏主意,我最近在使用TreeView控件时遇到了同样的问题。因此,线程安全调用Windows窗体控件的解决方案是微软的一篇文章。主要思想是使用控件的InvokeRequired
属性检查安全性,如果有必要,通过Invoke
方法运行方法调用,这是线程安全的。