[英]Wpf retrieving data from database freeze UI
每当我获得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:谢谢大家的帮助,Entity Framework导致了问题(我现在不知道为什么)。
我用SqlConnection和SqlCommand替换了所有模型行。
与UI相关的代码应在UI线程上调用。 不要将此与用于处理数据(发送,检索,更新等)的同一线程混在一起,以免发生死锁。 在您的情况下,这是由与数据库的交互引起的。
这是一个例子:
Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => {
/* Your code here */
MessageBox.Show("Error\n\n" + exception.Message + "\n\n" + baseException.Message);
}));
您的方法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线程的冻结时间。
为避免这种情况,您可以直接将hotItems
分配给Hotlist
(通过使用相应的Ienumerable转换)。 如果您可以给我提供Hotlist
类型,可以给您确切的语法。 或者,您可以先准备兼容类型的临时集合,然后将该集合分配给Hotlist
。 关键是尽量减少UI线程的工作。 替换整个foreach
,如下所示:
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => Settings.Hotlist.AddRange(hotItems)));
并在Thread
移动由foreach
完成的工作。 现在在Action
,使用AddRange()
,执行assignment
或任何使其有效的工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.