我有一个位于任务栏中的应用程序,并定期检查数据库(通过SQLConnection)。如果数据库无法访问,它只会在通知图标上显示红色状态,而不显示任何其他内容。这是因为用户将使用在设施之间旅行的笔记本电脑,并且只能在内部网络上或通过VPN连接时访问数据库。
我遇到的问题是,当数据库无法访问时,我仍然希望通知图标上下文菜单能够响应。目前,如果用户在数据库尝试连接时尝试与菜单进行交互,则线程会因连接尝试而被锁定。
我想要的是数据库连接发生在一个单独的线程中,但我知道在线程之间共享连接对象是一件坏事。数据库连接后,我需要从原始线程查询它。有没有好办法呢?
我知道我可以在一个新线程中创建一个rus函数并简单地检查连接是否失败,然后如果返回成功,原始线程可以继续并连接它自己的数据库对象。但这种方法似乎是一个糟糕的解决方法。想法?
谢谢!
感谢您的建议 - 我从他们那里学到了很多东西。最后,我做了我应该从一开始就做的事情。每当需要定期更新数据库时,主(UI)线程就会启动一个新线程(包括数据库对象创建和连接)。
因此,就像HenkHolterman在对我的原始消息的评论中所建议的那样,我真的不需要创建数据库并在单独的线程中使用它运行操作。
一旦我升级到VS2010,我一定会对使用SqlConnection.OpenAsync感兴趣。
再次感谢。
答案 0 :(得分:7)
SqlConnection
没有线程关联要求,因此您可以在单独的线程上创建并打开它,并将引用传递回UI线程。只要您不从多个线程同时调用同一实例上的任何属性或方法,就不应该有任何问题。
使用Task
类(System.Threading.Task)在后台启动此操作,然后调用ContinueWith
将实例的所有权转移回UI线程。
public class TrayIconForm : Form
{
private SqlConnection connection = null;
private void Form_Load(object sender, EventArgs args)
{
TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() =>
{
var sql = new SqlConnection();
sql.ConnectionString = "your connection string";
sql.Open();
return sql;
}).ContinueWith((task =>
{
connection = task.Result;
// You can access other UI elements here as needed.
}), ui);
}
}
在C#5.0中引入新的async
和await
关键字,现在可通过Async CTP使用,您可以执行此操作。
private async void Form_Load(object sender, EventArgs args)
{
connection = await Task.Run(() => // TaskEx.Run in the CTP
{
var sql = new SqlConnection();
sql.ConnectionString = "your connection string";
sql.Open();
return sql;
});
}
答案 1 :(得分:2)
我建议使用新的C# Async CTP.这将允许您继续使用UI线程,从而降低复杂性。
答案 2 :(得分:1)
使用BackgroundWorker对象应该以一种简单的方式解决您的问题,但更准确地说,您希望使用线程来尝试打开连接,让UI线程准备好接收用户输入。