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;
 }

 

运行如下:

360软件小助手截图20130728155058

现在,再添加一个按钮用来显示文件,但不希望任何文件都被打开。所以,要在加载的文件上提供某种类型的过滤器。现实现两个命令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();
        }
    }

 

 

 

运行结果:

360软件小助手截图20130728162329

这个例子虽然有点微不足道,不过可以使用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();
        }
    }

 

如果感觉不错的话,请帮忙推荐,谢谢……大笑

目录
相关文章
|
18天前
|
人工智能 Java API
Java与大模型集成实战:构建智能Java应用的新范式
随着大型语言模型(LLM)的API化,将其强大的自然语言处理能力集成到现有Java应用中已成为提升应用智能水平的关键路径。本文旨在为Java开发者提供一份实用的集成指南。我们将深入探讨如何使用Spring Boot 3框架,通过HTTP客户端与OpenAI GPT(或兼容API)进行高效、安全的交互。内容涵盖项目依赖配置、异步非阻塞的API调用、请求与响应的结构化处理、异常管理以及一些面向生产环境的最佳实践,并附带完整的代码示例,助您快速将AI能力融入Java生态。
197 12
|
2月前
|
人工智能 运维 负载均衡
F5发布业界首创集成式应用交付与安全平台,开启ADC 3.0新时代
F5发布业界首创集成式应用交付与安全平台,开启ADC 3.0新时代
69 0
|
2月前
|
人工智能 自然语言处理 分布式计算
AI 驱动传统 Java 应用集成的关键技术与实战应用指南
本文探讨了如何将AI技术与传统Java应用集成,助力企业实现数字化转型。内容涵盖DJL、Deeplearning4j等主流AI框架选择,技术融合方案,模型部署策略,以及智能客服、财务审核、设备诊断等实战应用案例,全面解析Java系统如何通过AI实现智能化升级与效率提升。
230 0
|
4月前
|
机器学习/深度学习 数据采集 存储
朴素贝叶斯处理混合数据类型,基于投票与堆叠集成的系统化方法理论基础与实践应用
本文探讨了朴素贝叶斯算法在处理混合数据类型中的应用,通过投票和堆叠集成方法构建分类框架。实验基于电信客户流失数据集,验证了该方法的有效性。文章详细分析了算法的数学理论基础、条件独立性假设及参数估计方法,并针对二元、类别、多项式和高斯分布特征设计专门化流水线。实验结果表明,集成学习显著提升了分类性能,但也存在特征分类自动化程度低和计算开销大的局限性。作者还探讨了特征工程、深度学习等替代方案,为未来研究提供了方向。(239字)
164 5
朴素贝叶斯处理混合数据类型,基于投票与堆叠集成的系统化方法理论基础与实践应用
|
8月前
|
前端开发 安全 开发工具
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
433 90
【11】flutter进行了聊天页面的开发-增加了即时通讯聊天的整体页面和组件-切换-朋友-陌生人-vip开通详细页面-即时通讯sdk准备-直播sdk准备-即时通讯有无UI集成的区别介绍-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
|
4月前
|
缓存 前端开发 定位技术
通义灵码2.5智能体模式实战———集成高德MCP 10分钟生成周边服务地图应用
通义灵码2.5智能体模式结合高德MCP服务,实现快速构建周边服务地图应用。通过自然语言需求输入,智能体自动分解任务并生成完整代码,涵盖前端界面、API集成与数据处理,10分钟内即可完成传统开发需数小时的工作,大幅提升开发效率。
250 0
|
11月前
|
机器学习/深度学习 Python
堆叠集成策略的原理、实现方法及Python应用。堆叠通过多层模型组合,先用不同基础模型生成预测,再用元学习器整合这些预测,提升模型性能
本文深入探讨了堆叠集成策略的原理、实现方法及Python应用。堆叠通过多层模型组合,先用不同基础模型生成预测,再用元学习器整合这些预测,提升模型性能。文章详细介绍了堆叠的实现步骤,包括数据准备、基础模型训练、新训练集构建及元学习器训练,并讨论了其优缺点。
602 3
|
9月前
|
机器人 应用服务中间件 API
轻松集成私有化部署Dify文本生成型应用
Dify 是一款开源的大语言模型应用开发平台,融合了后端即服务(Backend as Service)和 LLMOps 的理念,使开发者能快速搭建生产级生成式 AI 应用。通过阿里云计算巢,用户可以一键部署 Dify 社区版,享受独享的计算和网络资源,并无代码完成钉钉、企业微信等平台的应用集成。本文将详细介绍如何部署 Dify 并将其集成到钉钉群聊机器人和企业微信中,帮助您轻松实现 AI 应用的定义与数据运营,提升工作效率。
4728 65
轻松集成私有化部署Dify文本生成型应用
|
前端开发 JavaScript UED
探索Python Django中的WebSocket集成:为前后端分离应用添加实时通信功能
通过在Django项目中集成Channels和WebSocket,我们能够为前后端分离的应用添加实时通信功能,实现诸如在线聊天、实时数据更新等交互式场景。这不仅增强了应用的功能性,也提升了用户体验。随着实时Web应用的日益普及,掌握Django Channels和WebSocket的集成将为开发者开启新的可能性,推动Web应用的发展迈向更高层次的实时性和交互性。
266 1
|
Java Maven Docker
gitlab-ci 集成 k3s 部署spring boot 应用
gitlab-ci 集成 k3s 部署spring boot 应用