我有一个方法可以从带有引用的类调用另一个方法,而这些引用又返回一个数据表。
我正在尝试在一个线程中运行该查询,现在在一个线程中运行查询本身很容易,但是如何让它从线程中返回数据表呢?
调用类的方法示例:
private void loadCombo(string sqlComand, string value, ComboBox loadBox)
{
DataTable dt = new DataTable();
//Thread thread = new Thread(() => sqlScript.loadCombo(sqlComand, value, loadBox));
//thread.start();
dt = sqlScript.loadCombo(sqlComand, value, loadBox);
loadBox.ValueMember = value;
loadBox.DataSource = dt;
loadBox.Refresh();
}
答案 0 :(得分:0)
这听起来像一个简单的问题。
您可以使用Task
(以及async/await
,但这可能是可选的,通常用于禁用/启用相应按钮以防止多个执行)在事件处理程序中执行长时间运行的代码而不阻塞UI。您仍然需要调用访问UI元素:
async void loadCombo(string sqlComand, string value, ComboBox loadBox)
{
// disable button
await Task.Run(() =>
{
var dt = sqlScript.loadCombo(sqlComand, value, loadBox);
Invoke((Action)(() =>
{
loadBox.ValueMember = value; // is it out parameter? anyway, copying your code
loadBox.DataSource = dt;
loadBox.Refresh();
}));
}
// enable button
}
创建并从另一个线程传递DataTable
不应该有任何问题。
答案 1 :(得分:0)
不使用async-await
方法在另一个线程上执行数据库查询,而是在一个线程上执行,不会阻止UI。
为此你需要分开"数据查询"操作和ComboBox
设置
public class SqlScript
{
public async Task<DataTable> LoadDataAsync(string command, object value)
{
// Load data asynchronously by using ..Async methods
}
}
private async Task loadComboAsync(string sqlComand, string value, ComboBox loadBox)
{
var data = await sqlScript.LoadDataAsync(sqlComand, value);
loadBox.ValueMember = columnNameWhichRepresentValue;
loadBox.DataSource = data;
}
你不需要调用loadBox.Refresh
方法,设置新的数据源无论如何都会这样做。
请勿使用Task.Run
。数据库操作什么都不做&#34;沉重的&#34;需要在另一个线程上执行。数据库操作只发送命令并等待响应 - 因此仅使用另一个线程进行等待是浪费资源
而是使用SqlConnection.OpenAsync
和SqlCommand.ExecuteReaderAsync
方法
public async Task<DataTable> loadCombo(string sqlCommand, string value)
{
var yourConnectionString = "DataSource=...";
using (var connection = new SqlConnection(yourConnectionString))
using (var command = new SqlCommand(sqlCommand, connection))
{
await connection.OpenAsync();
var reader = await command.ExecuteReaderAsync();
var data = new DataTable();
data.Load(reader);
return data;
}
}
答案 2 :(得分:0)
谢谢@Sinatr和@Fabio,我测试了你的答案的组合,下面似乎给了我最快的回报时间。
主表单方法调用:
private async Task loadCombo(string sqlCommand, string value, ComboBox loadBox)
{
var data = await sqlScript.loadCombo(sqlCommand, value);
loadBox.ValueMember = value;
loadBox.DataSource = data;
}
sqlScript类方法:
public async Task<DataTable> loadCombo(string sqlCommand, string value)
{
SqlConnection myConn;
SqlCommand myCmd = default(SqlCommand);
SqlDataReader oResult;
DataTable dt = new DataTable();
await Task.Run(() =>
{
using (myConn = new SqlConnection("Data Source=" + frmMain.sqlServer + ";" + "Initial Catalog=" + frmMain.sqlData + ";User Id=" + frmMain.sqlUser + ";Password=" + frmMain.sqlPwd + ";"))
{
try
{
myConn.Open();
if (myConn.State == ConnectionState.Open)
{
myCmd = new SqlCommand((sqlCommand), myConn);
oResult = myCmd.ExecuteReader();
dt.Load(oResult);
myConn.Close();
}
else
{
}
}
catch (Exception err)
{
using (StreamWriter w = File.AppendText("ErrorLog.log"))
{
frmMain.Log("sqlScripts.loadCombo: " + err.Message, w);
}
}//End Try
}//End using
});
return dt;
}
答案 3 :(得分:-1)
谢谢@Sinatr,我只需要稍微调整你的答案,下面的代码似乎有效。
private async void loadCombo(string sqlCommand, string value, ComboBox loadBox)
{
await Task.Run(() =>
{
var dt = sqlScript.loadCombo(sqlCommand, value, loadBox);
Invoke((Action)(() =>
{
loadBox.ValueMember = value;
loadBox.DataSource = dt;
}));
});
}