【问题标题】:backgroundworker+wpf -> frozen windowbackgroundworker+wpf -> 冻结窗口
【发布时间】:2010-04-21 09:26:39
【问题描述】:

-进度条总是 0%

-窗口被冻结(DoWork r.)

-如果 System.threading.thread.sleep(1) on - 完美运行

有什么问题?

private void btnNext_Click(object sender, RoutedEventArgs e)
{
  this._worker = new BackgroundWorker();
  this._worker.DoWork += delegate(object s, DoWorkEventArgs args)
            {
                long current = 1;
                long max = generalMaxSzam();


                for (int i = 1; i <= 30; i++)
                {
                    for (int j = i+1; j <= 30; j++)
                    {
                        for (int c = j+1; c <= 30; c++)
                        {
                            for (int h = c+1; h <= 30; h++)
                            {
                                for (int d = h+1; d <= 30; d++)
                                {
                                    int percent = Convert.ToInt32(((decimal)current / (decimal)max) * 100);
                                    this._worker.ReportProgress(percent);
                                    current++;
                                    //System.Threading.Thread.Sleep(1); - it works well
                                }
                            }
                        }
                    }
                }
            };

            this._worker.WorkerReportsProgress = true;

 this._worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args)
            {
                this.Close();
            };

 this._worker.ProgressChanged += delegate(object s, ProgressChangedEventArgs args)
            {                              
                this.statusPG.Value = args.ProgressPercentage;             
            };

 this._worker.RunWorkerAsync();
}

<Window x:Class="SzerencsejatekProgram.Create"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Létrehozás" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Height="500" Width="700">    
    <DockPanel>    
        <Button DockPanel.Dock="Right"  Name="btnNext" Width="80" Click="btnNext_Click">Tovább</Button>
        <StatusBar DockPanel.Dock="Bottom">
            <StatusBar.ItemsPanel>
                <ItemsPanelTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="auto"/>
                            <ColumnDefinition Width="auto"/>
                        </Grid.ColumnDefinitions>
                    </Grid>
                </ItemsPanelTemplate>
            </StatusBar.ItemsPanel>
            <StatusBarItem Grid.Column="1">
                <TextBlock Name="statusText"></TextBlock>
            </StatusBarItem>
            <StatusBarItem Grid.Column="2">
                <ProgressBar Name="statusPG" Width="80" Height="18" IsEnabled="False" />
            </StatusBarItem>
            <StatusBarItem Grid.Column="3">
                <Button Name="statusB" IsCancel="True" IsEnabled="False">Cancel</Button>
            </StatusBarItem>
        </StatusBar>
    </DockPanel>
</Window>

【问题讨论】:

    标签: c# wpf progress-bar backgroundworker


    【解决方案1】:

    您的代码运行一个非常紧密的循环,并在其中心调用 ReportProgress()。

    这意味着您的 MessageQueue 被大量执行进度更新的请求所淹没。

    如果您在 Bgw 线程中构建一些延迟 (Thread.Sleep(100)),您会看到响应能力有所提高。

    更实用的解决方案是将报告移到外循环。在你的情况下:

    for (int i = 1; i <= 30; i++)
    {
        int percent = (i * 100) / 30;
        _worker.ReportProgress(percent);
        for(int j = 0; ....)
            ....
    }
    

    如果你只有 1 个循环,构建一个延迟:'if ((counter % 100) == 0) ...`

    您的目标是用户,目标是对 Reportprogress 进行 10 到 100 次调用。

    【讨论】:

    • 或报告基于 %10(00) 左右...有一位同事目前有同样的问题,因为他正在报告 250000 条记录的进度。
    • thread.Sleep(100) -> 不是解决方案。我认为更少的报告会起作用
    • @cyber, @Value:当然 Sleep() 不适用于真正的程序。但是这个内部循环只会增加一个 var。我已经扩展了我的答案。
    • 嗯嗯,它是进度更新的 30^5 倍,所以我仍然希望报告较少的进度。 progressupdates 的目标通常是向用户表明系统没有死,因为他们并不真正关心您是否有 10 或 10.000.000 万条记录(除非您故意告诉他们您将进行多少项目。跨度>
    • 啊,没看到你在“i”循环而不是“d”循环:D
    【解决方案2】:

    ProgressChanged 事件的匿名方法将在 UI 线程上运行。由于您经常报告进度,因此调度程序会将其排入队列并阻塞 UI。

    【讨论】:

      【解决方案3】:
       if (current++ % onePercent == 0)
                          {
                               int percent = Convert.ToInt32(((decimal)current / (decimal)max) * 100);
                               this._worker.ReportProgress(percent, new WorkerUserState { current = current, max = max });                        
                          }
      

      这很好用。

      【讨论】:

      • 因为你降低了频率:)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-08
      • 1970-01-01
      • 2020-05-25
      • 2013-01-07
      • 1970-01-01
      相关资源
      最近更新 更多