我有一个应用程序,该应用程序使用OLEDB从Excel表中获取数据。
在我有控件的表格上,用户可以根据他的需求过滤数据。
例如, FileSize
, UserID
, Rootpath
等。
最终选择后,用户必须按AN''Update''按钮,我可以根据他的输入过滤数据。结果将在DataGridView中显示。
但是,由于Excel表上的数据有很大不同,因此我以前在第二个表单(Waitform
(>或使DataGridView Invisible在UI上可见时可见非UI任务(数据收集(。
我确实知道我应该使用任务或线程(或背景工作者(来保持UI响应。
话虽如此,它仍然冻结了我的整个应用程序。
//Update Button which uses all the userdefined filters
private async void updateButton_Click(object sender, EventArgs e)
{
WaitBarDatagrid.Visible = true; //Progressbar is called WaitBarDatagrid
WaitBarDatagrid.Style = ProgressBarStyle.Marquee;
WaitBarDatagrid.MarqueeAnimationSpeed = 30;
dataGridView1.Visible = false;
await Task.Run(() => QueryToExcel());
dataGridView1.DataSource = FileInfos;
WaitBarDatagrid.Visible = false;
dataGridView1.Visible = true;
}
private void QueryToExcel()
{
this.Invoke((MethodInvoker)delegate ()
{
string fSize;
if (FileSizeComboBox.Text == "All Data")
{ fSize = "0"; }
else if (FileSizeComboBox.Text == "> 1 MB")
{ fSize = "1000"; } // 1MB = 1000kB
else if (FileSizeComboBox.Text == "> 10 MB")
{ fSize = "10000"; } // 10MB = 10.000kB
else if (FileSizeComboBox.Text == "> 100 MB")
{ fSize = "100000"; } // 100MB = 100.000kB
else if (FileSizeComboBox.Text == "> 1 GB")
{ fSize = "1000000"; } // 1 GB = 1000.000 kB
else
fSize = "0";
// The following ensures that all possibilities of User Definition are covered
string user = "";
string size = "";
string sep = ""; //Seperator
if (!string.IsNullOrEmpty(UserTextbox.Text))
{
user = $"[UserID] = '{UserTextbox.Text}'";
sep = "AND";
}
if (!string.IsNullOrEmpty(FileSizeComboBox.Text))
{
size = $"{sep} [File Size] >= {fSize}";
sep = "AND";
}
//Final Where CLAUSE based on User Input
//string command = $@"{user} {size}{sep} [Date] <= {DateBox.Value.ToOADate()}";
string command = $@"{user} {size} {sep} [Date] <= {DateBox.Value.ToOADate()}";
//Call Data from Excel
string connectionString = GetConnectionString(Datapath + RootCombobox.Text);
string query = $@"SELECT * from [FileInfos$] WHERE ({command})";
DataTable dt = new DataTable();
using (OleDbConnection conn = new OleDbConnection(connectionString))
{
conn.Open();
using (OleDbDataAdapter dataAdapter = new OleDbDataAdapter(query, conn))
{
try
{
dataAdapter.Fill(dt);
FileInfos = dt;
}
catch (System.Data.OleDb.OleDbException ex)
{
MessageBox.Show(ex.ToString());
}
}
}
});
}
到目前为止,我还尝试将Userinputs
的值分配给全局变量,并将在其通讯事件中更改。但是,即使调用我的UI冻结。它来自哪里?
QueryToExcel()
方法应该排队在线程泵线程上运行的工作,让UI线程继续自己的工作而不会冻结。
但是您注意到UI无论如何都会冻结,说:
即使使用我的UI冻结
它是从另一个冻结它的线程调用UI线程。
在另一个线程上进行工作是关于不使用UI线程。如果我们从工作人员线程中调用UI线程,则效果会丢失(或在任何情况下都丢失,烦人(。
您还使用Invoke((而不是BeginInVoke((。后者是异步执行的:它立即返回,如果调用的控件忙碌或无法实现/无响应,则可以防止死锁。
无论如何,它不会有时会阻止UI口吃。
查看您在此处介绍的代码,看来根本不需要调用UI线程:辅助线程只需要某些控件的属性值,然后将数据表分配给字段。
然后,可以将所需值作为参数传递给该方法,将控件的属性分配给某些变量或类的属性(因此更容易理解参数所包含的内容(。
可以在
中更改工作方法private DataTable QueryToExcel(string[] paramArray)
Or
private DataTable QueryToExcel(SomeClass values)
可以称为:
private async void updateButton_Click(object sender, EventArgs e)
{
var dt = await Task.Run(() => QueryToExcel(values));
Or
dataGridView1.DataSource = await Task.Run(() => QueryToExcel(values));
}
在 QueryToExcel()
中以excel:
- 访问
values
参数以设置查询或其他处理。 - 创建数据库连接并填充数据表/数据集。
- 处理所有创建的所有一次性对象(连接/dataAdapter等(
- 返回数据表
您的代码基本上跳到非UI线程,然后跳回UI-几乎好像您从未离开过UI线程。
您需要做的是在UI线程上完成所有UI工作,并且仅在另一个线程上进行非UI工作。
尝试此代码:
// Define other methods and classes here
//Update Button which uses all the userdefined filters
private async void updateButton_Click(object sender, EventArgs e)
{
WaitBarDatagrid.Visible = true; //Progressbar is called WaitBarDatagrid
// WaitBarDatagrid.Style = ProgressBarStyle.Marquee;
// WaitBarDatagrid.MarqueeAnimationSpeed = 30;
dataGridView1.Visible = false;
string fSize;
if (FileSizeComboBox.Text == "All Data")
{ fSize = "0"; }
else if (FileSizeComboBox.Text == "> 1 MB")
{ fSize = "1000"; } // 1MB = 1000kB
else if (FileSizeComboBox.Text == "> 10 MB")
{ fSize = "10000"; } // 10MB = 10.000kB
else if (FileSizeComboBox.Text == "> 100 MB")
{ fSize = "100000"; } // 100MB = 100.000kB
else if (FileSizeComboBox.Text == "> 1 GB")
{ fSize = "1000000"; } // 1 GB = 1000.000 kB
else
fSize = "0";
// The following ensures that all possibilities of User Definition are covered
string user = "";
string size = "";
string sep = ""; //Seperator
if (!string.IsNullOrEmpty(UserTextbox.Text))
{
user = $"[UserID] = '{UserTextbox.Text}'";
sep = "AND";
}
if (!string.IsNullOrEmpty(FileSizeComboBox.Text))
{
size = $"{sep} [File Size] >= {fSize}";
sep = "AND";
}
//Final Where CLAUSE based on User Input
//string command = $@"{user} {size}{sep} [Date] <= {DateBox.Value.ToOADate()}";
string command = $@"{user} {size} {sep} [Date] <= {DateBox.Value.ToOADate()}";
await Task.Run(() => QueryToExcel(command, RootCombobox.Text));
dataGridView1.DataSource = FileInfos;
WaitBarDatagrid.Visible = false;
dataGridView1.Visible = true;
}
private void QueryToExcel(string command, string RootCombobox_Text)
{
//Call Data from Excel
string connectionString = GetConnectionString(Datapath + RootCombobox_Text);
string query = $@"SELECT * from [FileInfos$] WHERE ({command})";
DataTable dt = new DataTable();
using (OleDbConnection conn = new OleDbConnection(connectionString))
{
conn.Open();
using (OleDbDataAdapter dataAdapter = new OleDbDataAdapter(query, conn))
{
try
{
dataAdapter.Fill(dt);
this.Invoke((MethodInvoker)delegate () { FileInfos = dt; });
}
catch (System.Data.OleDb.OleDbException ex)
{
this.Invoke((MethodInvoker)delegate () { MessageBox.Show(ex.ToString()); });
}
}
}
}
未经测试,但应该很近。请注意,在任何非UI线程上访问或更新了UI元素的非UI元素。