每次我获得UI锁定时,我都会遇到从数据库中异步检索数据的问题。
private async void RetrieveHotlist(object sender, RoutedEventArgs e) //button click
{
var hotItems = new ObservableCollection<HotItem>();
await Task.Factory.StartNew(() =>
{
try
{
var serv = "xxx";
string connStr = Common.GetConStrEF(serv + "\\" + Common.DBLOGIN_INSTANCE,
Common.DBLOGIN_DBNAME, Common.DBLOGIN_USER, Common.DBLOGIN_PASSWORD);
var dataModel = new xxxxDataModel(connStr);
foreach (var category in dataModel.SpecialNumberCategory) //retrieving database CreateObjectSet<SpecialNumberCategory>("SpecialNumberCategory"); //ObjectContext
{
var item = new HotItem() { Name = category.Name };
hotItems.Add(item);
}
}
catch (Exception exception)
{
var baseException = exception.GetBaseException();
MessageBox.Show("Error\n\n" + exception.Message + "\n\n" + baseException.Message);
}
});
if (Settings != null)
{
Settings.Hotlist.Clear();
foreach (var hotItem in hotItems)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => Settings.Hotlist.Add(hotItem)));
}
}
}
为什么RetrieveHotlist方法会锁定我的UI?为什么等待Task.Factory.StartNew()这还不够?
感谢您的帮助:)
修改
我删除了一些代码以便更清楚。
private void RetrieveHotlist(object sender, RoutedEventArgs e) //button click
{
var b = new BackgroundWorker();
b.DoWork += (o, args) =>
{
Thread.Sleep(2000); //**UI IS FULL RESPONSIVE FOR 2 sec.**
var hotItems = new ObservableCollection<HotItem>();
try
{
var serv = "xxxx";
var dataModel = new xxxxDataModel(connStr);
var c = dataModel.SpecialNumberCategory; //**UI FREEZE / ENTITY FRAMEWORK**
b.RunWorkerCompleted += (o, args) =>
{
};
b.RunWorkerAsync();
}
EDIT2: 感谢大家的帮助,实体框架引发了这个问题(我现在还不知道为什么)。
我用SqlConnection和SqlCommand替换了所有模型行。现在它很好用。
答案 0 :(得分:0)
应在UI线程上调用与UI相关的代码。不要将它与操作数据的相同线程(发送,检索,更新等)混合以避免死锁。在你的情况下,它是由与数据库的交互引起的。
以下是一个例子:
Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => {
/* Your code here */
MessageBox.Show("Error\n\n" + exception.Message + "\n\n" + baseException.Message);
}));
答案 1 :(得分:0)
您的方法RetrieveHotlist()
阻止代码
UI
原因
foreach (var hotItem in hotItems)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => Settings.Hotlist.Add(hotItem)));
}
正在主Thread
上执行。如果您仔细查看问题,那么您必须逐个向list
添加项目,并且每次将项目添加到Hotlist
时,都必须将更改提升为UI
,甚至如果它没有在每个项目上执行添加事件,则需要一些时间来迭代collection
并将项目添加到另一个collection
,这是您的UI线程的冻结时间。 / p>
为避免这种情况,您可以直接将hotItems
分配给Hotlist
(通过使用相应的Ienumerable转换)。如果你能给我Hotlist
的类型,我可以给你准确的语法。或者您可以先准备兼容类型的临时集合,然后将该集合分配给Hotlist
。 关键是尽量减少UI线程的工作。替换整个foreach
,如下所示:
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => Settings.Hotlist.AddRange(hotItems)));
并在foreach
中移动Thread
完成的工作。现在在Action
中,使用AddRange()
,执行assignment
或其他任何操作即可。