WPFプログレスバーとマルチスレッド

WPFプログレスバーとマルチスレッド

この記事では、進行状況バーコントロールを例として使用して、WPFマルチスレッドを紹介します。進行状況バーの例により、WPFマルチスレッドの特性を包括的に理解できます。

ユーザーが何かをダウンロードしたり、アプリケーションに大量のデータを読み込んだりすると、必然的に長時間待つ必要があります。このとき、プログラムがクラッシュしているとユーザーが思わないように、進行状況をリアルタイムでユーザーに反映する進行状況バーが必要です。一連のハニージュース操作。
それでは、最初にプログレスバーに行きましょう。

XAMLコード:

<Grid Margin="100,0">
    <Grid.RowDefinitions>
        <RowDefinition Height="100" />
        <RowDefinition Height="50" />
    </Grid.RowDefinitions>
    <ProgressBar
        Name="ProgressBar"
        Grid.Row="0"
        Width="580"
        Height="30"
        Maximum="100"
        Minimum="0" />
    <DockPanel Grid.Row="1" LastChildFill="False">
        <Button
            Width="100"
            Height="30"
            Click="Download_OnClick"
            Content="Download"
            DockPanel.Dock="Left" />
    </DockPanel>
</Grid>

プログレスバー画面
プログレスバーの進行状況を制御する方法はたくさんありますが、この記事では主に4つの代表的な方法を紹介しますWPFでマルチスレッドを使用する方法を紹介するために使用されます。

1つのシングルスレッド(失敗)

背景コード:

public partial class MainWindow : Window
{
    
    
    public MainWindow()
    {
    
    
        InitializeComponent();
    }

    /// <summary>
    /// Download按钮点击事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Download_OnClick(object sender, RoutedEventArgs e)
    {
    
    
        for (int i = 1; i <= 100; i++)
        {
    
    
            ProgressBar.Value = i;
            Thread.Sleep(100);
        }
    }

}

このメソッドは、UIスレッドの下で実行され、メソッドの実行中にUIスレッドがスタックし、メソッドが終了したときにのみ画面に反映されるため、明らかに進行状況バーの実装に失敗します。
したがって、進行状況バーが0から100に突然変化し、中間プロセスは表示されません。

次に、タスククラスマルチスレッドを使用して進行状況バーを実装します(失敗)

UIスレッドを使用すると、プログラムがフリーズします。誰もが簡単に考えて、スレッドコントロールを使用できます。これはUIスレッドには影響しません。
そうです、現時点ではマルチスレッドしか使用できないので、次のコードがあります。

public partial class MainWindow : Window
{
    
    
    public MainWindow()
    {
    
    
        InitializeComponent();
    }
    
    /// <summary>
    /// Download按钮点击事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Download_OnClick(object sender, RoutedEventArgs e)
    {
    
    
        Task task = new Task(TaskMethod);
        task.Start();
    }

    private void TaskMethod()
    {
    
    
        for (int i = 1; i <= 100; i++)
        {
    
    
            ProgressBar.Value = i;
            Thread.Sleep(50);
        }
    }

}

新しいスレッドには進行状況バーがないため、上記のコードを使用すると、間違いなく異常に実行され、プログラムが終了します。スレッドで見つからないオブジェクトを強制的に呼び出すと、エラーが発生します。したがって、タスクスレッドでアプリケーションオブジェクトにアクセスしようとしないでください。

3つ目は、Dispatcherを使用してスレッドを実行する

スレッド内のアプリケーションオブジェクトを操作Dispatcherするには、現在のアプリケーションのオブジェクトを使用できます

public partial class MainWindow : Window
{
    
    
    public MainWindow()
    {
    
    
        InitializeComponent();
    }
    
    /// <summary>
    /// Download按钮点击事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Download_OnClick(object sender, RoutedEventArgs e)
    {
    
    
        Task task = new Task(TaskMethod);
        task.Start();
    }

    private void TaskMethod()
    {
    
    
        for (int i = 1; i <= 100; i++)
        {
    
    
            Thread.Sleep(50);
            Dispatcher.BeginInvoke((ThreadStart)delegate
            {
    
    
                ProgressBar.Value = i;
            }, DispatcherPriority.Normal);
        }
    }

}

Dispatcherが現在のプログラムを取得した後、BeginInvoke(DispatcherPriority, Delegate)非同期メソッドを使用して、非同期メソッドはデリゲートを呼び出して、呼び出し元のアプリケーションオブジェクトを他のスレッドに実装します。
このメソッドには2つのパラメータがあります。:
DispatcherPriorityスレッドの優先度を示すために使用されます。通常はあまり使用されません。優先度の高い方が最初に実行されます。
Delegate:委任します。BeginInvoke()メソッドは、着信メソッドをスケジューラのタスクとしてスケジュールします。その後、スケジューラーはこのメソッドを実行します。

最後に、上記の3つの方法は弱いです。実際、BackgroundWorkerコンポーネントを使用すると、進行状況バーの機能とほぼ完全に一致する可能性があります。

4、BackgroundWorkerを使用して進行状況バーを達成します

使いやすくBackgroundWorkerするために、ウィンドウにリソースとして配置できますResources

属性
1.WorkerReportsProgress

このプロパティがTrueに設定されている場合、進行状況の更新メソッドがトリガーされます。

2.WorkerSupportsCancellation

このプロパティがTrueに設定されている場合、cancelメソッドがトリガーされます。

イベント
1.DoWork

非同期DoWork実行する必要のあるメソッドを追加するBackgroundWorker、作業時にイベントがトリガーされます。

2.ProgressChanged

Addメソッドは、進行状況が更新されたとき、進行状況が更新されProgressChangedWorkerReportsProgress = Trueときにイベントがトリガーされたときに実行されます

3.RunWorkerCompleted

RunWorkerCompleted作業の最後にフィードバックメソッドを追加すると、作業の最後にイベントがトリガーされます。

方法
1.RunWorkerAsync(オブジェクト引数)

object argument:非同期スレッドで使用できるようにオブジェクトを渡します。

非同期操作を開始します。

2.ProgressChanged(intpercentProgress)

int percentProgress:現在の進捗状況を示す値を渡します

トリガーRunWorkerCompletedイベント

<Window
    x:Class="ThreadDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:componentModel="clr-namespace:System.ComponentModel;assembly=System"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:ThreadDemo"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="MainWindow"
    Width="800"
    Height="300"
    mc:Ignorable="d">
    <Window.Resources>
        <componentModel:BackgroundWorker
            x:Name="Worker"
            x:Key="Worker"
            DoWork="Worker_OnDoWork"
            ProgressChanged="Worker_OnProgressChanged"
            RunWorkerCompleted="Worker_OnRunWorkerCompleted"
            WorkerReportsProgress="True"
            WorkerSupportsCancellation="True" />
    </Window.Resources>
    <Grid Margin="100,0">
        <Grid.RowDefinitions>
            <RowDefinition Height="100" />
            <RowDefinition Height="50" />
        </Grid.RowDefinitions>
        <ProgressBar
            Name="ProgressBar"
            Grid.Row="0"
            Width="580"
            Height="30"
            Maximum="100"
            Minimum="0" />
        <DockPanel Grid.Row="1" LastChildFill="False">
            <Button
                Width="100"
                Height="30"
                Click="Download_OnClick"
                Content="Download"
                DockPanel.Dock="Left" />
            <Button
                Width="100"
                Height="30"
                Click="Cancel_OnClick"
                Content="Cancel"
                DockPanel.Dock="Right" />
        </DockPanel>
    </Grid>
</Window>

public partial class MainWindow : Window
{
    
    
    private BackgroundWorker worker;
    public MainWindow()
    {
    
    
        InitializeComponent();
        worker = (BackgroundWorker)FindResource("Worker");
    }

    /// <summary>
    /// Download按钮点击事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Download_OnClick(object sender, RoutedEventArgs e)
    {
    
    
        worker?.RunWorkerAsync(ProgressBar);
    }


    /// <summary>
    /// Cancel按钮点击事件
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Cancel_OnClick(object sender, RoutedEventArgs e)
    {
    
    
        worker?.CancelAsync();
    }

    /// <summary>
    /// 线程工作方法
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Worker_OnDoWork(object sender, DoWorkEventArgs e)
    {
    
    
        for (int i = 1; i <= 100; i++)
        {
    
    
            if (worker.CancellationPending)
            {
    
    
                e.Cancel = true;
                return;
            }
            
            worker.ReportProgress(i);
            Thread.Sleep(100);
        }
    }

    /// <summary>
    /// 进度改变方法
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Worker_OnProgressChanged(object sender, ProgressChangedEventArgs e)
    {
    
    
        ProgressBar.Value = e.ProgressPercentage;
    }

    /// <summary>
    /// 工作完成方法
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void Worker_OnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
    
    
        if (e.Cancelled)
        {
    
    
            MessageBox.Show("已取消");
            return;
        }
        MessageBox.Show("下载完成");
    }
}

コードに示されているように、

1.BackgroundWorkerオブジェクトを初期化します

この例では、コンストラクターでBackgroundWorkerオブジェクトを初期化します。

2.非同期操作の実行を開始します

[ダウンロード]ボタンのクリックイベントで、BackgroundWorker的RunWorkerAsync(object argument)メソッドを使用して非同期スレッド実行します。

注:Doworkで追加されたメソッドは、非同期スレッドで実行されます。したがって、Doworkイベントでアプリケーションオブジェクトを呼び出すことはできないことに注意してください。

Doworkイベントで呼び出す必要のあるオブジェクトは、パラメーターとして渡すことができます。

3.フォームへのリアルタイムフィードバックの進行状況

この方法はDoworkいつでも呼び出すことができにおけるイベントフォームに進捗状況をフィードバックします。メソッドが呼び出されるとメソッドがトリガーされ、ウィンドウがリアルタイムで更新されて進行状況がユーザーに報告されます。メソッドはUIスレッドにあるため、アプリケーションオブジェクトを任意に呼び出すことができます。BackgroundWorkerReportProgress(int percentProgress)
Worker_OnProgressChanged()

4.メソッドの最終結果のフィードバック

DoWorkイベントの実行がRunWorkerCompleted終了すると、スレッドの実行が終了したこと示すイベントがトリガーされます。この方法では、RunWorkerCompletedEventArgsパラメータを使用して、スレッドの実行ステータスが正常に終了したかキャンセルされたかなどを判断し、フォームの更新方法を決定できます。

5.スレッドをキャンセルします

と呼ばれる任意の時点でスレッドを終了することができます。スレッドの終わりですが、実際には自動的に終了しませんが、スレッドをキャンセル済みとしてマークするように属性を設定しますBackgroundWorkerCancelAsync()
BackgroundWorker的CancellationPendingTrue

開発者は、DoWorkメソッドのCancellationPending属性判断して、スレッドを終了するかどうかを決定する必要があります。キャンセル状態が設定された後もRunWorkerCompletedイベントはトリガーされることに注意してください状態をイベント渡す
ために設定する必要DoWorkEventArgsのあるCancelプロパティ、そして最後にendメソッドで、プロパティが結果をフォームにフィードバックする方法を決定したと判断されます。TrueCancellationPending

上記の進行状況バーは、BackgroundWorkerを使用して簡単に実現できます。もちろん、これに加えて、このクラスを使用して、非同期メソッドを実装し、進行状況をフィードバックし、いつでもキャンセルすることができます。

それはあなたを助けますか?いいね〜

おすすめ

転載: blog.csdn.net/qq_42068856/article/details/109015792