WPF 路由事件和Javascript 事件

WPF路由事件

路由事件的定义:

路由事件是一种可以针对元素树中的多个侦听器(而不是仅针对引发该事件的对象)调用处理程序的事件。

理解路由事件

路由事件是一种可以针对元素树中的多个侦听器而不是仅仅针对引发该事件的对象调用处理程序的事件,也就是说,触发事件源的父级或子级如果都有对该事件的监听,则都能触发事件

路由事件与一般事件的区别在于:路由事件是一种用于元素树的事件,当路由事件触发后,它可以向上或向下遍历可视树和逻辑树,他用一种简单而持久的方式在每个元素上触发,而不需要任何定制的代码(如果用传统的方式实现一个操作,执行整个事件的调用则需要执行代码将事件串联起来)。

路由事件的分类

1、直接路由事件

和普通的控件事件一样,不能传递,只有事件源才有机会响应事件

2、冒泡路由事件

由事件源向上传递一直到根元素,由控件向上传递,直到窗体

3、隧道路由事件

冒泡和隧道事件是成对出现的,隧道路由事件是冒泡路由事件前面+preview,隧道路由事件比冒泡路由事件先触发。

和冒泡路由事件方向相反,由容器向下传递,从元素树的根部调用事件处理程序并依次向下深入直到事件源

冒泡路由事件实例

下面是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是指由谁激发了这个事件处理程序,它可以获取到触发对象
            //通过(sender as FrameworkElement).Name转换,将触发控件的名称拿出来,
            string message = "触发者:"+(sender as FrameworkElement).Name.ToString();
            this.Print_List.Items.Add(message);

            //e包含了与事件相关的一些参数,e.Handled如果设置为True,则表示冒泡不再继续
            //e.Handled = true;
        }
    }
}

运行结果

可以看出,事件首先在源元素上触发,然后从每一个元素向上沿着树传递,直到到达根元素为止(或者直到处理程序把事件标记为已处理为止),从而调用这些元素中的路由事件

如果将事件处理程序里的e.Handled = true;代码放开,效果如下 

//e包含了与事件相关的一些参数,e.Handled如果设置为True,则表示冒泡不再继续
e.Handled = true;

 

隧道事件

隧道的执行顺序与冒泡正好相反,直接看例子,然后再解释,将上便中所有的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>

运行结果

可以看出,隧道是指事件首先是从根元素上被触发,然后从每一个元素向下沿着树传递,直到到达根元素为止(或者直到到达处理程序把事件标记为已处理为止),他的执行方式正好与冒泡策略相反

所有的隧道事件都以Preview开头

后台代码记得将e.Handled=true注释掉

 

CLR事件和路由事件原理


传统的CLR事件+=的背后: Delegate.Combine(…)

路由事件+=的背后:AddHandler(…)

传统的CLR事件-=的背后:Delegate.Remove(…)

路由事件-=的背后:RemoveHandler(…)

 

Javascript 事件

Javascript 事件&冒泡

文章地址:https://blog.csdn.net/qinzheng_chen/article/details/115833458


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WPF中,自定义事件可以通过以下步骤实现: 1. 定义一个自定义事件: ``` public class MyRoutedEvent : RoutedEventArgs { public MyRoutedEvent() : base() { } public MyRoutedEvent(RoutedEvent routedEvent) : base(routedEvent) { } public MyRoutedEvent(RoutedEvent routedEvent, object source) : base(routedEvent, source) { } public string MyEventArgs { get; set; } // 自定义事件参数 public static readonly RoutedEvent MyEvent = EventManager.RegisterRoutedEvent("MyEvent", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyRoutedEvent)); // 添加事件处理程序 public event RoutedEventHandler MyEventHandler { add { AddHandler(MyEvent, value); } remove { RemoveHandler(MyEvent, value); } } // 触发事件 public void RaiseMyEvent() { RaiseEvent(new RoutedEventArgs(MyEvent)); } } ``` 在这个例子中,我们定义了一个继承自RoutedEventArgs的类,并添加了一个自定义事件参数MyEventArgs。我们还定义了一个静态只读的MyEvent事件,并为它添加了一个事件处理程序MyEventHandler。最后,我们实现了一个RaiseMyEvent方法,该方法将触发MyEvent事件。 2. 在UI元素中使用自定义事件: ``` <Button Content="Click me" Click="Button_Click"/> ``` 在这个例子中,我们将按钮的Click事件绑定到Button_Click方法。在该方法中,我们可以创建一个MyRoutedEvent实例并触发它: ``` private void Button_Click(object sender, RoutedEventArgs e) { MyRoutedEvent myEvent = new MyRoutedEvent(); myEvent.MyEventArgs = "Hello World!"; RaiseEvent(myEvent); } ``` 在这个例子中,我们创建了一个MyRoutedEvent实例,并将MyEventArgs设置为“Hello World!”。然后,我们调用RaiseEvent方法触发MyEvent事件。 3. 在父控件中处理自定义事件: ``` <Grid local:MyRoutedEvent.MyEvent="Grid_MyEvent"> <!-- 子控件 --> </Grid> ``` 在这个例子中,我们将Grid控件的MyEvent事件绑定到Grid_MyEvent方法。在该方法中,我们可以获取到MyEventArgs的值: ``` private void Grid_MyEvent(object sender, RoutedEventArgs e) { MyRoutedEvent myEvent = (MyRoutedEvent)e; string myEventArgs = myEvent.MyEventArgs; // 处理自定义事件 } ``` 在这个例子中,我们获取MyRoutedEvent实例,并将其转换为MyRoutedEvent类型。然后,我们可以获取MyEventArgs的值并进行处理。 这就是一个简单的自定义事件的实现方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值