【发布时间】:2019-05-07 07:16:20
【问题描述】:
我有一个使用 OleDb 从 Excel 表格中获取数据的应用程序。
在表单上,我有控件,因此用户可以根据自己的需要过滤数据。
例如,FileSize、UserID、Rootpath 等。这非常有效。
最终选择后,用户必须按下“更新”按钮,以便我可以根据他的输入过滤数据。结果将显示在 DataGridView 中。
但是,由于 Excel 表格上的数据变化很大,我曾经在第二个表单 (Waitform) 上有一个 ProgressBar,或在 UI 上的 ProgressBar 显示时使 DataGridView 不可见在非 UI 任务(数据收集)期间可见。
我知道我应该使用任务或线程(或 BackGroundWorker)来保持 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 也会冻结。它来自哪里?
【问题讨论】:
-
即使调用我的 UI 冻结。它正在调用冻结它的 UI 线程。在另一个线程上工作就是不使用 UI 线程。如果你调用回来......从我在这里看到的,你不需要。您可以将所有必需的值(您的控件的属性)作为字符串传递给您的方法 (
QueryToExcel()),并返回一个 DataTable。您可以在private DataTable QueryToExcel(string[] paramarray)中更改它,称为var dt = await Task.Run(() => QueryToExcel(values[]));。您没有显示与 ProgressBar 相关的任何内容,但是,由于您要返回 DataTable... -
顺便说一句,由于您使用的是 DataAdapter,因此您不需要这个:
conn.Open();。一个 MessageBox 不是一个好主意。它可能只是为了调试,但您可以在控制台(输出窗口)中写入错误。 -
嗨@Jimi,我只是自己想出来的。我希望你在一个小时前回答:) 你还是个天才,请把它写成答案,这样我就可以选择它作为解决方案。
标签: c# multithreading winforms datagridview task