【问题标题】:Refreshing screen on a bad way led to application performance issues以不良方式刷新屏幕导致应用程序性能问题
【发布时间】:2017-10-13 11:22:02
【问题描述】:

我的系统是这样工作的:

2 台计算机正在使用不同的应用程序但相同的数据库(表:订单)。

第一台计算机正在下订单并将其写入数据库, 第二台计算机需要每 5 秒显示一次新订单。

我将简要描述(以避免长文本)我需要实现什么以及我现在是如何做到的:

  • 第二台计算机应用程序需要每 5 秒“进入数据库”以检查新订单并将其显示在屏幕上

当有很多订单并且我经常这样做时,我的应用程序会崩溃。

这就是我的应用程序现在的工作方式:

public MainWindow()
{

    try
    {
       InitializeComponent();
       this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
       this.WindowState = WindowState.Maximized;
       //When app runs for first time get all orders
       var ordersList = OrdersController.GetOrders();


       collectionViewSource.Source = ordersList;
       collectionViewSource.GroupDescriptions.Add(new PropertyGroupDescription("NumberOfOrder"));
       DataContext = collectionViewSource;

       //Here I'm refreshing screen every 5 seconds




 DispatcherTimer timer = new DispatcherTimer();
       timer.Interval = TimeSpan.FromSeconds(5));
       timer.Tick += timer_Tick;
       timer.Start();

    }
    catch (Exception ex)
    {
       MessageBox.Show(ex.Message);
    }

}

void timer_Tick(object sender, EventArgs e)
{
    //Every 5 seconds get all orders from database
    var ordersList = OrdersController.GetOrders();
    collectionViewSource.Source = null;

    collectionViewSource.Source = ordersList;
    DataContext = collectionViewSource;
}

GetOrders方法:

public static List<Orders> GetOrders()
{
            DataServices.DB.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, DataServices.DB.Orders);

            var results = DataServices.DB.proc_Orders_GetAll().ToList();

            List<Orders> localOrders = new List<Orders>();

            foreach (var item in results)
            {
                Orders local = new Orders();
                local.Sender = item.Sender;
                local.Quantity = Convert.ToDecimal(item.Quantity);
                local.ArticleTitle = item.ArticleTitle;
                local.DateOfOrder = Convert.ToDateTime(item.DateOfOrder);
                lokalnen.Add(local);
            }
            return localOrders;
}

但是上面的代码不是很好,如果有很多订单,它会导致我的应用程序崩溃.. 可能是因为 UI 一直在渲染一次又一次

将这个“刷新作业”移动到另一个任务可能会解决这个问题,所以我尝试了这样的事情:

首先创建新方法RefreshScreen,它可能看起来像这样:

private void RefreshScreen()
{
  var ordersList = OrdersController.GetOrders();
  collectionViewSource.Source = null;

  collectionViewSource.Source = ordersList;
  DataContext = collectionViewSource;
}

我将这个 RefreshScreen() 移到了这样的新任务中:

void timer_Tick(object sender, EventArgs e)
{
    //Instead old code where I set source of my list and of my datagrid directlly in timer tick now I moved it to new method and calling that method from a new task
   Task.Factory.StartNew(() => RefreshScreen())
        .ContinueWith(task =>
   {

   }, System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());

}

但这又让我的应用在一段时间后崩溃了…… 我真的不知道如何解决这个问题,也许是 Observablle 集合之类的东西, 我不知道...

任何形式的帮助都会很棒,可以防止我的应用崩溃! 谢谢!

编辑:从我的视觉工作室运行应用程序后,几秒钟后我得到了这个(解决方案包括计时器滴答中的任务):

【问题讨论】:

  • @mjwills 只是在一段时间后弹出消息并显示一些错误,然后单击确定应用程序关闭。我意识到如果我在刷新过程中单击 UI 上的某个位置,就会发生这种情况..
  • @mjwills 我会尽量让这个错误发生,所以我可能会告诉你,但它并没有一直出现,但我知道一直在发生什么:应用程序很慢,因为经常刷新/渲染 UI 我猜...
  • 应用程序如何崩溃?它只是挂起还是您遇到异常?异常消息说明了什么?
  • 如果应用程序崩溃并弹出窗口 - 转到 windows 事件查看器并找到相应的事件,其中将包含有关崩溃源的更多信息。
  • @mm8 就像 Application.exe 停止工作 Windows 可以在线检查问题的解决方案...关闭应用程序...例如,如果我单击其他按钮来检查其他内容应用程序变慢了,因为它可能在那个时候刷新(将源设置为我的数据网格)有没有办法以某种方式解决这个问题?

标签: c# wpf xaml user-interface task


【解决方案1】:

您应该在后台线程上查询数据库,但您不能从后台线程访问 DataContext 属性或 UI 元素的任何其他属性。这就是为什么您会收到“调用线程无法访问..”异常。

您可以尝试在后台线程上启动一个调用GetOrders() 方法的Task

void timer_Tick(object sender, EventArgs e)
{
    Task.Factory.StartNew(() =>
    {
        return OrdersController.GetOrders()
    }).ContinueWith(task =>
    {
        collectionViewSource.Source = task.Result;
        DataContext = collectionViewSource;
    }, System.Threading.CancellationToken.None, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}

但是,如果是在查询完成后运行在ContinueWith 委托中的代码很慢,那么您别无选择,只能获取更少的记录。

您还应该确保您没有禁用 UI 虚拟化。您可能还想尝试不对结果进行分组。这也可能很慢。

【讨论】:

  • orderList 在那里无法识别,应该声明为全局列表?
  • 对不起,Source 属性应该设置为任务的结果。我编辑了答案。
  • 这段代码似乎可以工作,但无论如何我想知道是否有可能让这个应用程序更快,我的意思是:当我向下滚动并且应用程序被刷新时,一切都会变慢,并且滚动突然滞后。如果我能让它更实用,我不会逃避改变整个概念。..
【解决方案2】:

尝试实现 SignalR。非常适合这种操作

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-17
    • 2010-10-28
    • 2020-09-20
    • 2014-01-24
    • 2021-06-20
    • 2018-01-18
    • 1970-01-01
    • 2021-06-09
    相关资源
    最近更新 更多