改善感知的WPF应用启动时间

时间:2011-01-18 13:45:51

标签: c# .net wpf performance app-startup

我有一个WPF数据库查看器应用程序:它是一个简单的主窗口,包含一个用户控件,数据网格显示从SQLite数据库中提取的数据。 问题是这个应用程序需要6秒才能启动,直到它可用。

我尝试在主窗口的构造函数中构建用户控件(并执行所有数据加载):
启动屏幕将以这种方式显示5,然后是1个空主窗口,直到应用程序准备好使用。
用户表示,在某些(视觉上)发生之前需要很长时间。

然后我将用户控件创建(和数据加载)移动到主窗口的Loaded事件处理程序中: 启动画面将显示3s,然后显示3s空主窗口,直到应用程序准备就绪 用户说它“更好”,但不喜欢这样一个事实,即半完成的主窗口显示处于禁用状态这么长时间。

是否有关于感知应用程序加载时间的一般建议或是否有关于如何改进这种情况的任何其他建议?
我相信理想情况下主窗口会尽可能快地显示,还有一些沙漏或微调器,直到数据加载完毕。但是我不能将用户控件创建移动到后台工作程序中,因为这将在错误的线程上完成。

有人对此问题有任何建议吗?

编辑:
请注意,我刚刚将LINQ-to-EF查询指定为网格数据源 一种可能的改进可能是将这些数据加载到后台的数据表中,并仅在加载后分配它......

EDIT2: 我正在使用带有System.Data.SQLite和EF4的.net 4来加载数据。有大约4000行和30列。

3 个答案:

答案 0 :(得分:13)

异步加载数据。在加载时为用户在GUI上呈现一些不错的东西。以下代码可以帮助您:

BackgroundWorker bgWorker = new BackgroundWorker() { WorkerReportsProgress=true};  
bgWorker.DoWork += (s, e) => {      
    // Load here your file/s      
    // Use bgWorker.ReportProgress(); to report the current progress  
};  
bgWorker.ProgressChanged+=(s,e)=>{      
    // Here you will be informed about progress and here it is save to change/show progress. 
    // You can access from here savely a ProgressBars or another control.  
};  
bgWorker.RunWorkerCompleted += (s, e) => {      
// Here you will be informed if the job is done. 
// Use this event to unlock your gui 
};  
bgWorker.RunWorkerAsync();  

应用程序速度不快但似乎更快,因为GUI立即可见且响应迅速。也许您还可以在加载其余数据时向用户显示已加载数据的一部分。使用ProgressChanged - 事件执行此操作。

<强>更新

我不确定我是否理解你的问题。如果您的问题不是需要加载数据的时间,那么应用程序中的某些内容就很奇怪了。 WPF是IMO非常快。控制创建不需要花费很多时间。我在几毫秒内提到了更大的列表。

尝试查看UI中是否存在阻碍DataGrid虚拟化Items的内容。也许你在那里有一个问题。要分析WPF应用,我可以向您推荐WPF Profiling Tools

答案 1 :(得分:2)

您可以做的最明显的事情是分析您的应用程序并找到启动时间的瓶颈。听起来最可能的罪魁祸首就是从数据库中加载数据。

我学到的一个教训是,如果您正在使用ORM,那么在加载大型数据集时,如果您喜欢POCO(Plain Old CLR / C#Objects)而不是ORM生成的数据库实体(参见下面的示例),那么加载时间将会更快,RAM使用率也将大幅降低。这样做的原因是EF将尝试加载整个实体(即所有字段),并可能加载与您的实体相关的大量数据,其中大部分都是您甚至不需要的。您真正需要直接使用实体的唯一时间是进行插入/更新/删除操作。在阅读数据时,您应获取应用程序需要显示和/或验证的字段。

如果您遵循MVVM模式,上述架构并不难实现。

使用EF将数据加载到POCO中的示例:

var query = from entity in context.Entities
                select new EntityPoco
                {
                    ID = entity.ID,
                    Name = entity.Name
                };

return query.ToList();

POCO是非常简单的类,每个字段都有autoproperties。

我们通常在应用程序中为每个实体提供存储库,每个存储库负责获取/更新与该实体相关的数据。视图模型引用了它们所需的存储库,因此它们不直接使用EF。当用户进行需要持久化的更改时,我们使用存储库中的其他方法,然后仅加载实体的子集(即用户更改的实体)并应用必要的更新 - 通过viewmodel完成的一些验证以及可能的其他验证通过约束/触发器等在数据库中继续

答案 2 :(得分:0)

这有很多原因。

1)部署机器的配置可能相当低 2)In-Proper或数据绑定问题。

可能的解决方案是:
1)延迟加载数据
2)优化性能。 http://msdn.microsoft.com/en-us/library/aa970683.aspx

我已经看到应用程序在wpf中渲染了不到一秒的5M记录。

PS:由于列顺序访问,最不可能的原因可能是30列。