文章出處

要開始使用命令,必須做三件事:

                                              一:定義一個命令

                                              二:定義命令的實現

                                              三:為命令創建一個觸發器

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

 

如果感覺不錯的話,請幫忙推薦,謝謝……大笑


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()