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();
            }
        }
  • 相关阅读:
    Maven 集成Tomcat插件
    dubbo 序列化 问题 属性值 丢失 ArrayList 解决
    docker 中安装 FastDFS 总结
    docker 从容器中拷文件到宿主机器中
    db2 相关命令
    Webphere WAS 启动
    CKEDITOR 4.6.X 版本 插件 弹出对话框 Dialog中 表格 Table 自定义样式Style 问题
    SpringMVC JSONP JSON支持
    CKEDITOR 3.4.2中 按钮事件中 动态改变图标和title 获取按钮
    git回退到远程某个版本
  • 原文地址:https://www.cnblogs.com/sjqq/p/6636131.html
Copyright © 2011-2022 走看看