Wpf从数据库冻结UI中获取数据。

时间:2022-06-17 19:29:03

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(),执行一个任务,要么做任何事情来让它工作。