自定义路由事件

本博客为参考工具书,根据个人理解所写,目的在于个人的备忘(我是个新手),如文中有不正确的地方,望指正交流。

WPF中大部分的事件都是可路由的事件,如Button的Click。路由事件相对直接事件的好处在于,不用在消息发送和相应之间建立点对点的订阅关系,发送者只负责发送消息,不关心谁处理,响应者则负责侦听事件和响应。自定义路由事件可用于自定义控件等,如对一个充满自定义名片控件的列表中,对名片控件的共性操作可定义路由事件,然后在列表控件处统一处理。

路由事件的自定义:

public  class TimeTextBox:TextBox
    {
        //1.注册路由事件 
        //注册路由事件第一个参数ReportChangeAndTime为事件的名字,类似Button的Click
        //第二个参数为事件消息传递的类型,自下而上(冒泡Bubble)还是自上而下等
        //第三个参数是该路由事件的处理方法,并约束该方法的参数为ReportChangeAndTimeArgs,该参数中可根据需要添加属性如本例的ChangedTime
       //第四个参数是该路由事件的拥有者,类似Click的拥有者是Button
       public static readonly RoutedEvent ReportChangeAndTimeEvent = EventManager.RegisterRoutedEvent("ReportChangeAndTime", RoutingStrategy.Bubble, typeof(EventHandler<ReportChangeAndTimeArgs>), typeof(TimeTextBox));
       //2.添加CLR事件添加包装器,类似于依赖项属性的包装器,关键字和方法不一样而已
       public event RoutedEventHandler ReportChangeAndTime
       {
           add { this.AddHandler(ReportChangeAndTimeEvent,value); }
           remove { this.RemoveHandler(ReportChangeAndTimeEvent,value); }
       }
       //3.定义激发自定义路由的方法
       protected override void OnTextChanged(TextChangedEventArgs e)
       {
           base.OnTextChanged(e);//原有功能
           ReportChangeAndTimeArgs args = new ReportChangeAndTimeArgs(ReportChangeAndTimeEvent,this);
           args.ChangedTime = DateTime.Now;//为路由事件添加自定义参数
           this.RaiseEvent(args);//激发事件
       }

    }

 

 public class ReportChangeAndTimeArgs :RoutedEventArgs
    {
        public DateTime ChangedTime;
        public ReportChangeAndTimeArgs(RoutedEvent routedEvent, object source):base( routedEvent, source)
        {

        }
    }

在xaml中引入命名空间,添加自定义的空间TimeTextbox

<Window x:Class="INotifyProperChangedPro.Views.FamilyMembersShow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:uc="clr-namespace:INotifyProperChangedPro.UserControl"
        Title="FamilyMembersShow" Height="300" Width="300">
    <Grid uc:TimeTextBox.ReportChangeAndTime ="ReportChangedAndTimeEventHander" x:Name="Grid">
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <StackPanel Grid.Row="0" uc:TimeTextBox.ReportChangeAndTime ="ReportChangedAndTimeEventHander" x:Name="stackPanel">
            <TextBox Text="{Binding ThePerson.name}"></TextBox>
            <TextBox Text="{Binding ThePerson.age}"></TextBox>
            <Button Content="clickMe" Name="ClickButton" Width="60" Click="ClickMeEventHander"></Button>
                    <ListBox x:Name="listBox"></ListBox>
            <uc:TimeTextBox Width="100" x:Name="textbox" ReportChangeAndTime="ReportChangedAndTimeEventHander"></uc:TimeTextBox>
        </StackPanel>
        <DataGrid Grid.Row="1" ItemsSource="{Binding FamilyMembers,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
            <DataGrid.Columns>
                <DataGridTextColumn Header="姓名" Binding="{Binding name}" Width="60"></DataGridTextColumn>
                <DataGridTextColumn Header="年龄" Binding="{Binding age}"></DataGridTextColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

xaml.cs中添加路由事件的响应方法

  private void ReportChangedAndTimeEventHander(object sender, ReportChangeAndTimeArgs e)
        {
            FrameworkElement element = sender as FrameworkElement;
            string timeStr = e.ChangedTime.ToLongDateString();
            string text = string.Format("{0}路由至{1}", timeStr, element.Name);
            listBox.Items.Add(text);
            if(element == this.stackPanel)
            {
                e.Handled  = true;
            }
        }

犹豫指定了冒泡传递方式,当事件自下而上传递至stackpanel时,e.Handled  = true;通知该事件已经被处理,不再继续传递。

WPF的UI分为逻辑树Logical Tree和视觉树Visual Tree,当路由事件被激发后的传递,是沿着Visual Tree进行的。因为逻辑树的节点不是布局组件就是控件, 视觉树包含了所有的细节,这些细节是构成控件本身的更细微的派生自Visual的可视化组件,意思是视觉树比逻辑树更细,包含更多内容,只有路由事件沿着视觉树传递时,可视化组件中的消息才能被传递出来。

路由事件的传递其实是路由事件消息的传递,而路由事件的消息是包含在路由事件参数RoutedEventArgs中,该参数有Source和OriginalSource两个属性,都表示路由事件的源头,前者是逻辑树的源头,后者是视觉树的源头。

 

posted @ 2017-12-12 11:46  大龄程序猿  阅读(175)  评论(0)    收藏  举报