您的位置:首页 > 其它

WPF RoutedEvent and Command Sample

2011-08-12 12:10 225 查看
一直对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>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: