码迷,mamicode.com
首页 > Windows程序 > 详细

WPF命令绑定 自定义命令

时间:2015-04-04 06:53:00      阅读:179      评论:0      收藏:0      [点我收藏+]

标签:

WPF的命令系统是wpf中新增加的内容,在以往的winfom中并没有。为什么要增加命令这一块内容。在winform里面的没有命令只使用事件的话也可以实现程序员希望实现的功能。这个问题在很多文章中都提到了。但大家都是引用深入浅出wpf里面的概述。没有用自己的话来阐述。当然你仔细理解一下的话也很容易理解。但在这里我还是用我自己的话来说一下什么情况下使用命令。


命令具有约束力


事件的作用是发布、传播一些消息,消息传达到了接收者,事件的指令也就算完成了,至于如何响应事件送来的消息事件并不做任何限制,每个接收者可已用自己的行为来响应事件。也就是说,事件不具有约束力。命令和事件的区别就在于命令具有约束力。


事件是一种很自由散漫的调用。就像我们平时的自由职业者一样,不受约束,想做什么就做什么。仔细运用的话虽然可以什么功能都实现,但是总是有些凌乱。但是命令不同,命令具有约束力,也就是上班族一样。有一个制度来约束你。必须按照流程来实现功能。所说这样做略显麻烦,但是对于一些复杂特定的情况却能够避免程序员出错。


比如保存事件的处理器,程序员可以写Save()、SaveHandle()、SaveDocument()... 这些都符合代码规范。但迟早有一天整个项目会变的让人无法读懂,新来的程序员或修改bug的程序员会很抓狂。如果使用命令,情况就会好很多----当Save命令到达某个组件的时候,命令会自动去调用组件的Save方法。而这个方法可能定义在基类或者接口里(即保证了这个方法是一定存在的),这就在代码结构和命名上做了约束。


这里所谓的约束力就是指命令系统的几大要素  造句大全 www.zaojuzi.com )


命令(Command):WPF的命令实际上就是实现了ICommand接口的类,平时使用最多的就是RoutedCommand类。我们还会学习使用自定义命令。
命令源(Command Source):即命令的发送者,是实现了ICommandSource接口的类。很多界面元素都实现了这个接口,其中包括Button,ListBoxItem,MenuItem等。
命令目标(Command Target):即命令发送给谁,或者说命令作用在谁的身上。命令目标必须是实现了IInputElement接口的类。
命令关联(Command Binding):负责把一些外围逻辑和命令关联起来,比如执行之前对命令是否可以执行进行判断、命令执行之后还有哪些后续工作等。
要想使用命令,就必须要实现这几大要素。而程序员如果实现了这几大要素,那么程序的逻辑就很明了。也就是让程序员想犯错都难。


命令最常见的使用情况是例如工具栏里面绑定命令,右键命令,菜单绑定命令,保存,撤销,打开文件夹等情境。


命令实现例1


命令的实现可以自定义命令,但对于一些简单的情况我们可以使用wpf内置的已经实现了ICommand接口的RoutedCommand或者RoutedUICommand


注意RoutedUICommand只是比RoutedCommand多了一个说明性的文本参数。


xaml


复制代码
<Window x:Class="WpfApplication1.Window28"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window28" Height="300" Width="300" WindowStyle="ToolWindow">
    <StackPanel Background="LightBlue" x:Name="sp1">
        <Button Content="Send Command" x:Name="btn1" Margin="5"></Button>
        <TextBox x:Name="txtA" Margin="5,0" Height="200"></TextBox>
    </StackPanel>
</Window>
复制代码
后台cs


 View Code
上面这个例子代码写的比较详细,简单些我们也可以这样写


复制代码
<Window x:Class="WpfApplication1.Window65"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1"
        Title="Window64" Height="159" Width="461">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="100" />
        </Grid.RowDefinitions>
        <Menu>
            <MenuItem Header="文件">
                <MenuItem Header="打开文件" Command="{x:Static Member=local:Commands.NewProject}"></MenuItem>
                <MenuItem Header="另存为"></MenuItem>
                <MenuItem Header="关闭文件"></MenuItem>
            </MenuItem>
        </Menu>
    </Grid>
</Window>
复制代码
 View Code
自定义命令(深入浅出wpf原版例30)


关于自定义命令,园子里大多文章都是取自深入浅出理解wpf里面的例子。我们也从这个例子开始分析,然后一点一点把这个例子改为我们自己掌握的例子。


xaml窗体


 View Code
 View Code
 


命令源:


 View Code
 View Code
 


命令目标:


 View Code
 View Code
自定义命令:


 View Code
定义的接口


 View Code
原版命令改


原例子中首先对于命令源。:即命令的发送者,是实现了ICommandSource接口的类。很多界面元素都实现了这个接口,其中包括Button,ListBoxItem,MenuItem等。因为wpf中大部分控件都已经实现了这个接口,所以我们可以把例子弄简单些,暂时不用实现自定义的MyCommandSource


我们把我们主窗体中的xaml修改成下面这样


复制代码
<Window x:Class="WpfApplication1.Window30"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window30" Height="300" Width="300" xmlns:my="clr-namespace:WpfApplication1">
    <StackPanel>
        <!--<my:MyCommandSource x:Name="myCommandSource1">
            <TextBlock Text="清除" Width="80" FontSize="16" TextAlignment="Center" Background="LightGreen"></TextBlock>
        </my:MyCommandSource>-->
        <Button Name="myCommandSource1">
            <TextBlock Text="清除" Width="80" FontSize="16" TextAlignment="Center" Background="LightGreen"></TextBlock>
        </Button>
        <my:MniView x:Name="mniView1" />
    </StackPanel>
</Window>
复制代码
用一个button来作为命令源。调试程序,会报错如下










在原版代码里面是没有return true 的,所以在给空间绑定命令的时候会报错。这说明当给wpf自带的控件作为命令源绑定时会初始化执行CanExecute,而在我们自己实现的命令源MyCommandSource并没有实现这一逻辑。也就是当我们初始化命令绑定的时候并没有去执行CanExecute这个方法。当然在这个例子中这无关紧要,但当我们自定义控件的时候最好实现这一逻辑,所以在初始化时候可以首先检查命令是否可以执行。我们现在先把canExecute  return true;继续我们的改造。






此时我们点击清除,会发现命令并没有被执行。检查代码我们会发现 public void Execute(object parameter)方法的parameter为null.






 我们看一下原版中当我们左击的时候,源命令源执行了上面这个方法。此时感觉有些奇怪。CommandTarget命令目标是这样使用的么?


我们查看一下msdn,解释如下。


在 Windows Presentation Foundation (WPF) 命令系统中,仅当 ICommand 为 RoutedCommand 时,ICommandSource 上的 CommandTarget 属性才适用。 如果 CommandTarget 是在 ICommandSource 上设置的,并且对应的命令不是 RoutedCommand,则会忽略该命令目标。


命令目标是只针对RoutedCommand实现的。我们看一下我们最开始的例子,该例使用了wpf内置的 RoutedCommand 命令。


 private void ExecuteNewProject(object sender, ExecutedRoutedEventArgs e)
与该命令绑定的方法实现有两个参数,其中sender 就是指的我们的CommandTarget


与 RoutedCommand 一起使用时,命令目标为引发 Executed 和 CanExecute 事件的对象。 如果未设置 CommandTarget 属性,则会将具有键盘焦点的元素用作目标。


所以原版demo中命令目标的使用有些不恰当。此时我们可以将主窗体的代码改为如下。向目标源传递参数


this.myCommandSource1.CommandParameter = mniView1;此时我们发现命令被正确执行。


复制代码
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.Shapes;
using WpfApplication1.Command;


namespace WpfApplication1
{
    /// <summary>
    /// Window30.xaml 的交互逻辑
    /// </summary>
    public partial class Window30 : Window
    {
        public Window30()
        {
            InitializeComponent();
            ClearCommand clearCommand = new ClearCommand();
            this.myCommandSource1.Command = clearCommand;
            this.myCommandSource1.CommandParameter = mniView1;
            //this.myCommandSource1.CommandTarget = mniView1;
        }
    }
}
复制代码
通过这个例子的改造我们发现,很多情况下我们如果不需要实现自定义控件是不需要自定义命令源的,而命令目标很多情况下也不需要。我们只需要向命令绑定传递参数就可以实现很多的应用。


通过构造函数传递参数


另外我们也可以重新命令的构造函数来实现参数的传递。改造后代码如下。


复制代码
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.Shapes;
using WpfApplication1.Command;


namespace WpfApplication1
{
    /// <summary>
    /// Window30.xaml 的交互逻辑
    /// </summary>
    public partial class Window30 : Window
    {
        public Window30()
        {
            InitializeComponent();
            ClearCommand clearCommand = new ClearCommand(mniView1);
            this.myCommandSource1.Command = clearCommand;
            //this.myCommandSource1.CommandParameter = mniView1;
            //this.myCommandSource1.CommandTarget = mniView1;
        }
    }
}
复制代码
复制代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using WpfApplication1.InterFace;


namespace WpfApplication1.Command
{
    /// <summary>
    ///自定义命令
    /// </summary>
    public class ClearCommand : ICommand
    {
        IView _view;
        public ClearCommand(IView view)
        {
            this._view = view;
        }
        //用来判断命令是否可以执行
        public bool CanExecute(object parameter)
        {
            return true;
            throw new NotImplementedException();
        }
        //当命令可执行状态发送改变时,应当被激发
        public event EventHandler CanExecuteChanged;


        //命令执行时,带有与业务相关的Clear逻辑
        public void Execute(object parameter)
        {
            //IView view = parameter as IView;
            IView view = _view as IView;
            if (view != null)
            {
                view.Clear();


本文章由   造句大全 www.zaojuzi.com  整理发布






WPF命令绑定 自定义命令

标签:

原文地址:http://blog.csdn.net/doulyun/article/details/44866419

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!