WPF之路-路由事件

理解路由事件

路由事件是一種可以針對元素樹中的多個偵聽器而不是僅僅針對引發(fā)該事件的對象調用處理程序的事件唆途,也就是說蹬挤,觸發(fā)事件源的父級或子級如果都有對該事件的監(jiān)聽阴孟,則都能觸發(fā)事件

路由事件與一般事件的區(qū)別在于:路由事件是一種用于元素樹的事件彤避,當路由事件觸發(fā)后荐类,它可以向上或向下遍歷可視樹和邏輯樹肃叶,他用一種簡單而持久的方式在每個元素上觸發(fā)蹂随,而不需要任何定制的代碼(如果用傳統的方式實現一個操作,執(zhí)行整個事件的調用則需要執(zhí)行代碼將事件串聯起來)

路由事件的路由策略

所謂的路由策略就是指:路由事件實現遍歷元素的方式

路由事件一般使用以下三種路由策略:

  1. 冒泡:由事件源向上傳遞一直到根元素
  2. 直接:只有事件源才有機會響應事件
  3. 隧道:從元素樹的根部調用事件處理程序并依次向下深入直到事件源

一般情況下因惭,WPF提供的輸入事件都是以隧道/冒泡對實現的岳锁。隧道事件常常被稱為Preview事件

冒泡

程序設計思路是,將多個Grid嵌套起來蹦魔,構成父子結構激率,在最底層支Grid上定義一個按鈕咳燕,綁定一個單擊事件,并且按鈕的所有低級元素都綁定該事件乒躺,它們使用同一個事件處理程序招盲;再定義一個ListBox,當事件處理程序執(zhí)行的時候嘉冒,打印出事件激發(fā)者的名字曹货,這樣便能看到事件執(zhí)行的順序

下圖是界面設計:

下面是XMAL代碼,按鈕和每一個Grid都綁定了Button.Click="Btn_Click"

<Window x:Class="WPF_CODE.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <!--最外層的Grid-->
    <Grid Button.Click="Btn_Click" Name="Grid_1" Background="#FF43AEAE">
        <!--定義兩行-->
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        
        <!--第二層Grid-->
        <Grid Button.Click="Btn_Click" Name="Grid_2"  Margin="10" Background="#FF8D888D" Grid.Row="0">
            <!--定義兩列-->
            <Grid.ColumnDefinitions>
                <ColumnDefinition></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            
            <!--第三層左側Grid-->
            <Grid Button.Click="Btn_Click" Name="Grid_3_Left" Grid.Column="0" Background="#FF3D8F3A" Margin="10">
                <!--添加一個按鈕-->
                <Button Button.Click="Btn_Click" Name="ButtonLeft" Width="80" Height="50" Content="Hello"/>
            </Grid>
            
            <!--第三層右側Grid-->
            <Grid Button.Click="Btn_Click" Name="Grid_3_Right" Grid.Column="1" Background="#FFC95E3E" Margin="10">
                <!--添加一個按鈕-->
                <Button Button.Click="Btn_Click" Name="ButtonRight" Width="80" Height="50" Margin="10" Content="World"></Button>
            </Grid>
            
        </Grid>
        
        <!--定義一個ListBox健爬,用于輸出結果-->
        <ListBox Name="Print_List"  Grid.Row="1"/>
        
    </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 WPF_CODE
{
    /// <summary>
    /// MainWindow.xaml 的交互邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        // 事件處理程序
        private void Btn_Click(object sender, RoutedEventArgs e)
        {
            //sender是指由誰激發(fā)了這個事件處理程序控乾,它可以獲取到觸發(fā)對象
            //通過(sender as FrameworkElement).Name轉換,將觸發(fā)控件的名稱拿出來娜遵,
            string message = "觸發(fā)者:"+(sender as FrameworkElement).Name.ToString();
            this.Print_List.Items.Add(message);

            //e包含了與事件相關的一些參數蜕衡,e.Handled如果設置為True,則表示冒泡不再繼續(xù)
            //e.Handled = true;
        }
    }
}

運行程序设拟,點擊左側按鈕慨仿,結果如下:

點擊右側按鈕,結果如下:

可以看出纳胧,事件首先在源元素上觸發(fā)镰吆,然后從每一個元素向上沿著樹傳遞,直到到達根元素為止(或者直到處理程序把事件標記為已處理為止)跑慕,從而調用這些元素中的路由事件

如果將事件處理程序里的e.Handled = true;代碼放開万皿,效果如下

//e包含了與事件相關的一些參數,e.Handled如果設置為True核行,則表示冒泡不再繼續(xù)
e.Handled = true;

即事件處理程序只要被觸發(fā)一次牢硅,并不會發(fā)生冒泡

隧道

隧道的執(zhí)行順序與冒泡正好相反,直接看例子芝雪,然后再解釋减余,將上便中所有的Click事件改為PreviewMouseDown事件,而綁定的事件處理程序不變

XAML代碼如下:

<Window x:Class="WPF_CODE.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <!--最外層的Grid-->
    <Grid PreviewMouseDown="Btn_Click" Name="Grid_1" Background="#FF43AEAE">
        <!--定義兩行-->
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        
        <!--第二層Grid-->
        <Grid PreviewMouseDown="Btn_Click" Name="Grid_2"  Margin="10" Background="#FF8D888D" Grid.Row="0">
            <!--定義兩列-->
            <Grid.ColumnDefinitions>
                <ColumnDefinition></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            
            <!--第三層左側Grid-->
            <Grid PreviewMouseDown="Btn_Click" Name="Grid_3_Left" Grid.Column="0" Background="#FF3D8F3A" Margin="10">
                <!--添加一個按鈕-->
                <Button PreviewMouseDown="Btn_Click" Name="ButtonLeft" Width="80" Height="50" Content="Hello"/>
            </Grid>
            
            <!--第三層右側Grid-->
            <Grid PreviewMouseDown="Btn_Click" Name="Grid_3_Right" Grid.Column="1" Background="#FFC95E3E" Margin="10">
                <!--添加一個按鈕-->
                <Button PreviewMouseDown="Btn_Click" Name="ButtonRight" Width="80" Height="50" Margin="10" Content="World"></Button>
            </Grid>
            
        </Grid>
        
        <!--定義一個ListBox惩系,用于輸出結果-->
        <ListBox Name="Print_List"  Grid.Row="1"/>
        
    </Grid>
    
</Window>

運行程序位岔,查看效果:

可以看出,隧道是指事件首先是從根元素上被觸發(fā)堡牡,然后從每一個元素向下沿著樹傳遞抒抬,直到到達根元素為止(或者直到到達處理程序把事件標記為已處理為止),他的執(zhí)行方式正好與冒泡策略相反

所有的隧道事件都以Preview開頭

后臺代碼記得將e.Handled=true注釋掉

直接策略

事件僅僅在源元素上觸發(fā)晤柄,這個與普通的.Net事件的行為相同擦剑,不同的是這樣的事件仍然會參與一些路由事件的特定機制,如事件觸發(fā)器等;該事件唯一可能的處理程序是與其掛接的委托

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末抓于,一起剝皮案震驚了整個濱河市做粤,隨后出現的幾起案子,更是在濱河造成了極大的恐慌捉撮,老刑警劉巖怕品,帶你破解...
    沈念sama閱讀 219,366評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異巾遭,居然都是意外死亡肉康,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,521評論 3 395
  • 文/潘曉璐 我一進店門灼舍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吼和,“玉大人,你說我怎么就攤上這事骑素§排遥” “怎么了?”我有些...
    開封第一講書人閱讀 165,689評論 0 356
  • 文/不壞的土叔 我叫張陵献丑,是天一觀的道長末捣。 經常有香客問我,道長创橄,這世上最難降的妖魔是什么箩做? 我笑而不...
    開封第一講書人閱讀 58,925評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮妥畏,結果婚禮上邦邦,老公的妹妹穿的比我還像新娘。我一直安慰自己醉蚁,他們只是感情好燃辖,可當我...
    茶點故事閱讀 67,942評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著馍管,像睡著了一般郭赐。 火紅的嫁衣襯著肌膚如雪薪韩。 梳的紋絲不亂的頭發(fā)上确沸,一...
    開封第一講書人閱讀 51,727評論 1 305
  • 那天,我揣著相機與錄音俘陷,去河邊找鬼罗捎。 笑死,一個胖子當著我的面吹牛拉盾,可吹牛的內容都是我干的桨菜。 我是一名探鬼主播,決...
    沈念sama閱讀 40,447評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼倒得!你這毒婦竟也來了泻红?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,349評論 0 276
  • 序言:老撾萬榮一對情侶失蹤霞掺,失蹤者是張志新(化名)和其女友劉穎谊路,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體菩彬,經...
    沈念sama閱讀 45,820評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡缠劝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,990評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了骗灶。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片惨恭。...
    茶點故事閱讀 40,127評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖耙旦,靈堂內的尸體忽然破棺而出脱羡,到底是詐尸還是另有隱情,我是刑警寧澤免都,帶...
    沈念sama閱讀 35,812評論 5 346
  • 正文 年R本政府宣布轻黑,位于F島的核電站,受9級特大地震影響琴昆,放射性物質發(fā)生泄漏氓鄙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,471評論 3 331
  • 文/蒙蒙 一业舍、第九天 我趴在偏房一處隱蔽的房頂上張望抖拦。 院中可真熱鬧,春花似錦舷暮、人聲如沸态罪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,017評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽复颈。三九已至,卻和暖如春沥割,著一層夾襖步出監(jiān)牢的瞬間耗啦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,142評論 1 272
  • 我被黑心中介騙來泰國打工机杜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留帜讲,地道東北人。 一個月前我還...
    沈念sama閱讀 48,388評論 3 373
  • 正文 我出身青樓椒拗,卻偏偏與公主長得像似将,于是被迫代替她去往敵國和親获黔。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,066評論 2 355

推薦閱讀更多精彩內容

  • ??JavaScript 與 HTML 之間的交互是通過事件實現的。 ??事件腋舌,就是文檔或瀏覽器窗口中發(fā)生的一些特...
    霜天曉閱讀 3,495評論 1 11
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理预茄,服務發(fā)現,斷路器侦厚,智...
    卡卡羅2017閱讀 134,668評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,182評論 25 707
  • 芬蘭的冬天很長耻陕,從十月底一直延續(xù)到來年的四五月。半年的時間里刨沦,人們都帽子诗宣、圍巾、手套還有大衣想诅。噢召庞,還有防水的靴子,...
    Samoi閱讀 259評論 0 0
  • 晨間思4 生活里的隨機性與規(guī)則性 雪花的花瓣 有一次出差在高鐵上看雜志来破,看到一個攝影師拍攝的顯微鏡下的雪花的...
    huangdan閱讀 483評論 0 1