C# 尝试更新datagridview时接口冻结
我正在使用下面的代码复制文件,并在C# 尝试更新datagridview时接口冻结,c#,datagridview,C#,Datagridview,我正在使用下面的代码复制文件,并在datagridview处设置status列,以通知用户连接已打开,但当我按下按钮执行时,连接已关闭 方法界面冻结 我已经搜索了很多我知道使用task.run()是不可能的,因为它不包括在中.not 4它是.net 4.5的一个新功能,我还知道Task.Factory.StartNew()来代替task.run(),但它作为隐式线程有很大的风险,我知道使用显式线程也是一个不错的选择 我想得到一些帮助,继续我的项目,继续学习,而不是在那个无聊的时刻堆积起来 pub
datagridview
处设置status列,以通知用户连接已打开,但当我按下按钮执行时,连接已关闭
方法界面冻结
我已经搜索了很多我知道使用task.run()代码>是不可能的,因为它不包括在中.not 4
它是.net 4.5
的一个新功能,我还知道Task.Factory.StartNew()可以使用code>来代替task.run(),但它作为隐式线程有很大的风险,我知道使用显式线程也是一个不错的选择
我想得到一些帮助,继续我的项目,继续学习,而不是在那个无聊的时刻堆积起来
public void PatchUpdates()
{
try
{
foreach (DataGridViewRow OfficeListRow in DGV_OfficeList.Rows)
{
string OfficeIPAddress = OfficeListRow.Cells[3].Value.ToString();
foreach (DataGridViewRow FileListRow in DGV_FileList.Rows)
{
string SoruceFileNamePath = FileListRow.Cells[4].Value.ToString();
string DestinationFileNamePath = @"\\" + OfficeIPAddress + @"\usb1_1\test\" + Path.GetFileName(SoruceFileNamePath);
//check if connection to remote server is available
var vResult = CheckOffice(OfficeIPAddress);
if (vResult == 1)
{
DGV_OfficeList[4, DGV_OfficeList.CurrentCell.RowIndex].Value = "Connected";
File.Copy(SoruceFileNamePath, DestinationFileNamePath, true); //copy files...
}
else if (vResult == 0)
{
DGV_OfficeList[4, DGV_OfficeList.CurrentCell.RowIndex].Value = "disconnected";
break;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
检查下面的办公室代码
public int CheckOffice(string _ipAddress)
{
int timeout = 120;
string data = "PingTestData";
byte[] buffer = Encoding.ASCII.GetBytes(data);
Ping PingSender = new Ping();
PingOptions options = new PingOptions();
options.DontFragment = true;
PingReply reply = PingSender.Send(_ipAddress, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
return 1;
}
else
{
return 0;
}
}
下面是我如何尝试制作线程,但这并不能解决我的问题
public void PatchUpdates()
{
try
{
foreach (DataGridViewRow OfficeListRow in DGV_OfficeList.Rows)
{
string OfficeIPAddress = OfficeListRow.Cells[2].Value.ToString();
foreach (DataGridViewRow FileListRow in DGV_FileList.Rows)
{
string SoruceFileNamePath = FileListRow.Cells[4].Value.ToString();
string DestinationFileNamePath = @"\\" + OfficeIPAddress + @"\usb1_1\test\" + Path.GetFileName(SoruceFileNamePath);
Thread foregroundthread = new Thread(() => CheckOffice(OfficeIPAddress));
foregroundthread.Start();
//check if connection to remote server is available
if (CheckOffice(OfficeIPAddress) == 1)
{
DGV_OfficeList[3, DGV_OfficeList.CurrentCell.RowIndex].Value = "Connected";
//file.copy(sorucefilenamepath, destinationfilenamepath, true); //copy files...
}
else if (CheckOffice(OfficeIPAddress) == 0)
{
DGV_OfficeList[3, DGV_OfficeList.CurrentCell.RowIndex].Value = "disconnected";
break;
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
我也尝试过,但正如我所说,thask.run在dot net 4上不可用
var task = Task.Run(() =>
{
var result = CheckOffice(OfficeIPAddress);
this.BeginInvoke((Action)(() =>
{
if (result == 1)
{
DGV_OfficeList[4, DGV_OfficeList.CurrentCell.RowIndex].Value = "Connected";
//file.copy(sorucefilenamepath, destinationfilenamepath, true); //copy files...
}
else if (result == 0)
{
DGV_OfficeList[4, DGV_OfficeList.CurrentCell.RowIndex].Value = "disconnected";
}
}));
}
);
-------------------------------------------------------------更新-----------------------------------------------
public void PatchUpdates()
{
try
{
foreach (DataGridViewRow OfficeListRow in DGV_OfficeList.Rows)
{
string OfficeIPAddress = OfficeListRow.Cells[3].Value.ToString();
int RowNum = OfficeListRow.Index;
foreach (DataGridViewRow FileListRow in DGV_FileList.Rows)
{
string SoruceFileNamePath = FileListRow.Cells[4].Value.ToString();
//string DestinationFileNamePath = @"\\" + OfficeIPAddress + @"\usb1_1\test\" + Path.GetFileName(SoruceFileNamePath);
string DestinationFileNamePath = @"F:\test\" + Path.GetFileName(SoruceFileNamePath); //TestPurpose
Thread t2 = new Thread(new ThreadStart(() =>
{
int vResult = CheckOffice(OfficeIPAddress);
UpdateUI(vResult, RowNum, SoruceFileNamePath, DestinationFileNamePath, OfficeIPAddress);
}));
t2.Start();
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error Message", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
更新UI的UpdateUI方法
public void UpdateUI(int vResult, int RowNum, string SoruceFileNamePath, string DestinationFileNamePath,string OfficeIPAddress)
{
try
{
var timeNow = DateTime.Now;
if ((DateTime.Now - PreviousTime).Milliseconds <= 10)
return;
SynchronizationContext.Post(new SendOrPostCallback(o =>
{
if (vResult == 1)
{
DGV_OfficeList[4, RowNum].Value = "Connected";
//File.Copy(SoruceFileNamePath, DestinationFileNamePath, true);
//MessageBox.Show("Pingable " + OfficeIPAddress); //TestPurpose
}
else if (vResult == 0)
{
DGV_OfficeList[4, RowNum].Value = "Disconnected";
//MessageBox.Show("Not reachable"); //TestPurpose
}
}), vResult);
PreviousTime = timeNow;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
public void UpdateUI(int-vResult、int-RowNum、string-SoruceFileNamePath、string-DestinationFileNamePath、string-OfficeIPAddress)
{
尝试
{
var timeNow=DateTime.Now;
if((DateTime.Now-PreviousTime).ms
{
如果(vResult==1)
{
DGV_OfficeList[4,RowNum].Value=“已连接”;
//Copy(SoruceFileNamePath,DestinationFileNamePath,true);
//MessageBox.Show(“Pingable”+OfficeIPAddress);//TestPurpose
}
否则如果(vResult==0)
{
DGV_OfficeList[4,RowNum].Value=“已断开”;
//MessageBox.Show(“不可访问”);//TestPurpose
}
}),vResult);
以前的时间=现在的时间;
}
捕获(例外情况除外)
{
MessageBox.Show(例如Message,“Error”,MessageBoxButtons.OK,MessageBoxIcon.Error);
}
}
简短回答:您的代码没有问题。设计不好
长答案
你听到有人说“我一次只能做一件事!”这就是这里发生的事情。windows窗体应用程序的代码由一个线程执行,该线程一次只能执行一件事。当它ping时,它会等待回复。如果回复成功,则复制一个文件。因为您有一个循环,所以它会一直这样做,直到完成所有行
当它这样做的时候,你可能正在点击UI中的其他东西,但是你的线程“一次只能做一件事”。它忙着做循环中的事情。因此,当您单击时,您只需等待
那么如何修复它,使UI不会冻结?
简单地说,你需要这样做。想象你是一根线:
我是UI线程,我的最终目标是保持UI的响应性。我不希望UI冻结。因此,如果我需要做除UI工作以外的任何事情,我会请其他人来做。当其他人在做其他工作时,我可以自由地做UI工作
其他人是另一个线索。下面是一个示例,请阅读我在代码中的注释并将其应用于您的应用程序。如果要运行此代码,请使用名为label1
的标签和两个按钮创建一个表单Form1
。将按钮ClickHandlerAsync
分配给一个按钮的单击处理程序,并将停止\u单击
分配给另一个按钮
当您单击执行按钮ClickHandlerAsync
的按钮时,整个操作开始。当它工作时,您可以单击另一个按钮,它将显示一个消息框并保持响应。顺便说一句,我从中复制了这段代码,但我在代码中添加了自己的注释,这样您就知道发生了什么
public partial class Form1 : Form {
// We need this because this will allow us to interact with UI controls. UI controls can only be accessed by the thread that
// created the UI control. In this case it is the thread which started the application so the main thread.
private readonly SynchronizationContext synchronizationContext;
private DateTime previousTime = DateTime.Now;
public Form1() {
InitializeComponent();
synchronizationContext = SynchronizationContext.Current;
}
private void Stop_Click(object sender, EventArgs e) {
// I am the UI thread. I can do this because T2 is helping me do the loop.
MessageBox.Show( "I am doing other things." );
}
private async void ButtonClickHandlerAsync(object sender, EventArgs e) {
button1.Enabled = false;
var count = 0;
// I am the UI thread. I have other things to do. So please run this loop by using a thread from the thread pool.
// When you are done running the loop let me know (This is what the await does)
// I am the UI thread so I am going to return back from right here
// to the point where ButtonClickHandlerAsync was called from. (it was called by a click, so when it returns it will have nothing
// to do. Therefore, it will be ready to react to another UI job such as another click or update the UI etc.
await Task.Run( () =>
{
// I am a thread from the thread pool. My name is T2. I am helping the UI thread so the UI thread can do other things.
for( var i = 0; i <= 5000000; i++ ) {
UpdateUI( i );
count = i;
}
} );
// I am the UI thread. Ok looks like the loop is done. So I will do the following 2 lines of work
label1.Text = @"Counter " + count;
button1.Enabled = true;
}
public void UpdateUI(int value) {
// I am T2. I am helping the UI thread.
var timeNow = DateTime.Now;
if( ( DateTime.Now - previousTime ).Milliseconds <= 50 )
return;
// I do not have access to the UI controls since I did not create them. So I am just going to ask the synchronizationContext
// to do this for me by giving it a SendOrPostCallback
synchronizationContext.Post( new SendOrPostCallback( o =>
{
// I am the UI thread. I will do this.
label1.Text = @"Counter " + ( int ) o;
} ), value );
// I am T2. I will do this and then return and do more work.
previousTime = timeNow;
}
简短回答:您的代码没有问题。设计不好
长答案
你听到有人说“我一次只能做一件事!”这就是这里发生的事情。windows窗体应用程序的代码由一个线程执行,该线程一次只能执行一件事。当它ping时,它会等待回复。如果回复成功,则复制一个文件。因为您有一个循环,所以它会一直这样做,直到完成所有行
当它这样做的时候,你可能正在点击UI中的其他东西,但是你的线程“一次只能做一件事”。它忙着做循环中的事情。因此,当您单击时,您只需等待
那么如何修复它,使UI不会冻结?
简单地说,你需要这样做。想象你是一根线:
我是UI线程,我的最终目标是保持UI的响应性。我不希望UI冻结。因此,如果我需要做除UI工作以外的任何事情,我会请其他人来做。当其他人在做其他工作时,我可以自由地做UI工作
其他人是另一个线索。下面是一个示例,请阅读我在代码中的注释并将其应用于您的应用程序。如果要运行此代码,请使用名为label1
的标签和两个按钮创建一个表单Form1
。将按钮ClickHandlerAsync
分配给一个按钮的单击处理程序,并将停止\u单击
分配给另一个按钮
当您单击执行按钮ClickHandlerAsync
的按钮时,整个操作开始。当它工作时,您可以单击另一个按钮,它将显示一个消息框并保持响应。顺便说一句,我从中复制了这段代码,但我在代码中添加了我自己的注释,所以您知道goi是什么
Thread t2 = new Thread( new ThreadStart(() =>
{
for( var i = 0; i <= 5000000; i++ ) {
UpdateUI( i );
count = i;
}
} ) );
t2.Start();