zoukankan      html  css  js  c++  java
  • WPF命令(Command)介绍、命令和数据绑定集成应用

    要开始使用命令,必须做三件事:

                                                  一:定义一个命令

                                                  二:定义命令的实现

                                                  三:为命令创建一个触发器

     WPF中命令系统的基础是一个相对简单的ICommand的接口,代码如下:

    public interface ICommand 
    { event EventHandler CanExecuteChanged; bool CanExecute(object parameter); void Execute(object parameter); }

     CanExecute用于确定命令是否处于可执行的状态。典型的,UI控件能使用CanExecute来启用或禁用自己。也就是说,在相关的命令从CanExecute中返回False的时候,按钮将变得不可用。

          Execute是命令的关键,当被调用时,它将触发命令的执行。

          要定义一个新命令,可以实现ICommand接口。如希望ICommand在被调用后关闭应用程序,代码如下:

    public class Exit : ICommand {
     event EventHandler CanExecuteChanged;
     public bool CanExecute(object parameter) 
    {
     return true; 
    } 
    public void Execute(object parameter)
     { 
    Application.Current.Shutdown(); 
    } 
    }
    要把一个菜单项绑定到应用程序关闭这个命令上,可以把他们的Command属性挂到Exit命令上,代码如下:
    <MenuItem Header="_File">
     <MenuItem Header="_Exit">
     <MenuItem.Command>
     <local:Exit/> 
    </MenuItem.Command>
     </MenuItem> 
    </MenuItem>
    由于把命令用于多个位置比较常见,所以创建一个存储命令的静态字段也常见:
    public static readonly ICommand ExitCommand = new Exit();
    这样做的好处是,通过这个类型为ICommand的字段,可以让Exit命令的实现完全私有化。现在,可以把Exit标记为私有类,并把标记转化为绑定到静态字段,代码如下:
     <MenuItem Header="_File">
                <MenuItem Header="_Exit" Command="{x:Static local:WinCommand.ExitCommand}"/>
            </MenuItem>
    下面我们通过添加一个和Close命令挂接的按钮,可以为窗口编写一个模板,以实现关闭窗口的功能,代码如下:
     <Window.Style>
            <Style TargetType="Window">
    
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate  TargetType="Window">
                            <DockPanel>
                                <StatusBar DockPanel.Dock="Bottom">
                                    <StatusBarItem>
                                        <Button 
                                Command="{x:Static ApplicationCommands.Close}">Close</Button>
                                    </StatusBarItem>
                                </StatusBar>
                                <ContentPresenter/>
                            </DockPanel>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Window.Style>
    我们接着要通过把命令绑定添加到窗口中让窗口关闭。
    /// <summary>
        /// WinCommand.xaml 的交互逻辑
        /// </summary>
        public partial class WinCommand : Window
        {
            public static readonly ICommand ExitCommand = new Exit();
            public WinCommand()
            {
                InitializeComponent();
    
                CommandBindings.Add(
                    new CommandBinding(
                        ApplicationCommands.Close,
                        CloseExecuted));
    
            }
    
            void CloseExecuted(object sender, ExecutedRoutedEventArgs e)
            {
                this.Close();
            }
          
        }

    使用命令可以清晰地把显示和行为分开。通过使用单一的名称为所需的语义动作签名,在尝试把多个控件和单个事件处理过程挂接起来的时候,可以避免很多由此引发的紧耦合问题。通常,应用程序逻辑应该总是通过命令的方式来实现的,而不是事件处理程序。对于很多需要直接挂接到事件处理过程上的常见例子,用触发器来处理更好。

    命令与数据绑定

              使用命令的一个令人振奋和强大的特性 就是和数据绑定集成。由于Command和CommandParameter都是元素上的属性,所以他们都能被设置为一些绑定到他们的数据。因此,可以使用绑定的数据内容来确定应该发生的动作。

          为了演示他们是如何融合到一起的,将以C:下面的文件的应用程序来开头。首先,定义一个显示内容的ListBox,和一个显示了每个文件名的数据模板,代码如下:

    <ListBox Margin="2" Name="lbFile">

    <ListBox.ItemTemplate>

    <DataTemplate>

    <TextBlock Text="{Binding Path=Name}"/>

    </DataTemplate>

    </ListBox.ItemTemplate>

    </ListBox>

     

    在后台,把ItemSource属性设置为文件列表:

    public WinCommandAndBinding() 
    {
     InitializeComponent();
    
     FileInfo[] fileList = new DirectoryInfo("C:\").GetFiles("*.*");
     
    lbFile.ItemsSource = fileList;
     }

    现在,再添加一个按钮用来显示文件,但不希望任何文件都被打开。所以,要在加载的文件上提供某种类型的过滤器。现实现两个命令Open和Blocked并为他们提供某种类型的处理过程,代码如下:
    public static readonly RoutedCommand OpenCommand =
                new RoutedCommand("Open", typeof(WinCommandAndBinding));
    
            public static readonly RoutedCommand BlockedCommand =
                new RoutedCommand("Blocked", typeof(WinCommandAndBinding));
    
            public WinCommandAndBinding()
            {
                InitializeComponent();
    
                CommandBindings.Add(new CommandBinding (OpenCommand,
                    delegate(object sender,ExecutedRoutedEventArgs e){
                        Process.Start("notepad.exe",(string)e.Parameter);}));
    
                CommandBindings.Add(new CommandBinding(BlockedCommand,
                    delegate(object sender, ExecutedRoutedEventArgs e)
                    {
                        MessageBox.Show((string)e.Parameter, "Blocked");
                    }));
    
    
                FileInfo[] fileList = new DirectoryInfo("C:\").GetFiles("*.*");
                lbFile.ItemsSource = fileList;
            }
        }
    在定义好两个命令后,就可以更新文件的数据模板来包含按钮了。在命令参数(文件名)中使用数据绑定。对应命令本身,由于希望某些条目用OpenCommand,而其他条目用BlockedCommand,所以将使用IValueConvert把文件名转换为ICommand,代码如下:
    <ListBox Margin="2" Name="lbFile">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <WrapPanel>
                            <TextBlock Text="{Binding Path=Name}"/>
                            <Button Margin="5" CommandParameter="{Binding Path=FullName}">
                                <Button.Command>
                                    <Binding>
                                        <Binding.Converter>
                                            <local:FileToCommandConverter/>
                                        </Binding.Converter>
                                    </Binding>
                                </Button.Command> Show
                            </Button>
                        </WrapPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
    下面是转换器:
     public class FileToCommandConverter : IValueConverter
        {
            public object Convert(object value ,Type targetType,object parameter,CultureInfo culture)
            {
                string ext = ((FileInfo)value).Extension.ToLowerInvariant();
                if (ext == ".txt")
                    return WinCommandAndBinding.OpenCommand;
                else
                    return WinCommandAndBinding.BlockedCommand;
            }
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    运行结果:
    
    

    这个例子虽然有点微不足道,不过可以使用CanExecute方法轻松地完成类似的行为,并针对“坏”文件禁用这个命令。然而,这里最重要的一点是,可以返回任何命令。可以使用任何基于数据的逻辑来确定任何元素的行为。

    另外我们可以考虑下能不能用数据触发器实现呢?呵呵,可以的,这等于把命令、数据绑定和触发器三者融合到一起了?是不是很强大,呵呵下面是代码:

     <ListBox Margin="2" Name="lbFile2">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <WrapPanel>
                            <TextBlock Text="{Binding Path=Name}"/>
                            <Button x:Name="btnShow" Margin="5" CommandParameter="{Binding Path=FullName}" 
                                    Command="{x:Static local:WinCommandAndBinding.BlockedCommand}"
                                    Content="  Block"/>
                        </WrapPanel>
                        <DataTemplate.Triggers>
                            <DataTrigger  Value=".txt">
                                <DataTrigger.Binding>
                                    <Binding  Path='Extension'>
                                        <Binding.Converter>
                                            <local:ToLowerInvariantConvert/>
                                        </Binding.Converter>
                                    </Binding>
                                </DataTrigger.Binding>
                                <Setter TargetName="btnShow"
                                Property="Command"
                                    Value="{x:Static local:WinCommandAndBinding.OpenCommand}"/>
                                <Setter TargetName="btnShow" Property="Content" Value="Show"/>
                            </DataTrigger>
                        </DataTemplate.Triggers>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
    转换器:
        public class ToLowerInvariantConvert : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
              return  ((string)value).ToLowerInvariant();
               
            }
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
  • 相关阅读:
    在项目开始前,为客户做专门的“需求变更流程”培训是必要的
    代码优化四部曲:“拆套”、“解耦”、”封装“、“重构”
    这个博客的目的就是解构程序猿的世界观
    如果3D技术仅仅只是用于游戏和娱乐,那真是太暴殄天物了
    如何用Xcode 4.5开发3.5寸屏幕的iPhone 应用程序?
    所谓开发经验,其实就是对业务流程的积累
    项目经理必备的两大能力
    XML文件总是无法读取其中的数据
    在switch的case语句后,使用UIAlertView报错
    代码编写原则
  • 原文地址:https://www.cnblogs.com/sjqq/p/6636131.html
Copyright © 2011-2022 走看看