1 //错误的处理 2 private void cmdBreakRules_Click(object sender, RoutedEventArgs e) 3 { 4 Thread thread = new Thread(UpdateTextWrong); 5 thread.Start(); 6 } 7 8 private void UpdateTextWrong() 9 { 10 txt.Text = "Here is some new text."; 11 } 12 13 //正确的处理 14 private void cmdFollowRules_Click(object sender, RoutedEventArgs e) 15 { 16 Thread thread = new Thread(UpdateTextRight); 17 thread.Start(); 18 } 19 20 private void UpdateTextRight() 21 { 22 this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, 23 (ThreadStart) delegate() 24 { 25 //txt.Text = "Here is some new text."; 26 UpdateText(); 27 } 28 ); 29 } 30 31 private void UpdateText() 32 { 33 34 txt.Text = "这是更新后的文本。"; 35 }
说明:public DispatcherOperation BeginInvoke(DispatcherPriority priority, Delegate method);其中DispatcherPriority是从-1到10 的枚举值,10优先级最高。在UpdateTextRight方法中的一下代码段
this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate() { //txt.Text = "Here is some new text."; UpdateText(); } );
可以用一下代码来替换,以增加代码的可读性
private delegate void UpdateTextDelegate(); this.Dispatcher.BeginInvoke(DispatcherPriority.Normal,new UpdateTextDelegate(UpdateText));
其实,这与上篇实例中应用的方法是相同的。
2.BackgroundWorker
2.1FindPrimesInput
FindPrimesInput
1 public class FindPrimesInput 2 { 3 public int To 4 { get; set; } 5 6 public int From 7 { get; set; } 8 9 public FindPrimesInput(int from, int to) 10 { 11 To = to; 12 From = from; 13 } 14 15 }
2.2 Worker
Worker
1 public class Worker 2 { 3 public static int[] FindPrimes(int fromNumber, int toNumber) 4 { 5 return FindPrimes(fromNumber, toNumber, null); 6 } 7 8 public static int[] FindPrimes(int fromNumber, int toNumber, System.ComponentModel.BackgroundWorker backgroundWorker) 9 { 10 int[] list = new int[toNumber - fromNumber]; 11 12 // Create an array containing all integers between the two specified numbers. 13 for (int i = 0; i < list.Length; i++) 14 { 15 list[i] = fromNumber; 16 fromNumber += 1; 17 } 18 19 20 //find out the module for each item in list, divided by each d, where 21 //d is < or == to sqrt(to) 22 //if the remainder is 0, the nubmer is a composite, and thus 23 //we mark its position with 0 in the marks array, 24 //otherwise the number is a prime, and thus mark it with 1 25 26 //Math.Floor 返回小于或等于指定双精度浮点数的最大整数。 27 int maxDiv = (int)Math.Floor(Math.Sqrt(toNumber)); 28 29 int[] mark = new int[list.Length]; 30 31 for (int i = 0; i < list.Length; i++) 32 { 33 for (int j = 2; j <= maxDiv; j++) 34 { 35 36 if ((list[i] != j) && (list[i] % j == 0)) 37 { 38 mark[i] = 1; 39 } 40 41 } 42 43 int iteration = list.Length / 100; 44 if ((i % iteration == 0) && (backgroundWorker != null)) 45 { 46 //BackgroundWorker.CancellationPending获取一个值,指示应用程序是否已请求取消后台操作。 47 if (backgroundWorker.CancellationPending) 48 { 49 // Return without doing any more work. 50 return null; 51 } 52 53 //BackgroundWorker.WorkerReportsProgress 获取或设置一个值,该值指示 System.ComponentModel.BackgroundWorker 能否报告进度更新。 54 if (backgroundWorker.WorkerReportsProgress) 55 { 56 //float progress = ((float)(i + 1)) / list.Length * 100; 57 //BackgroundWorker.ReportProgress 引发 System.ComponentModel.BackgroundWorker.ProgressChanged 事件。 58 backgroundWorker.ReportProgress(i / iteration); 59 //(int)Math.Round(progress)); 60 } 61 } 62 63 } 64 65 //create new array that contains only the primes, and return that array 66 int primes = 0; 67 for (int i = 0; i < mark.Length; i++) 68 { 69 if (mark[i] == 0) 70 primes += 1; 71 72 } 73 74 int[] ret = new int[primes]; 75 int curs = 0; 76 for (int i = 0; i < mark.Length; i++) 77 { 78 if (mark[i] == 0) 79 { 80 ret[curs] = list[i]; 81 curs += 1; 82 } 83 } 84 85 if (backgroundWorker != null && backgroundWorker.WorkerReportsProgress) 86 { 87 backgroundWorker.ReportProgress(100); 88 } 89 90 return ret; 91 92 } 93 94 95 }
2.3BackgroundWorker XAML
XAML
1 <Window x:Class="Multithreading.BackgroundWorkerTest" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 Title="Multithreading" Height="323.2" Width="305.6" 5 xmlns:cm="clr-namespace:System.ComponentModel;assembly=System" 6 > 7 <Window.Resources> 8 <cm:BackgroundWorker x:Key="backgroundWorker" 9 WorkerReportsProgress="True" WorkerSupportsCancellation="True" 10 DoWork="backgroundWorker_DoWork" ProgressChanged="backgroundWorker_ProgressChanged" 11 RunWorkerCompleted="backgroundWorker_RunWorkerCompleted"></cm:BackgroundWorker> 12 </Window.Resources> 13 14 <Grid Margin="5"> 15 <Grid.RowDefinitions> 16 <RowDefinition Height="Auto"></RowDefinition> 17 <RowDefinition Height="Auto"></RowDefinition> 18 <RowDefinition Height="Auto"></RowDefinition> 19 <RowDefinition></RowDefinition> 20 <RowDefinition Height="Auto"></RowDefinition> 21 </Grid.RowDefinitions> 22 <Grid.ColumnDefinitions> 23 <ColumnDefinition Width="Auto"></ColumnDefinition> 24 <ColumnDefinition></ColumnDefinition> 25 </Grid.ColumnDefinitions> 26 27 28 <TextBlock Margin="5">From:</TextBlock> 29 <TextBox Name="txtFrom" Grid.Column="1" Margin="5">1</TextBox> 30 <TextBlock Grid.Row="1" Margin="5">To:</TextBlock> 31 <TextBox Name="txtTo" Grid.Row="1" Grid.Column="1" Margin="5">500000</TextBox> 32 33 <StackPanel Orientation="Horizontal" 34 Grid.Row="2" Grid.Column="1"> 35 <Button Name="cmdFind" 36 Margin="5" Padding="3" 37 Click="cmdFind_Click">Find Primes</Button> 38 <Button Name="cmdCancel" 39 Margin="5" Padding="3" IsEnabled="False" 40 Click="cmdCancel_Click">Cancel</Button> 41 </StackPanel> 42 43 <TextBlock Grid.Row="3" Margin="5">Results:</TextBlock> 44 <ListBox Name="lstPrimes" Grid.Row="3" Grid.Column="1" 45 Margin="5"></ListBox> 46 47 48 <ProgressBar Name="progressBar" 49 Grid.Row="4" Grid.ColumnSpan="2" 50 Margin="5" VerticalAlignment="Bottom" MinHeight="20" 51 Minimum="0" Maximum="100" Height="20"></ProgressBar> 52 </Grid> 53 </Window>
2.4 CS code
1 public partial class BackgroundWorkerTest : System.Windows.Window 2 { 3 public BackgroundWorkerTest() 4 { 5 InitializeComponent(); 6 //BackgroundWorker 在单独的线程上执行操作 7 //Window.FindResource(object resourceKey)搜索具有指定密钥的资源,找不到则会引发异常 8 backgroundWorker = ((BackgroundWorker)this.FindResource("backgroundWorker")); 9 } 10 11 private BackgroundWorker backgroundWorker; 12 13 private void cmdFind_Click(object sender, RoutedEventArgs e) 14 { 15 // Disable the button and clear previous results. 16 cmdFind.IsEnabled = false; 17 cmdCancel.IsEnabled = true; 18 lstPrimes.Items.Clear(); 19 20 // Get the search range. 21 int from, to; 22 if (!Int32.TryParse(txtFrom.Text, out from)) 23 { 24 MessageBox.Show("Invalid From value."); 25 return; 26 } 27 if (!Int32.TryParse(txtTo.Text, out to)) 28 { 29 MessageBox.Show("Invalid To value."); 30 return; 31 } 32 33 // Start the search for primes on another thread. 34 FindPrimesInput input = new FindPrimesInput(from, to); 35 backgroundWorker.RunWorkerAsync(input); 36 } 37 38 private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e) 39 { 40 // Get the input values. 41 FindPrimesInput input = (FindPrimesInput)e.Argument; 42 43 // Start the search for primes and wait. 44 int[] primes = Worker.FindPrimes(input.From, input.To, backgroundWorker); 45 46 //BackgroundWorker.CancellationPending 获取一个值,指示应用程序是否已请求取消后台操作。 47 if (backgroundWorker.CancellationPending) 48 { 49 e.Cancel = true; 50 return; 51 } 52 53 // Return the result. 54 e.Result = primes; 55 } 56 57 private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 58 { 59 if (e.Cancelled) 60 { 61 MessageBox.Show("Search cancelled."); 62 } 63 else if (e.Error != null) 64 { 65 // An error was thrown by the DoWork event handler. 66 MessageBox.Show(e.Error.Message, "An Error Occurred"); 67 } 68 else 69 { 70 int[] primes = (int[])e.Result; 71 foreach (int prime in primes) 72 { 73 lstPrimes.Items.Add(prime); 74 } 75 } 76 cmdFind.IsEnabled = true; 77 cmdCancel.IsEnabled = false; 78 progressBar.Value = 0; 79 } 80 81 private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) 82 { 83 //ProgressChangedEventArgs.ProgressPercentage 获取异步任务的进度百分比 84 progressBar.Value = e.ProgressPercentage; 85 } 86 87 private void cmdCancel_Click(object sender, RoutedEventArgs e) 88 { 89 //BackgroundWorker.CancelAsync() 请求取消挂起后的操作 90 backgroundWorker.CancelAsync(); 91 } 92 }