WPF RoutedEvent and Command Sample

        一直对WPF中的RoutedEvent和Command不太理解其原理,最近看了

ButtonBase.cs(http://reflector.webtropy.com/default.aspx/4@0/4@0/DEVDIV_TFS/Dev10/Releases/RTMRel/wpf/src/Framework/System/Windows/Controls/Primitives/ButtonBase@cs/1305600/ButtonBase@cs)

和Button.cs(http://reflector.webtropy.com/default.aspx/4@0/4@0/untmp/DEVDIV_TFS/Dev10/Releases/RTMRel/wpf/src/Framework/System/Windows/Controls/Button@cs/1458001/Button@cs)

源代码才逐渐明白一些,所以赶快写下来,以备后观。

编写自己的 RoutedEvent

要编写自己的RoutedEvent需要两大步骤,1是定义和注册RoutedEvent, 2是引发RoutedEvent。

1、定义和注册RoutedEvent

需要三个步骤,a, definite your event. b, Register your event with EventManager. c, Wrap your event with traditional event wrapper(Property).

比如我要写一个自己的Custom Control, 一个自己的Button,该Button不只有Click事件,同时还有自己定义的MyClick事件。那么如何定义和注册RoutedEvent呢,如下:

      // 步骤1.要添加一个 RoutedEvent 首先要用EventManager注册一个 RoutedEvent
        public static readonly RoutedEvent MyClickEvent = EventManager.RegisterRoutedEvent(
            "MyClick", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButton));

        // 步骤2.要定义一个Property 然后增加 对add/remove RoutedEventHandler的处理
        public event RoutedEventHandler MyClick
        {
            add 
            {
                base.AddHandler(MyButton.MyClickEvent, value);
            }

            remove
            {
                base.RemoveHandler(MyButton.MyClickEvent, value);
            }
        }

上面的步骤1就是我合并后的a,b两步。

2、引发RoutedEvent

要引发RoutedEvent, 需要处理更底层的Event事件,然后再Raise自己的RoutedEvent。我本来采用处理鼠标左键按下的事件来引发自定义的事件,但是好像屏蔽掉了Base的Click和Command处理。我想原因应该是没有处理左键弹起的事件。后来干脆OverRide ButtonBase.OnClick。

// 3. 要通过对底层事件的处理引发自定义的事件。这里重写MouseDoubleClick
        //protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        //{
        //    //base.OnMouseLeftButtonDown(e); //base 的函数不起作用 Click 和 Command 都没有处理 

        //    // new一个RoutedEventArgs
        //    RoutedEventArgs re = new RoutedEventArgs(MyButton.MyClickEvent, this);
        //    // Raise it.
        //    base.RaiseEvent(re);

        //    base.OnMouseLeftButtonDown(e);
        //}
        //  由于ButtonBase有virtual OnClick 会在OnMouseLeftButtonDown时被调用,可以重写此函数试一试
        protected override void OnClick()
        {
            // 首先调用base的OnClick
            try
            {
                base.OnClick();
            }
            finally
            {
                // new一个RoutedEventArgs
                RoutedEventArgs re = new RoutedEventArgs(MyButton.MyClickEvent, this);
                //    // Raise it.
                base.RaiseEvent(re);
            }
        }//结果与设想的一样 引发Click,执行命令,并且处理MyClick.

 

然后就是编写自己的Button样式,并且使用该Button

样式:

  <Style TargetType="{x:Type local:MyButton}">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type local:MyButton}">
          <Border Background="LightBlue"
                            BorderBrush="Black"
                            BorderThickness="1">
            <ContentPresenter></ContentPresenter>
          </Border>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>

使用之

<local:MyButton Click="Button_Click" Command="local:ExampleCommands.Requery" MyClick="MyButton_MyClick">My button</local:MyButton>

 

详细代码如下

// MyButton.CS

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;
using System.Windows.Controls.Primitives;

namespace CommandAndEvent
{
    /// <summary>
    /// Follow steps 1a or 1b and then 2 to use this custom control in a XAML file.
    ///
    /// Step 1a) Using this custom control in a XAML file that exists in the current project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:CommandAndEvent"
    ///
    ///
    /// Step 1b) Using this custom control in a XAML file that exists in a different project.
    /// Add this XmlNamespace attribute to the root element of the markup file where it is 
    /// to be used:
    ///
    ///     xmlns:MyNamespace="clr-namespace:CommandAndEvent;assembly=CommandAndEvent"
    ///
    /// You will also need to add a project reference from the project where the XAML file lives
    /// to this project and Rebuild to avoid compilation errors:
    ///
    ///     Right click on the target project in the Solution Explorer and
    ///     "Add Reference"->"Projects"->[Browse to and select this project]
    ///
    ///
    /// Step 2)
    /// Go ahead and use your control in the XAML file.
    ///
    ///     <MyNamespace:MyButton/>
    ///
    /// </summary>
    public class MyButton : ButtonBase
    {
        static MyButton()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(MyButton), new FrameworkPropertyMetadata(typeof(MyButton)));
        }

        // 1.要添加一个 RoutedEvent 首先要用EventManager注册一个 RoutedEvent
        public static readonly RoutedEvent MyClickEvent = EventManager.RegisterRoutedEvent(
            "MyClick", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButton));

        // 2.要定义一个Property 然后增加 对add/remove RoutedEventHandler的处理
        public event RoutedEventHandler MyClick
        {
            add 
            {
                base.AddHandler(MyButton.MyClickEvent, value);
            }

            remove
            {
                base.RemoveHandler(MyButton.MyClickEvent, value);
            }
        }

        // 3. 要通过对底层事件的处理引发自定义的事件。这里重写MouseDoubleClick
        //protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        //{
        //    //base.OnMouseLeftButtonDown(e); //base 的函数不起作用 Click 和 Command 都没有处理 

        //    // new一个RoutedEventArgs
        //    RoutedEventArgs re = new RoutedEventArgs(MyButton.MyClickEvent, this);
        //    // Raise it.
        //    base.RaiseEvent(re);

        //    base.OnMouseLeftButtonDown(e);
        //}
        //  由于ButtonBase有virtual OnClick 会在OnMouseLeftButtonDown时被调用,可以重写此函数试一试
        protected override void OnClick()
        {
            // 首先调用base的OnClick
            try
            {
                base.OnClick();
            }
            finally
            {
                // new一个RoutedEventArgs
                RoutedEventArgs re = new RoutedEventArgs(MyButton.MyClickEvent, this);
                //    // Raise it.
                base.RaiseEvent(re);
            }
        }//结果与设想的一样 引发Click,执行命令,并且处理MyClick.
    }
}

/Theme/Generic.xaml

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:CommandAndEvent">


  <Style TargetType="{x:Type local:MyButton}">
    <Setter Property="Template">
      <Setter.Value>
        <ControlTemplate TargetType="{x:Type local:MyButton}">
          <Border Background="LightBlue"
                            BorderBrush="Black"
                            BorderThickness="1">
            <ContentPresenter></ContentPresenter>
          </Border>
        </ControlTemplate>
      </Setter.Value>
    </Setter>
  </Style>
</ResourceDictionary>

Command binding

实现命令的邦定,需要有命令源,只有实现了ICommandSouce的控件才能作为命令源,还好ButtonBase已经实现了,这里只要创建自己的RoutedCommand就可以了。与创建RoutedEvent类似:

        private static RoutedUICommand requery;

        static ExampleCommands()
        {
            InputGestureCollection inputs = new InputGestureCollection();
            inputs.Add(new KeyGesture(Key.R, ModifierKeys.Control, "Ctr+R"));
            requery = new RoutedUICommand(
                "Requery text", "Requery name", typeof(ExampleCommands), inputs);
        }

        public static RoutedUICommand Requery
        {
            get { return requery; }
        }

然后就是把他们绑在一起就可以了。 详细见

// MainWindow.xaml

<Window x:Class="CommandAndEvent.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:CommandAndEvent"
        Title="MainWindow" Height="350" Width="525">
  <WrapPanel>
    <Button Click="Button_Click" Command="local:ExampleCommands.Requery">
      Click Me
    </Button>
    <local:MyButton Click="Button_Click" Command="local:ExampleCommands.Requery" MyClick="MyButton_MyClick">My button</local:MyButton>
  </WrapPanel>
  <Window.CommandBindings>
    <CommandBinding Command="local:ExampleCommands.Requery"
                    CanExecute="Requery_CanExecute"
                    Executed="Requery_Executed" />
  </Window.CommandBindings>
</Window>


 


 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值