简体   繁体   English

WPF从数据库冻结UI检索数据

[英]Wpf retrieving data from database freeze UI

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? 为什么RetrieveHotlist方法锁定我的UI? And why await Task.Factory.StartNew() it's not enough? 为什么还要等待Task.Factory.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). EDIT2:谢谢大家的帮助,Entity Framework导致了问题(我现在不知道为什么)。

I replaced all model lines with SqlConnection and SqlCommand.Now it works great. 我用SqlConnection和SqlCommand替换了所有模型行。

UI-related codes should be invoked on the UI-thread. 与UI相关的代码应在UI线程上调用。 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. 在您的情况下,这是由与数据库的交互引起的。

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);
}));

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 . 在主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. 如果您发现问题很严重,那一定是您正在将一个项目一个一个地添加到list并且每次将一个项目添加到Hotlist它都必须引起对UI的更改,即使在每次添加项目时都没有这样做,迭代一个collection并将项目添加到另一个collection需要花费一些时间,这就是UI线程的冻结时间。

To avoid this you can directly assign the hotItems to Hotlist ( by using corresponding Ienumerable conversion). 为避免这种情况,您可以直接将hotItems分配给Hotlist (通过使用相应的Ienumerable转换)。 If you can give me type of Hotlist I can give you exact syntax. 如果您可以给我提供Hotlist类型,可以给您确切的语法。 or you can prepare a temporary collection first of compatible type and then assign that collection to Hotlist . 或者,您可以先准备兼容类型的临时集合,然后将该集合分配给Hotlist The key point is to minimize the work at UI thread. 关键是尽量减少UI线程的工作。 Replace whole foreach as below: 替换整个foreach ,如下所示:

Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() => Settings.Hotlist.AddRange(hotItems)));

and move the work done by foreach in your Thread . 并在Thread移动由foreach完成的工作。 Now in the Action , either use AddRange() , do an assignment or anything to make it work. 现在在Action ,使用AddRange() ,执行assignment或任何使其有效的工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM