close

image


image

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: }
button1開一個執行緒執行回呼函式SyncCallback
   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: }


image


image


參考資料


1. Dispatcher.BeginInvoke()方法使用不当导致UI界面卡死的原因分析

2. 深入了解 WPF Dispatcher 的工作原理(Invoke/InvokeAsync 部分)

arrow
arrow
    全站熱搜

    me1237guy 發表在 痞客邦 留言(0) 人氣()