【问题标题】:Wpf retrieving data from database freeze UIWpf 从数据库冻结 UI 中检索数据
【发布时间】:2016-08-07 00:03:09
【问题描述】:

每次我获得 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?为什么 await 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 替换了所有模型行。现在效果很好。

【问题讨论】:

  • 您应该在单独的线程上检索数据并显示消息对话框,UI 更改在另一个线程上。我们有所谓的 UI 线程,应该调用所有与 UI 相关的操作。
  • 你确定上面是你的代码吗? await 只能和 async 方法一起使用,上面的代码甚至不能编译...
  • 你确定下一行hotItems.Add(item);没有抛出任何异常吗?
  • @Ephraim 我已经尝试过使用后台工作人员,它是一样的。我会尝试使用新线程。
  • @Kylo Ren & StepUp - 代码正确,没有错误和异常:) StartNew 是等待的。

标签: c# wpf async-await


【解决方案1】:

应在 UI 线程上调用与 UI 相关的代码。不要将它与您操作数据(发送、检索、更新等)的同一线程混合以避免死锁。在您的情况下,它是由与数据库的交互引起的。

这是一个例子:

 Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() => { 
    /* Your code here */ 
    MessageBox.Show("Error\n\n" + exception.Message + "\n\n" + baseException.Message);
}));

【讨论】:

  • 您好,感谢您的回复。可悲的是它仍然是一样的.. 所有与 UI 相关的东西都被 Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
  • 还要确保您没有在 Application.Current.Dispatcher.Invoke 中调用 RetrieveHotlist 方法
  • 我认为它是自动的......因为它是按钮点击事件处理程序。
【解决方案2】:

您的方法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)));

并将foreach 完成的工作移到您的Thread 中。现在在 Action 中,要么使用 AddRange(),要么使用 assignment 或任何使其工作的方法。

【讨论】:

  • 请检查编辑后的帖子,现在我知道 UI 冻结是由 :dataModel.SpecialNumberCategory;
  • @PawełCharzewski 从您的评论来看,似乎不可能在异步操作中,一个部分执行良好而另一个部分阻塞了 UI。我能想到的唯一问题是您的 xxxxDataModel (或任何内部组件)在某种程度上与 UI 线程相关。你也可以给那个类的代码吗?
  • 对不起,我不能:(这是实体框架生成的简单类
  • @PawełCharzewski 如果它是一个简单的类,那么我认为它无法阻止 UI。问题必须是 UI 线程在您的方法中工作的位置,并且只能是 RunWorkerCompleted 块或 Dispatcher 操作。
  • @PawełCharzewski 在您的第一个代码块中我 100% 确定这是迭代,使用调度程序添加项目会导致问题。您的新任务可能会阻塞我无法在此处创建的 UI,这可能是一种上下文可能性。但除此之外的方法都很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-02
  • 1970-01-01
  • 1970-01-01
  • 2019-11-19
相关资源
最近更新 更多