close
MainWindow.xaml
1: <Window x:Class="WpfDispatcherApp.MainWindow"
2: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4: xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
5: xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
6: xmlns:local="clr-namespace:WpfDispatcherApp"
7: mc:Ignorable="d"
8: Title="MainWindow" Height="137" Width="554">
9: <UniformGrid Rows="3" Columns="2">
10: <Label Content="Input a number:" Height="28" HorizontalAlignment="Center" Name="label1" VerticalAlignment="Center" />
11: <TextBox Height="23" HorizontalAlignment="Center" Name="textBox1" VerticalAlignment="Center" Width="100" Text="1000000000"/>
12:
13: <Label Content="Result:" Height="28" HorizontalAlignment="Center" Name="label2" VerticalAlignment="Center" />
14: <TextBox Height="23" HorizontalAlignment="Center" Name="textBox2" VerticalAlignment="Center" Width="100"/>
15: <Button Content="synchronization" Height="23" HorizontalAlignment="Center" Name="button1" VerticalAlignment="Center" Width="100" Click="button1_Click" />
16: <Button Content="asynchronization" Height="23" HorizontalAlignment="Center" Name="button2" VerticalAlignment="Center" Width="100" Click="button2_Click" />
17: </UniformGrid>
18: </Window>
button1_Click 同步執行
1: private void button1_Click(object sender, RoutedEventArgs e)
2: {
3: Int64 inputNumber;
4: Int64.TryParse(this.textBox1.Text, out inputNumber);
5: this.textBox2.Text = "";
6:
7: Thread thread = new Thread(new ParameterizedThreadStart(SyncCallback));
8: thread.Start(inputNumber);
9: }
1: private void SyncCallback(object inputNumber)
2: {
3: this.Dispatcher.BeginInvoke((Action)delegate ()
4: {
5: this.textBox2.Text = TimesTwo((Int64)inputNumber).ToString();
6: });
7: }
在TimesTwo()模擬一個需要5秒模擬時間
1: private double TimesTwo(Int64 inputNumber)
2: {
3: // 模擬大量計算等待時間
4: Thread.Sleep(5000);
5: return 2 * inputNumber;
6: }
上面回呼函式SyncCallback中
BeginInvoke 是非同步執行,但是TimesTwo計算未完成前,介面自然會被卡住this.textBox2
所以,按下button1滑鼠去移動GUI會發現無反應。
1: this.Dispatcher.BeginInvoke((Action)delegate ()
2: {
3: this.textBox2.Text = TimesTwo((Int64)inputNumber).ToString();
4: });
解決方式
將SyncCallback內容修改成AsyncCallback
1: private void AsyncCallback(object inputNumber)
2: {
3: double result = TimesTwo((Int64)inputNumber);
4: this.Dispatcher.BeginInvoke((Action)delegate ()
5: {
6: this.textBox2.Text = result.ToString();
7: });
8: }
由上面程式碼可以看出,TimesTwo 未計算完成前,會另外開非同步呼叫(BeginInvoke)
this.textBox2更新,防止AsyncCallback執行緒因為Timestwo未計算完成而被堵塞,
直到計算Timestwo完成時,再去更新this.textBox2.Text,
所以在TimesTwo計算期間,介面可以自由移動,非同步執行更新this.textBox2.Text
非同步應用: 更新即時影像串流事件Callback
必須加上
this.Dispatcher.BeginInvoke((Action)delegate(){ … });
才能避免MainWindow介面被咬死或是應用程式無反應
1: public void FrameGrabbed(int cameraIndex, double frameCount)
2: {
3: this.Dispatcher.BeginInvoke((Action)delegate()
4: {
5: try
6: {
7: bool flag = cVideo.Snap(cameraIndex);
8: if (!flag)
9: {
10: videoTimer.StopPlayBtn_Click(null, null);
11: return;
12: }
13: videoPgBar.Value = frameCount;
14:
15: // if frameCount equals to the maximum value of the video
16: if (videoPgBar.Maximum == frameCount)
17: videoTimer.StopPlayBtn_Click(null, null);
18:
19: //cVideo.PutTextOfFrameCount(cameraIndex);
20: cVideo.ShowLiveImage(cameraIndex);
21: }
22: catch (Exception)
23: {
24: videoTimer.StopPlayBtn_Click(null, null);
25: }
26: });
27:
28: }
參考資料
1. Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析
2. 深入了解 WPF Dispatcher 的工作原理(Invoke/InvokeAsync 部分)
全站熱搜
留言列表