I have a problem with async retrieving data from database, everytime i get UI lock.
我有一个问题,异步从数据库检索数据,每次我得到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)));
}
}
}
Why the RetrieveHotlist method locks my UI? And why await Task.Factory.StartNew() it's not enough?
为什么RetrieveHotlist方法会锁定我的UI?为什么要等待任务?工厂。startnew()这还不够?
Thanks for help :)
谢谢你的帮助:)
EDIT:
编辑:
I deleted some code to be more clear.
我删除了一些代码以便更清楚。
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: Thanks all for help, Entity Framework caused the issue ( i don't know why for now).
谢谢大家的帮助,实体框架引起了这个问题(我现在不知道为什么)。
I replaced all model lines with SqlConnection and SqlCommand.Now it works great.
我用SqlConnection和SqlCommand替换了所有模型行。现在,伟大的工作。
2 个解决方案
#1
0
UI-related codes should be invoked on the UI-thread. Don't mix this with the same thread where you manipulate data (send, retrieve, update, etc.) to avoid deadlocks. On your case it was caused by the interaction with the database.
ui相关的代码应该在ui线程上调用。不要将此与操作数据(发送、检索、更新等)的线程混合,以避免死锁。在您的例子中,它是由与数据库的交互引起的。
Here is an example:
这是一个例子:
Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => {
/* Your code here */
MessageBox.Show("Error\n\n" + exception.Message + "\n\n" + baseException.Message);
}));
#2
0
Your method RetrieveHotlist()
is blocking the UI
cause below code
你的方法RetrieveHotlist()阻塞了代码下面的UI原因
foreach (var hotItem in hotItems)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => Settings.Hotlist.Add(hotItem)));
}
is getting executed on main Thread
. If you see closely the problem must be your are adding item one by one to the list
and every time a item is added to your Hotlist
it must be raising the change to UI
, even if it's not doing it on every item add event happens, it will take some time to iterate a collection
and add items to another collection
, which is your freeze time of UI thread.
正在主线程上执行。如果你仔细看问题必须将条目添加到列表,每次项目都加到你的活动表必须提高改变UI,即使它不是做每项添加事件发生,它将需要一些时间进行迭代并将条目添加到另一个集合,集合你的冻结时间的UI线程。
To avoid this you can directly assign the hotItems
to Hotlist
( by using corresponding Ienumerable conversion). If you can give me type of Hotlist
I can give you exact syntax. or you can prepare a temporary collection first of compatible type and then assign that collection to Hotlist
. The key point is to minimize the work at UI thread. Replace whole foreach
as below:
为了避免这种情况,您可以直接将hotItems分配到Hotlist(通过使用相应的Ienumerable转换)。如果你能给我热列表类型,我可以给你准确的语法。或者您可以先准备一个临时集合,然后将该集合分配给Hotlist。关键是最小化UI线程上的工作。替换完整的foreach如下:
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => Settings.Hotlist.AddRange(hotItems)));
and move the work done by foreach
in your Thread
. Now in the Action
, either use AddRange()
, do an assignment
or anything to make it work.
并在线程中移动foreach完成的工作。现在,在操作中,要么使用AddRange(),执行一个任务,要么做任何事情来让它工作。
#1
0
UI-related codes should be invoked on the UI-thread. Don't mix this with the same thread where you manipulate data (send, retrieve, update, etc.) to avoid deadlocks. On your case it was caused by the interaction with the database.
ui相关的代码应该在ui线程上调用。不要将此与操作数据(发送、检索、更新等)的线程混合,以避免死锁。在您的例子中,它是由与数据库的交互引起的。
Here is an example:
这是一个例子:
Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => {
/* Your code here */
MessageBox.Show("Error\n\n" + exception.Message + "\n\n" + baseException.Message);
}));
#2
0
Your method RetrieveHotlist()
is blocking the UI
cause below code
你的方法RetrieveHotlist()阻塞了代码下面的UI原因
foreach (var hotItem in hotItems)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => Settings.Hotlist.Add(hotItem)));
}
is getting executed on main Thread
. If you see closely the problem must be your are adding item one by one to the list
and every time a item is added to your Hotlist
it must be raising the change to UI
, even if it's not doing it on every item add event happens, it will take some time to iterate a collection
and add items to another collection
, which is your freeze time of UI thread.
正在主线程上执行。如果你仔细看问题必须将条目添加到列表,每次项目都加到你的活动表必须提高改变UI,即使它不是做每项添加事件发生,它将需要一些时间进行迭代并将条目添加到另一个集合,集合你的冻结时间的UI线程。
To avoid this you can directly assign the hotItems
to Hotlist
( by using corresponding Ienumerable conversion). If you can give me type of Hotlist
I can give you exact syntax. or you can prepare a temporary collection first of compatible type and then assign that collection to Hotlist
. The key point is to minimize the work at UI thread. Replace whole foreach
as below:
为了避免这种情况,您可以直接将hotItems分配到Hotlist(通过使用相应的Ienumerable转换)。如果你能给我热列表类型,我可以给你准确的语法。或者您可以先准备一个临时集合,然后将该集合分配给Hotlist。关键是最小化UI线程上的工作。替换完整的foreach如下:
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => Settings.Hotlist.AddRange(hotItems)));
and move the work done by foreach
in your Thread
. Now in the Action
, either use AddRange()
, do an assignment
or anything to make it work.
并在线程中移动foreach完成的工作。现在,在操作中,要么使用AddRange(),执行一个任务,要么做任何事情来让它工作。