【问题标题】:Implementing WPF Progressbar for long running methods为长时间运行的方法实现 WPF 进度条
【发布时间】:2012-09-21 18:14:30
【问题描述】:

我们有一个 3 层架构(UI、BL、DAL)的 WPF 应用程序。我需要处理加载大量行的 WPF 和 DevExpress 数据网格。 BL 方法将返回要绑定到 WPF 数据网格的可观察对象集合。如果记录的数量非常大,那么 UI 将变得无响应。因此,我们需要实现一个解决方案,以便在 BL 方法执行查询和处理数据时显示一个进度条,其中包含已完成工作的百分比。在这里,我需要在执行查询时立即获取记录总数,并且在处理完每一行之后,我需要在标签中显示项目处理的当前索引,例如“处理 1/2000 个文档”。

实现上述功能的最佳方法是什么。我们正在使用 MVVM 模式。我是否需要更改我们在 BL 中获取和处理记录的方式(当前是 BL 方法中的 fectch 和处理(将值从数据读取器映射到自定义对象))。或者,我正在寻找在用户滚动数据网格时以分页方式加载数据网格中的行。

欢迎提供任何示例链接。

编辑: @Big Daddy 你的解决方案 1) 向视图模型添加新属性以获取 TotalCount 和 PercentComplete。 2) 将视图模型传递给 Search 方法。 3)使用BGW更新属性。

以上似乎是一个可行的解决方案。但我很想知道是否有任何其他方法可以在不依赖视图模型的情况下解决这个问题。任何设计模式可用于此类操作?

【问题讨论】:

    标签: wpf progress-bar


    【解决方案1】:

    您可以使用 BackgroundWorker 来处理此问题。它不会在获取您的数据时阻止 UI,并且会保持 UI 响应用户。 BackgroundWorker 有一个 ProgressChanged 事件,可以很好地与 ProgressBars 配合使用。

    在我从事的项目中,我在客户端服务/存储库中实现了 BW。您的视图模型可以调用此类。这里的方法将实例化 BW、完成工作、报告进度并返回数据。您需要在 UI 上报告进度,因此在视图模型中设置一个属性并将 ProgressBar 的值绑定到它,如下所示:

    视图模型

    private int _percentCompleted;
        [DefaultValue(0)]
        public int PercentCompleted
        {
            get { return _percentCompleted; }
            set
            {
                _percentCompleted = value;
                RaisePropertyChanged(() => this.PercentCompleted);
            }
        }
    

    查看

    <ProgressBar x:Name="SourceBatchUploadProgressBar"
                             Style="{StaticResource GreenProgressBar}" Grid.Column="1"  Grid.Row="1" 
                             Value="{Binding PercentCompleted, UpdateSourceTrigger=PropertyChanged}" 
                             Height="25" Width="200" Margin="5,0,10,5"/>
    

    您需要让 BW 的 ReportProgress 事件更新 PercentCompleted 属性才能使其正常工作。像这样的:

    BackgroundWorker.RunWorkerCompleted += (o, e) =>
            {
                ...Update progress
            };
    

    如果您想了解更多详情,请告诉我。

    【讨论】:

    • 我认为这里的挑战是,如果它是一个查询,就像在数据库查询中一样,除了完成之外没有任何进展可以报告。如果 OP 正在处理查询结果并且这是一项耗时的任务,那么完美的答案。
    • @Blam 好点。如果消耗任务是数据库查询,那么 BackgroundWorker 的好处仅限于不阻塞 UI。
    • @Big Daddy 我的问题是 BL 方法如何发送/更新它正在执行的任务的进度?它应该独立于视图模型。所以应该有一些机制来从 BL 方法执行时获取进度。在我的情况下,过程如下:
    • 1)视图模型调用BL方法MyClass.Search(param1,Param2)。该方法的 returnType 是 MyClass 对象的 ObservableCollection。 2) Search 方法首先执行查询并作为 DataReader 返回。然后我们从 reader 中读取数据,并一一映射到 MyClass 对象。因此,我需要在执行查询时通知 UI 总 rocords,并在每行完成 datareader 值到 MyClass 对象的映射时通知 UI。那么我们如何将完成百分比从 BL 发送到这里的视图模型?
    • @saravana 根据我对您的情况的理解,我建议尝试以下操作。一,将 BackgroundWorker、TotalRecords (int) 属性和 PercentCompleted (int) 属性添加到您的 ViewModel。第二,将您的视图模型传递给您的 MyClass.Search() 方法,并在此方法中报告 TotalRecords 并更新 BackgroundWorker.ProgressChanged 和 BackgroundWorker 中的 PercentComplete 属性。 RunWorkerCompleted 事件处理程序。
    【解决方案2】:

    所以你有所有的行。你指的是什么处理?渲染?渲染的显示状态将始终为 100%,因为它在完成渲染之前不会渲染。

    UI 需要很长时间才能呈现 2000 行。有很多格式化和大小调整。

    分解 UI 以显示每页 40 行,并带有下一页和上一页按钮。

    如果 DevExpress 数据网格不支持虚拟化,则寻找支持的网格。为了速度,我喜欢 ListView GridView。

    哇,支票。你在听。我给你更多。

    因此,如果速度快的话,可以立即获取整个 ID 列表(并且您可以获得总数)。然后按需创建 40 个对象。如果您想花哨,请在 BackGroundWorker 上创建下一个 40。启动 BackGroundWorker 时禁用 Next 按钮并在 Complete 中启用它。

    【讨论】:

    • @Balm 我在我的 commnets 中为 Big Daddy 的回答添加了更多细节。
    • 在 DevExpress 和 WPF 数据网格中,都启用了虚拟化。对于查询(使用 LLBLGen ORM)执行需要几毫秒。查询结果到业务对象的映射需要更多时间。所以这与渲染无关。它是关于向用户提供有用的信息,直到 BL 方法返回可观察的集合。正如我在我的问题中所问的那样,如果无法从 BL 获取中间信息到 View 模型,那么有没有办法处理和查询结果,并在处理一行时将其发送到 View 模型?
    • @saravana 因此,创建业务对象比查询花费的时间更长。不要试图告诉我渲染不是问题——我知道渲染 2000 行需要一段时间。你从我自己和大爸爸那里得到了你驳回的有效答案。不要指望人们阅读 cmets 以获得完整的问题陈述 - 更新问题。
    • @Balm,如果我的描述没有给你正确的图片,我很抱歉。请注意英语不是我的母语。我的意思是在我的评论中渲染不是当务之急,向用户提供反馈是首要任务,因为它将解决这两个问题。我昨天接受了这两个答案。但是其中一些仍然未经检查。
    猜你喜欢
    • 2011-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-30
    相关资源
    最近更新 更多