最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解WPF中的隧道路由和冒泡路由事件

 更新時間:2021年04月02日 09:38:17   作者:杜文龍  
這篇文章主要介紹了WPF中的隧道路由和冒泡路由事件的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用c#的wpf,感興趣的朋友可以了解下

  WPF中使用路由事件升級了傳統(tǒng)應(yīng)用開發(fā)中的事件,在WPF中使用路由事件能更好的處理事件相關(guān)的邏輯,我們從這篇開始整理事件的用法和什么是直接路由,什么是冒泡路由,以及什么是隧道路由。

事件最基本的用法

  在基于事件驅(qū)動的開發(fā)中,把代碼放在響應(yīng)注冊的事件的處理函數(shù)內(nèi),比如Click事件、MouseDown事件、MouseUp事件等等。每個控件響應(yīng)自己的注冊事件,有很多如果在事件上有相互關(guān)聯(lián)和影響的事件,就要在一個業(yè)務(wù)邏輯里寫比較多的代碼。而路由事件主要的優(yōu)勢就是路由事件可以在元素樹上進行傳遞,并且沿著元素樹的傳播途徑被事件處理程序處理。這樣我們寫代碼的過程中時就可以更好的組織代碼到合適的位置。

   WPF事件模型和WPF屬性模型非常類似,與依賴項屬性一樣,路由事件由只讀的靜態(tài)字段表示,在靜態(tài)構(gòu)造函數(shù)中注冊,并通過標(biāo)準(zhǔn)的.NET事件定義進行封裝。這里我們只講如何更好的使用。原理部分請看源碼。比如ButtonBase提供的Click事件。

     <Button Content="事件處理程序" Click="Button_Click"/>
     private void Button_Click(object sender, RoutedEventArgs e)
    {
      //這是Click事件處理程序代碼部分。
    }

  在注冊事件后,在事件處理程序中第一個參數(shù) sender提供引發(fā)該事件的對象,第二個參數(shù)是EventArgs對象。在WPF中如果事件不需要傳遞額外的信息,可以使用RoutedEventArgs類,如果需要傳遞額外的信息,就要是有繼承自RoutedEventArgs的對象。比如處理inkcanvas墨跡繪制的。比如處理多點觸控的。這些都是變相繼承RoutedEventArgs類。里面會包含在這種場景下更加多的信息。 

注冊事件的幾種寫法:

1)在XAML代碼中<Button x:Name="EventMessageButton" Content="事件處理程序" MouseUp="EventMessageButton_MouseUp"/>
2)在cs代碼中 EventMessageButton.MouseUp += EventMessageButton_MouseUp;
3)在cs代碼中 EventMessageButton.MouseUp += new MouseButtonEventHandler(EventMessageButton_MouseUp);

private void EventMessageButton_MouseUp(object sender, MouseButtonEventArgs e)
{
  //我是處理程序。
}

 第一種寫法:我們使用XAML文件中在Button元素內(nèi)使用MouseUp來創(chuàng)建后臺事件處理代碼 Btn_eventMessge_MouseUp

 第二種寫法:我們在后臺代碼中使用MouseUp+=的方式注冊。一種是New MouseButtonEventHandler傳入方法名。一種是匿名的直接傳入方法名,這三種注冊方式達成的效果是一樣的。

而這三種實際上使用的是事件封裝器。另一種方式是通過使用UIElement.AddHandler來直接連接事件。這里看個人習(xí)慣把。但是各種寫法主要解決的問題還是解耦,因為這些會關(guān)聯(lián)到后面的命令,動畫。模板。觸發(fā)器。MVVM下的使用,等等。這是個比較長久的問題。所以在這里,能夠使用,看得明白,目前這個階段就可以了。

我們繼續(xù)往下。解除關(guān)聯(lián)

在注冊事件的時候,最好先使用-=來解除關(guān)聯(lián),避免多次觸發(fā)不合符預(yù)期的監(jiān)聽事件。斷開使用-=或者使用UIElement.RemoveHandler來解除關(guān)聯(lián)。  因為事件在多次+=注冊事件處理程序是可行的。而事件的多詞解除關(guān)系不會引發(fā)任何問題,因此不要擔(dān)心+=和-=不匹配的問題。

public MainWindow()
    {
      InitializeComponent();
          EventMessageButton.MouseUp -= EventMessageButton_MouseUp;               EventMessageButton.MouseUp += EventMessageButton_MouseUp;

    }

理解路由事件

我們知道了事件可以在元素上注冊事件處理程序,那么我們知道內(nèi)容控件是可以相互嵌套各種奇奇怪怪的組合以達到自己想要的效果,在這種情況下我們假設(shè)一個比較常見的場景。我們有一個標(biāo)簽,標(biāo)簽中包含一個StackPanel面板,面板中包含一幅圖片和2個文本。

<Label BorderBrush="Black" BorderThickness="1">
      <StackPanel>
        <TextBlock Margin="3">
         我是圖片標(biāo)題
        </TextBlock>
        <Image Source="1.png" Stretch="None"/>
        <TextBlock Margin="3">
          我是圖片正文
        </TextBlock>
      </StackPanel>
 </Label>

我們的控件來回嵌套內(nèi)容結(jié)構(gòu)很復(fù)雜了。但是我們想在用戶點擊時只在一個地方響應(yīng)我們的代碼。如果為每個元素都關(guān)聯(lián)同一個事件處理程序,代碼會很亂。而且難以維護。而路由事件就是為了解決這個問題的。路由事件分為三種:

1)和普通的.NET事件類似,直接路由事件(direct event) 他們源于一個元素,不傳遞給其他元素,比如MouseEnter事件,是直接路由事件。

2)向上傳遞的冒泡路由事件(bubbling event)比如MouseDown事件,是冒泡路由事件,該事件先由被單擊的元素引發(fā),接下來被該元素的父元素引發(fā),然后被父元素的父元素引發(fā),以此類推。直到元素樹的頂部。

3)向下傳遞的隧道路由事件(tunneling event) 比如PreviewKeyDown事件,隧道路由事件在事件到達恰當(dāng)?shù)目臻g之前為預(yù)覽事件和終止事件提供了機會,比如PreviewKeyDown事件可以截獲是否按下了某個鍵,首先在窗口級別上,然后是更具體的容器,直到當(dāng)按下時具有焦點的元素。

當(dāng)使用EventManager.RegisterEvent()發(fā)給發(fā)注冊路由事件時,需要傳遞一個RoutingStrategy枚舉,指示希望用于事件的事件行為。

MouseUP和MouseDown事件都是冒泡路由事件,因此當(dāng)在上面的圖片中按下鼠標(biāo)左鍵后順序觸發(fā)MouseDown事件的順序是冒泡的。我們使用Snoop軟件抓取一下過程:

從圖中我們看到首先觸發(fā)的是PreviewMouseDown的隧道路由。他可以讓我們有機會預(yù)覽事件或終止事件。我們看到了從MainWindow開始到最終的Image結(jié)束。我們沒有終止路由。所以進行了下一輪的冒泡路由。從Image開始到MainWindow。

整個流程就結(jié)束了。我們看到路由事件提供了對事件處理非常豐富的功能。具體的隧道或冒泡行為可以參考RoutedEventArgs中的內(nèi)容。

Source 屬性是引發(fā)事件的的對象。 OriginalSource是最初是什么對象引發(fā)了事件。RoutedEvent為觸發(fā)的事件提供的RoutedEvent對象。里面是需要用到的當(dāng)前的參數(shù),比如鼠標(biāo)坐標(biāo),touch等等。Handled屬性的作用是終止事件是否繼續(xù)傳遞。

我們現(xiàn)在開始在這個例子上添加代碼。用于演示我們怎么處理冒泡路由。

<Window x:Class="WPFEvent.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:WPFEvent"
    mc:Ignorable="d" MouseUp="EventResponseProcess_MouseUp"
    Title="MainWindow" Height="450" Width="800">
  <Grid Margin="3" MouseUp="EventResponseProcess_MouseUp">
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"></RowDefinition>
      <RowDefinition Height="*"></RowDefinition>
      <RowDefinition Height="Auto"></RowDefinition>
      <RowDefinition Height="Auto"></RowDefinition>
    </Grid.RowDefinitions>
    <Label Margin="5" Grid.Row="0" HorizontalAlignment="Left" Background="AliceBlue" BorderBrush="Black" BorderThickness="1" MouseUp="EventResponseProcess_MouseUp">
      <StackPanel MouseUp="EventResponseProcess_MouseUp">
        <TextBlock Margin="3" MouseUp="SomethingClicked">
         我是圖片標(biāo)題
        </TextBlock>
        <Image Source="1.png" Stretch="None" MouseUp="EventResponseProcess_MouseUp"/>
        <TextBlock Margin="3">
          我是圖片正文
        </TextBlock>
      </StackPanel>
    </Label>
    <ListBox Grid.Row="1" Margin="5" Name="MessageListBox"></ListBox>
    <CheckBox Grid.Row="2" Margin="5" Name="HandlerCheckBox">
      Handle first event
    </CheckBox>
    <Button Grid.Row="3" Margin="5" Padding="3" HorizontalAlignment="Right" Name="ClearButton" Click="ClearButton_Click">Clear List</Button>
  </Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 WPFEvent
{
  /// <summary>
  /// MainWindow.xaml 的交互邏輯
  /// </summary>
  public partial class MainWindow : Window
  {
    public MainWindow()
    {
      InitializeComponent();
    }

    protected int eventCounter = 0;
    private void EventResponseProcess_MouseUp(object sender, MouseButtonEventArgs e)
    {
      eventCounter++;
      string message = $"#{ eventCounter}:\r\n Sender: {sender} \r\n Source: {e.Source} \r\n Original Source: {e.OriginalSource}"; 
      MessageListBox.Items.Add(message);
      e.Handled = (bool)HandleCheckBox.IsChecked;
    }
       private void ClearButton_Click(object sender, RoutedEventArgs e)      { 
          }
  }
}

和上圖一樣,我們嘗試觀察執(zhí)行過程??聪掠|發(fā)過程,我們就能了解這個冒泡路由的工作過程了。上面寫的這個例子。主要是讓我們熟悉對于事件傳入?yún)?shù)OriginalSource的使用。勾選界面上的HandleCheckBox復(fù)選框可以終止冒泡事件,從而只觸發(fā)第一個Image的事件。可以自己寫代碼嘗試一下整個過程。

有個方法可以接收終止的事件消息,使用AddHandler()重載的方法。

這里還有一個常用的技巧,事件的附加。

如下面的代碼,在StackPanel中不存在Button的Click事件,但是可以通過ButtonBase.Click獲取按鈕的點擊事件,此事件將會在StackPanel容器里面的任意按鈕被點擊時觸發(fā)。

  <StackPanel ButtonBase.Click="StackPanel_Click" Margin="5">
      <Button Content="按鈕A" Click="Button_Click"/>
      <Button Content="按鈕B" Click="Button_Click"/>
      <Button Content="按鈕C" Click="Button_Click"/>
  </StackPanel>

隧道路由這里就不寫了,前面已經(jīng)講過。隧道路由命名都是Preview開頭的。隧道路由全部結(jié)束了之后,同級的冒泡路由才開始。隧道路由主要是做預(yù)先處理,可以停止路由事件,也可以在事件處理程序中寫一些對應(yīng)的處理代碼。

這篇文章只是熟悉什么是路由事件,了解什么是冒泡路由、什么是隧道路由。所以理解這些是什么事件,這些事件在如何工作就可以了。后面會講到Window類的生命周期。才會去深入分析WPF下的事件過程。

以上就是詳解WPF中的隧道路由和冒泡路由事件的詳細內(nèi)容,更多關(guān)于WPF中的隧道路由和冒泡路由事件的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 基于WPF實現(xiàn)簡單的下拉篩選控件

    基于WPF實現(xiàn)簡單的下拉篩選控件

    這篇文章主要為大家詳細介紹了如何基于WPF實現(xiàn)簡單的下拉篩選控件,文中的示例代碼講解詳細,對我們學(xué)習(xí)或工作有一定幫助,感興趣的小伙伴可以了解一下
    2023-04-04
  • C#中OpenCvSharp 通過特征點匹配圖片的方法

    C#中OpenCvSharp 通過特征點匹配圖片的方法

    這篇文章主要介紹了OpenCvSharp 通過特征點匹配圖片的方法,本文通過實例代碼給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-09-09
  • C#實現(xiàn)簡單成績管理系統(tǒng)的完整步驟

    C#實現(xiàn)簡單成績管理系統(tǒng)的完整步驟

    這篇文章主要給大家介紹了關(guān)于C#實現(xiàn)簡單成績管理系統(tǒng)的完整步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者使用C#具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-11-11
  • 怎么利用c#修改services的Startup type

    怎么利用c#修改services的Startup type

    C#必須以管理員的權(quán)限運行才能達到效果的,不然service的startmode修改是沒有效果的
    2013-08-08
  • 詳細解析C#多線程同步事件及等待句柄

    詳細解析C#多線程同步事件及等待句柄

    本篇文章主要介紹了C#多線程同步事件及等待句柄,希望通過本篇的介紹能對常見的線程同步方法有一個整體的認識,有需要的可以了解一下。
    2016-11-11
  • C#定位txt指定行的方法小例子

    C#定位txt指定行的方法小例子

    近日,在開發(fā)CAD插件時需要定位TXT文件指定行并將其選中,在網(wǎng)絡(luò)找了一下沒有找到現(xiàn)成的,自己編了一個定位程序,實現(xiàn)了定位功能..與大家分享
    2013-04-04
  • C#如何將DLL打包到程序中

    C#如何將DLL打包到程序中

    這篇文章主要介紹了C#如何將DLL打包到程序中問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-01-01
  • C#使用PPT組件的CreateVideo方法實現(xiàn)視頻生成

    C#使用PPT組件的CreateVideo方法實現(xiàn)視頻生成

    這篇文章主要為大家詳細介紹了C#如何使用PPT組件的CreateVideo方法實現(xiàn)視頻生成,文中的示例代碼講解詳細,有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-10-10
  • C#泛型詳解及關(guān)鍵字作用

    C#泛型詳解及關(guān)鍵字作用

    這篇文章主要來講講c#中的泛型,因為泛型在c#中有很重要的位置,對于寫出高可讀性,高性能的代碼有著關(guān)鍵的作用,大家都知道泛型公共語言運行庫是非常重要功能,那么為什么使用泛型呢,帶著這個問題一起通過本文學(xué)習(xí)下吧
    2021-08-08
  • Unity使用ScrollRect制作搖桿

    Unity使用ScrollRect制作搖桿

    這篇文章主要為大家詳細介紹了Unity使用ScrollRect制作搖桿,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-04-04

最新評論

堆龙德庆县| 眉山市| 资中县| 阿尔山市| 中西区| 巫溪县| 来安县| 锡林郭勒盟| 苏尼特左旗| 南安市| 扎囊县| 梓潼县| 新河县| 荆州市| 紫云| 荣成市| 城固县| 伊通| 达孜县| 商洛市| 屯门区| 贵定县| 丹寨县| 宝山区| 石嘴山市| 广灵县| 汽车| 全州县| 赫章县| 阿拉善右旗| 卓尼县| 浦江县| 维西| 濉溪县| 仙游县| 花莲县| 阿坝县| 闽清县| 龙州县| 清原| 蒙阴县|