我有一个WPF应用程序,用户在某些文本框中输入数据库信息。用户单击“连接”后,将根据用户输入的内容创建连接字符串并建立连接。我注意到,如果用户输入任何错误的信息,应用程序将挂起,直到连接超时。挂起,我的意思是用户根本无法与应用程序的其余部分进行交互。
我的目标是在测试连接字符串时保持应用程序的响应。
我认为将此工作流程放在不同的线程上是一个很好的解决方案。我的想法是在线程运行时禁用任何可能需要数据库连接的东西。一旦线程返回(并且已确认连接字符串有效),我将重新启用所有内容。否则,请将所有内容都禁用。
但是,Thread
类在线程完成时没有事件通知(或者至少我不知道一个)。
我还与BackgroundWorker
班级合作过。这效果更好。但是,当RunWorkerCompletedEventHandler
事件被触发且连接字符串无效时,我得到以下异常:
调用线程无法访问此对象,因为它不同 线程拥有它。
这可能是因为当触发完成的事件处理程序时,连接仍未超时。
是否有任何想法,或者我是否应该尝试多线程连接到数据库?
我正在做的代码大纲:
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
dbTool = new DBTool();
// Create the connection string
e.Result = dbTool.connectToDB(); // connectToDB() returns a bool (true if connection established)
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// connectToDB() returns a bool (true if connection established)
if(e.Result == true) // Trying to read e.Result here throws the exception
{
// e.Error and e.Cancel should be checked first
// However, I would like the thread to finish before
// this event is fired
}
if (e.Error != null)
{
Console.WriteLine(e.Error.Message);
}
}
答案 0 :(得分:3)
不要将DbConnection
对象保留在单个全局变量中,并在线程之间共享。
.NET环境将自动汇集您的连接并共享它们,因此调用new DbConnection()
非常快。
您应该将连接字符串保存在全局变量中,然后根据需要在每个线程上创建连接。
编辑:原始海报可能实际上想要了解如何在测试连接字符串时保持WinForms应用程序的响应。在这种情况下,您希望生成一个不同的线程来测试连接。从“连接测试线程”,您可以按照此模式更新UI - How to update the GUI from another thread in C#?public void TestConnectionThread(String connstr_to_test)
{
// Notify the user that we're doing our test
string message = "Testing...";
lblTestResultMessage.SetPropertyThreadSafe(() => lblTestResultMessage.Text, message);
try {
dbTool = new DBTool();
message = dbTool.connectToDB();
// If something failed, show a useful debugging message
} catch (Exception ex) {
message = ex.ToString();
}
// Use a lambda expression to communicate results to the user safely
lblTestResultMessage.SetPropertyThreadSafe(() => lblTestResultMessage.Text, message);
}
答案 1 :(得分:0)
来自DBConnection's documentation:
此类型的任何公共静态(在Visual Basic中为Shared)成员都是线程安全的。 不保证所有实例成员都是线程安全的。
换句话说,不同的线程永远不应共享数据库连接,因为无法安全地共享实例。正如Ted Spence建议的那样,您应该只在您需要时创建连接(并在完成它们时.Dispose()
。 .NET有一个内置的连接池机制,可以很好地确保连接在可能的情况下被重用,但是保持连接的时间超过了绝对必要的时间会干扰它的能力。
答案 2 :(得分:0)
尝试
dbtool tool = e.result as dbtool;
如果dbTool中的变量在查询完成时设置为true或false,那么您应该可以调用
tool.variable = true/false
答案 3 :(得分:0)
感谢大家的意见。
我能够想出一个解决方案。在遇到Working With The WPF Dispatcher之后。我确定你可以获得UI线程的Dispatcher
对象:
//...
dbTool = new DBTool();
// Initialize the connection string
// Disable some UI
Thread thread = new Thread(new ThreadStart(
delegate()
{
dbTool.connectToDB();
UIControl.Dispatcher.BeginInvoke(
new Action(
update
));
}
));
thread.Start();
//.....
void update()
{
if (dbTool.validString) // If the connection string was valid
{
// Re-enable controls
}
else // Invalid connection string
{
// Keep controls disabled if no connection could be created
}
}
这确实会测试不同线程上的连接字符串,使应用程序的其余部分响应。