`

wpf - RoutedCommand use example

    博客分类:
  • WPF
wpf 
阅读更多

It is always useful to have some common stereotype/boilerplate so that you can copy and paste and start something every quickly.

 

 

This is for RoutedCommand stenciles/templates.

 

there are three major steps involves with the RoutedCommand;

 

they are 

 

  1. Declare/Define/Create the routed Command
  2. Set the Command property a Control can raise/trigger, e.g. <Button Command=...>
  3. Add/Remove the handler to the RoutedCommand, through the use CommandBinding

 

 

In the following example, we are going to create Custom RoutedCommand, and we are going to give it  name "OKCommand";

 

The RoutedComand Static Field Approach

 

Since in Xaml the CommandBinding's Command Property is a static field, you could not use a Binding Element on the Command attribute of CommandBindings;

 

So it is recommended to use Static Field for the RoutedCommands;

 

 

    private static RoutedCommand m_okCommand;
    public static RoutedCommand OKCommand
    {
      get
      {
        return m_okCommand != null ? m_okCommand : (m_okCommand = new RoutedCommand("OKCommand", typeof(MainWindow)));
      }
    }
 

 

and you use the x:Static Xaml directive to pick up the ICommand 

 

 

 

        <Button x:Name="OKButton" IsDefault="True" Content="OK" Command="{x:Static local:MainWindow.OKCommand}" CommandTarget="{Binding RelativeSource={RelativeSource Self}}">
            <Button.CommandBindings>
                <CommandBinding
                    Command="{x:Static local:MainWindow.OKCommand}"
                    CanExecute="OKCommandCanExecute"
                    Executed="OKCommandExecuted"
                    >
                    
                </CommandBinding>
            </Button.CommandBindings>
            <Button.InputBindings>
                <KeyBinding Gesture="Alt+O"
                            Command="{x:Static local:MainWindow.OKCommand}">
                    
                </KeyBinding>
            </Button.InputBindings>
        </Button>
 

 

Except setting the command bindings through the use of Xaml, you can also do it via code inside the CLR code. Below is one example.

 

 

 

    public MainWindow()
    {
      InitializeComponent();

      this.CommandBindings.Add(new CommandBinding(
        OKCommand,
        OKCommandExecuted,
        OKCommandCanExecute)
        );

    }
 

 

 

As you can see, this is the most common way of using the RoutedCommand. 

 

 

A slightly better way is to move the RoutedCommand out of the MainWindow and put into a separate class which can be shared by many classes. 

 

 

Following the discussion, we will move the commands to another class called Commands;

 

 

namespace AcceptOrCancelButton
{
  public class Commands : DependencyObject
  {
    private static RoutedCommand m_okCommand;
    public static RoutedCommand OKCommand
    {
      get
      {
        return m_okCommand != null ? m_okCommand : (m_okCommand = new RoutedCommand("OKCommand", typeof(MainWindow)));
      }
    }
  }
}
 

The Dependency Property approach

 

 

DependencyProperty the key is a public static readonly field, the metadata is associated with the owner class as well, but the CLR accessor is associated with the class intance, and this is creating a issue for us iin Xaml.

 

 

Suppose now the Commands class is like this:

 

 

 

namespace AcceptOrCancelButton
{
  public class Commands : DependencyObject
  {
    public RoutedCommand OKCommand
    {
      get { return (RoutedCommand)GetValue(OKCommandProperty); }
      set { SetValue(OKCommandProperty, value); }
    }

    // Using a DependencyProperty as the backing store for OKCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty OKCommandProperty =
        DependencyProperty.Register("OKCommand", typeof(RoutedCommand), typeof(Commands), new UIPropertyMetadata(new RoutedCommand("OKCommand", typeof(Commands))));

  }
}
 

 

In xaml , the following won't work.

 

 

 

<Window x:Class="AcceptOrCancelButton.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:AcceptOrCancelButton"
        x:Name="Self"
        >
    <Window.CommandBindings>
        <CommandBinding
            Command="{Binding Path=OKCommand, ElementName=Self}"
            CanExecute="OKCommandCanExecute"
            Executed="OKCommandExecuted"
            >
        </CommandBinding>
    </Window.CommandBindings>
</Window>
 

 

You will see the following error at runtime. 

 

 

A 'Binding' cannot be set on the 'Command' property of type 'CommandBinding'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.

 

 

 

however, you can still use the code to do the bindings;

 

 

 

namespace AcceptOrCancelButton
{
  public partial class MainWindow : Window
  {


    public MainWindow()
    {
      InitializeComponent();

      this.CommandBindings.Add(new CommandBinding(
        Commands.OKCommand,
        OKCommandExecuted,
        OKCommandCanExecute)
        );
    }

    private Commands m_commands = new Commands();
    public Commands Commands { get { return m_commands; } }
   }
}

 

the UIElement do has the Command as DependencyProperty, so that you can do the following. 

 

 

        <Button x:Name="OKButton" IsDefault="True" Content="OK" Command="{Binding Path=Commands.OKCommand, ElementName=Self}" CommandTarget="{Binding RelativeSource={RelativeSource Self}}">
            <Button.InputBindings>
                <KeyBinding Gesture="Alt+O"
                            Command="{Binding Path=Commands.OKCommand, ElementName=Self}">
                </KeyBinding>
            </Button.InputBindings>
        </Button> 
 

However, if you do want to achieve this in Xaml (if you are paranoid for no reason).

 

the key is the StaticResource

 

 

 

<Window x:Class="AcceptOrCancelButton.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:AcceptOrCancelButton"
        Title="MainWindow" Height="350" Width="525"
        x:Name="Self"
        >
    <Window.Resources>
        <RoutedCommand x:Key="MyCommand" />
        <local:Commands x:Key="Commands" OKCommand="{StaticResource MyCommand}" >
            <!--<local:Commands.OKCommand>
                <StaticResource ResourceKey="MyCommand"></StaticResource>
            </local:Commands.OKCommand>-->
        </local:Commands>
    </Window.Resources>
<StackPanel>
        <!-- With the help of Click Event, prove cancel and default button works -->
        <!--<Button x:Name="OKButton" IsDefault="True" Content="OK" Click="OkClick"/>
        <Button x:Name="CancelButton" IsCancel="True" Content="Cancel" Click="CancelClick"/>-->

        <!-- With the help of Static Routed Comand, prove cancel and default button works -->
        <Button x:Name="OKButton" IsDefault="True" Content="OK" Command="{StaticResource MyCommand}" CommandTarget="{Binding RelativeSource={RelativeSource Self}}">
            <Button.CommandBindings>
                <CommandBinding
                    Command="{StaticResource MyCommand}"
                    CanExecute="OKCommandCanExecute"
                    Executed="OKCommandExecuted"
                    >
                </CommandBinding>
            </Button.CommandBindings>
            <Button.InputBindings>
                <KeyBinding Gesture="Alt+O"
                            Command="{StaticResource MyCommand}">
                </KeyBinding>
            </Button.InputBindings>
        </Button> 
  </StackPanel>
</Window>

 

 

You can only use StaticResource, you cannot use DynamicResource, because DynamicResource requires that the target property is a DependencyProperty;

 

 

Tricks to use AttachedDependencyProperty

You can create a Attached Dependency Property,which indicate if the element that the attached property is applied will be bound to a known RoutedCommand (in this example), the known RoutedCommand is the defined in the Resources.  

 

here is the code.

 

 

    public static bool GetIsOKCommandSource(DependencyObject obj)
    {
      return (bool)obj.GetValue(IsOKCommandSourceProperty);
    }

    public static void SetIsOKCommandSource(DependencyObject obj, bool value)
    {
      obj.SetValue(IsOKCommandSourceProperty, value);
    }

    // Using a DependencyProperty as the backing store for IsOKCommandSource.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty IsOKCommandSourceProperty =
        DependencyProperty.RegisterAttached("IsOKCommandSource", typeof(bool), typeof(MainWindow), new UIPropertyMetadata(false, OnIsOkCommandSourceChanged));

    public static void OnIsOkCommandSourceChanged(DependencyObject dep, DependencyPropertyChangedEventArgs e)
    {
      if ((bool)e.NewValue == true)
      {
        //Button button = dep as Button;
        Button button = dep as Button;
        if (button != null)
        {
          var command = ((Commands)button.TryFindResource("Commands")).OKCommand;
          button.Command = command;
          button.CommandTarget = button;
        }
      }
    }
 

 

and you have the following xaml which basically create the resource, create the Command handlers, and use the attach dependency property.

 

 

<Window x:Class="AcceptOrCancelButton.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:AcceptOrCancelButton"
        Title="MainWindow" Height="350" Width="525"
        x:Name="Self"
        >
    <Window.Resources>
        <RoutedCommand x:Key="MyCommand" />
        <local:Commands x:Key="Commands" OKCommand="{StaticResource MyCommand}" >
        </local:Commands>
    </Window.Resources>
    <Window.CommandBindings>
        <CommandBinding
            Command="{StaticResource MyCommand}"
            CanExecute="OKCommandCanExecute"
            Executed="OKCommandExecuted"
            >
        </CommandBinding>
    </Window.CommandBindings>
    <StackPanel>
        <Button x:Name="OKButton" local:MainWindow.IsOKCommandSource="True"  IsDefault="True" Content="OK">
        </Button>

    </StackPanel>
</Window>

 

 

Another way to use the Attached Dependency Property is as follow. -- this is not IDEAL, tend to remove 

 

 

 

    public static RoutedCommand GetOkCommand(DependencyObject obj)
    {
      return (RoutedCommand)obj.GetValue(OkCommandProperty);
    }

    public static void SetOkCommand(DependencyObject obj, RoutedCommand value)
    {
      obj.SetValue(OkCommandProperty, value);
    }

    // Using a DependencyProperty as the backing store for OkCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty OkCommandProperty =
        DependencyProperty.RegisterAttached("OkCommand", typeof(RoutedCommand), typeof(MainWindow), new UIPropertyMetadata(null, OnOKCommandChanged));

    public static void OnOKCommandChanged(DependencyObject dep, DependencyPropertyChangedEventArgs e)
    {
      if (e.NewValue != null)
      {
        if (dep is ICommandSource)
        {
          var parent = GetParent(dep, typeof(MainWindow)) as MainWindow;

          if (dep.GetType() == typeof(Button))
          {
            Button button = (Button)dep;
            button.Command = (RoutedCommand)e.NewValue;
            button.CommandTarget = button;
            button.CommandBindings.Add(new CommandBinding(button.Command, parent.OKCommandExecuted, parent.OKCommandCanExecute));
          }
        }
      }
    }    public static DependencyObject GetParent(DependencyObject obj, Type parentType)
    {
      DependencyObject parent = obj ;
      if (obj == null) return null;

      Type type = obj.GetType();
      while (type != parentType)
      {
        parent = LogicalTreeHelper.GetParent(parent);
        if (parent != null) type = parent.GetType();
        else return null;
      }

      return parent;
    }
 

 

 

 

and the xaml

 

 

 

 

<Window x:Class="AcceptOrCancelButton.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:AcceptOrCancelButton"
        Title="MainWindow" Height="350" Width="525"
        x:Name="Self"
        >
    <Window.Resources>
        <RoutedCommand x:Key="MyCommand" />
        <local:Commands x:Key="Commands" OKCommand="{StaticResource MyCommand}" >
        </local:Commands>
    </Window.Resources>
    <StackPanel>
      <Button x:Name="OKButton" local:MainWindow.OkCommand="{Binding Source={StaticResource MyCommand}}" IsDefault="True" Content="OK" />

    </StackPanel>
</Window>
 

 

The last attached event I am thinking of is of type CommandBinding; Please see below. 

 

 

 

    public static CommandBinding GetOKCommandBinding(DependencyObject obj)
    {
      return (CommandBinding)obj.GetValue(OKCommandBindingProperty);
    }

    public static void SetOKCommandBinding(DependencyObject obj, CommandBinding value)
    {
      obj.SetValue(OKCommandBindingProperty, value);
    }

    // Using a DependencyProperty as the backing store for OKCommandBinding.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty OKCommandBindingProperty =
        DependencyProperty.RegisterAttached("OKCommandBinding", typeof(CommandBinding), typeof(MainWindow), new UIPropertyMetadata(null, OnOKCommandBindingChanged));

    public static void OnOKCommandBindingChanged(DependencyObject dep, DependencyPropertyChangedEventArgs e)
    {
      if (e.NewValue != null)
      {
        if (dep.GetType() == typeof(Button))
        {
          var button = (Button)dep;
          button.CommandBindings.Clear();
          button.CommandBindings.Add((CommandBinding)e.NewValue);
        }
        
      }
    }

 

 

and the Xaml

 

 

 

<Window x:Class="AcceptOrCancelButton.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:AcceptOrCancelButton"
        Title="MainWindow" Height="350" Width="525"
        x:Name="Self"
        >
    <Window.Resources>
        <RoutedCommand x:Key="MyCommand" />
        <local:Commands x:Key="Commands" OKCommand="{StaticResource MyCommand}" >
        </local:Commands>
        <CommandBinding x:Key="OKCommandBinding" 
                       Command="{StaticResource MyCommand}"
                        Executed="OKCommandExecuted"
                        CanExecute="OKCommandCanExecute"
                        >
        </CommandBinding>
    </Window.Resources>


   <StackPanel>
        <Button x:Name="OKButton" local:MainWindow.OKCommandBinding="{StaticResource OKCommandBinding}" Command="{StaticResource MyCommand}" IsDefault="True" Content="OK" />

    </StackPanel>
</Window>
 

 

分享到:
评论

相关推荐

    gong-wpf-dragdrop, GongSolutions.WPF.DragDrop 库是WPF的拖动'n'拖放框架.zip

    gong-wpf-dragdrop, GongSolutions.WPF.DragDrop 库是WPF的拖动'n'拖放框架 简介GongSolutions.WPF.DragDrop 库是一个易于使用的拖拉'n'拖放框架。特性使用 MVVM: 拖放逻辑可以放在ViewModel中。 代码不需要放在in中...

    通用WPF主题控件包rubyer-wpf-master

    通用WPF主题控件包rubyer-wpf-master是一款专为Windows Presentation Foundation (WPF) 应用程序设计的开源UI框架。它提供了丰富的主题和控件,旨在帮助开发者快速构建美观且用户友好的应用程序界面。在2.0.0版本中...

    wpf-mvvm-DeskTop-Sample-master_C#_WPF_wpf客户端zfs_

    标题中的“wpf-mvvm-DeskTop-Sample-master”表明这是一个关于WPF(Windows Presentation Foundation)桌面应用程序的示例项目,使用了MVVM(Model-View-ViewModel)设计模式。这个项目是用C#编程语言编写的,面向的...

    WPF-Blockly-master.zip

    **WPF-Blockly** 是一个基于Windows Presentation Foundation (WPF) 的图形化编程工具,它为用户提供了构建和设计程序的直观界面。WPF作为Microsoft .NET Framework的一部分,主要用于构建桌面应用程序,它提供了...

    C#开发WPF-Silverlight动画及游戏系列教程-深蓝色右手 4

    C#开发WPF-Silverlight动画及游戏系列教程-深蓝色右手 C#开发WPF-Silverlight动画及游戏系列教程-深蓝色右手 C#开发WPF-Silverlight动画及游戏系列教程-深蓝色右手

    WPF-ControlBase-master.zip

    在这个名为"WPF-ControlBase-master.zip"的压缩包中,我们可以推测它包含了一个基于WPF的控制库项目,可能是一个开源或者个人开发的项目,用于提供自定义的WPF控件。这些控件可能是对标准WPF控件的扩展或增强,也...

    WPF-Samples-master_WPF基本sample_

    WPF的基本空间历程,使用.net core3.0.1版本

    基于WPF的图形化编程控件和环境WPF-Blockly-master

    【标题】"基于WPF的图形化编程控件和环境WPF-Blockly-master" 提供了一个创新的编程体验,它将传统的代码编写转变为图形化的流程图形式,使得编程变得更加直观和易于理解。WPF(Windows Presentation Foundation)是...

    bootstrap-wpf-style-master 样式

    Bootstrap-WPF 样式是一种将流行的前端框架 Bootstrap 的设计风格应用于 WPF(Windows Presentation Foundation)应用程序的方法。Bootstrap 是一个广泛使用的开源工具包,主要用于构建响应式、移动设备优先的网页...

    WPF-JJDown-v1.234.0

    【标题】"WPF-JJDown-v1.234.0" 提示我们这是一个基于Windows Presentation Foundation(WPF)的应用程序,名为JJDown。版本号v1.234.0表明这是该软件的第1次重大更新,第234次次要更新或修复。这通常意味着它经历了...

    WPF-Diagram-Designer:WPF图表设计器源代码

    通过深入研究WPF-Diagram-Designer的源代码(如WPF-Diagram-Designer-master文件夹中的内容),开发者不仅可以学习到如何在WPF中构建复杂的图形界面,还可以了解到图形编辑器的设计原理和实现细节,对于提升图形应用...

    AI-wpf-controls一个Wpf控件库

    在本文中,我们将深入探讨"AI-wpf-controls",这是一个专为Windows Presentation Foundation(WPF)框架设计的控件库。这个独特的库整合了多个知名控件库的优点,包括MahApps.Metro、Material-Design、HandyControl...

    WPF-MaterialDesign-master.zip_WPF_WPF非常好的界面_包括多种漂亮的皮肤_漂亮的控件_配色

    在本项目"WPF-MaterialDesign-master.zip"中,重点在于利用**Material Design**这一设计语言来增强WPF应用的视觉效果。Material Design是Google推出的一种设计规范,其灵感来源于现实世界中的纸张和墨水,强调层次感...

    Wpf-glTF-testing.zip

    在“Wpf-glTF-testing.zip”压缩包中,我们有一个基于WPF(Windows Presentation Foundation)的简化glTF文件查看器项目。 WPF是.NET Framework的一部分,是一个用于构建Windows桌面应用程序的框架。它提供了丰富的...

    WPF-强大的图表.zip

    **WPF - 强大的图表技术** Windows Presentation Foundation (WPF) 是Microsoft开发的一个用于构建桌面应用程序的框架,它提供了丰富的图形系统,包括对2D和3D图形的强大支持。在WPF中,开发人员可以利用各种图表...

    Wpf的Diagram画板aistudio-wpf-diagram-master

    【标题】"Wpf的Diagram画板aistudio-wpf-diagram-master" 是一个基于WPF(Windows Presentation Foundation)技术的图形设计工具,用于创建和编辑图表或流程图。这个项目是在原有的WPF-Diagram-Designer基础上进行的...

    OpenControls.Wpf-master

    《OpenControls.Wpf-master:深度探索WPF框架控件》 在Windows Presentation Foundation(WPF)的世界里,开发者们能够创建出美观且功能丰富的桌面应用程序。OpenControls.Wpf-master项目,正如其名,是一个专注于...

    wpf---StatusBar

    “wpf---StatusBar”这个标题表明我们将探讨的是WPF(Windows Presentation Foundation)框架中的StatusBar组件。WPF是.NET Framework的一部分,用于构建桌面应用程序,它提供了丰富的用户界面(UI)功能。StatusBar...

    wpf-datagrid-access DB

    在这个“wpf-datagrid-access DB”主题中,我们将深入探讨如何利用WPF Datagrid与Microsoft Access数据库进行交互,实现数据的读取、更新和保存。 1. **WPF Datagrid简介** - Datagrid是WPF中的一个数据展示控件,...

    C#开发WPF-Silverlight动画及游戏系列教程-深蓝色右手1

    C#开发WPF-Silverlight动画及游戏系列教程-深蓝色右手 C#开发WPF-Silverlight动画及游戏系列教程-深蓝色右手 C#开发WPF-Silverlight动画及游戏系列教程-深蓝色右手

Global site tag (gtag.js) - Google Analytics