WPF Backgroundworker dowork work completed progress changed

FredGrit發表於2024-06-24
<Window x:Class="WpfApp178.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp178"
        mc:Ignorable="d"  WindowState="Maximized"
        
        Title="MainWindow" Height="450" Width="800">
    <Grid TextBlock.FontSize="16">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <StackPanel Orientation="Horizontal" Margin="6">
            <TextBlock Text="From:"/>
            <TextBox Margin="10,2,2,2" x:Name="_from"/>
            <TextBlock Text="To:" Margin="20,0,0,0"/>
            <TextBox Margin="10,2,2,2" Width="120"
                     MaxLength="10" x:Name="_to"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" Grid.Row="1" Margin="6">
            <Button Content="Calculate" Padding="4" x:Name="calc" Click="Button_Click"/>
            <Button Content="Cancel" Padding="4" x:Name="cancel" Click="cancel_Click"/>
        </StackPanel>
        <ProgressBar x:Name="progress" Grid.Row="2" Height="30" Margin="4"/>
        <TextBlock x:Name="_result" Grid.Row="3" FontSize="20"
                   Margin="6" HorizontalAlignment="Center" />
        <TextBlock x:Name="progressTb" Grid.Row="4" FontSize="20"
                   Margin="6" HorizontalAlignment="Center"/>
    </Grid>
</Window>



using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Data.SqlTypes;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp178
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        ObservableCollection<int> numbers = new ObservableCollection<int>();
        object lockObj = new object();
        CancellationTokenSource cts;
        BackgroundWorker worker;

        public MainWindow()
        {
            InitializeComponent(); 
        }

        static int CountPrimes(int from,int to,CancellationToken ct)
        {
            int total = 0;
            for(int i=from;i<=to;i++)
            {
                if(ct.IsCancellationRequested)
                {
                    return -1;
                }
                bool isPrime = true;
                int limit = (int)Math.Sqrt(i);
                for(int j=2;j<=limit;j++)
                {
                    if(i%j==0)
                    {
                        isPrime = false;
                        break;
                    } 
                }
                if (isPrime)
                {
                    total++;
                }
            }
            return total; 
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            worker = new BackgroundWorker();
            worker.WorkerSupportsCancellation = true;
            worker.WorkerReportsProgress = true;
            worker.ProgressChanged += Worker_ProgressChanged;
            worker.DoWork += Worker_DoWork;
            worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
            calc.IsEnabled = false;
            cancel.IsEnabled = true;
            _result.Text = "Calculating...";
            var data = new PrimeInputData
            {
                First = int.Parse(_from.Text),
                Last = int.Parse(_to.Text)
            };
            worker.RunWorkerAsync(data); 
        }

        private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            progress.Value = e.ProgressPercentage;
            _result.Text = $"Calculating:{progress.Value}%";
            progressTb.Text = progress.Value.ToString();
        }

        private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            _result.Text = e.Cancelled ? "Operation Cancelled" : $"Total Primes:{e.Result}"; 
            calc.IsEnabled = true;
            cancel.IsEnabled = false;
        }

        private void Worker_DoWork(object sender, DoWorkEventArgs e)
        {
            var data = e.Argument as PrimeInputData;
            int count = 0;
            bool isFirstZero = true;
            worker.ReportProgress(0);
            int range = data.Last - data.First + 1, progressCount = 0;
            for(int i=data.First;i<=data.Last;i++)
            {
                if(worker.CancellationPending)
                {
                    e.Cancel = true;
                    break;
                }

                int limit = (int)Math.Sqrt(i);
                bool isPrime = true;
                for(int j=2;j<=limit;j++)
                {
                    if(i%j==0)
                    {
                        isPrime = false;
                        break;
                    }
                }
                if(isPrime)
                {
                    count++;
                }
                if(++progressCount%100==0)
                {
                    int value = progressCount * 100 / range;
                    if(value>0)
                    {
                        worker.ReportProgress(value);
                    } 
                }  
            }

            if(!e.Cancel)
            {
                worker.ReportProgress(100);
                e.Result = count;
            } 
        }

        private void cancel_Click(object sender, RoutedEventArgs e)
        { 
            worker.CancelAsync();
        }
    }

    class PrimeInputData
    {
        public int First { get; set; }
        public int Last { get; set; }   
    }
}

相關文章