久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

【W(wǎng)PF學(xué)習(xí)】第三十二章 執(zhí)行命令

 怡紅公子0526 2020-04-19

  前面章節(jié)已經(jīng)對命令進行了深入分析,,分析了基類和接口以及WPF提供的命令庫。但尚未例舉任何使用這些命令的例子,。

  如前所述,,RoutedUICommand類沒有任何硬編碼的功能,而是只表達(dá)命令,,為觸發(fā)命令,,需要有命令源(也可使用代碼)。為響應(yīng)命令,,需要有命令綁定,,命令綁定將執(zhí)行轉(zhuǎn)發(fā)給普遍的事件處理程序。

一,、命令源

  命令庫中的命令始終可用,。觸發(fā)他們的最簡單的方法是將它們關(guān)聯(lián)到實現(xiàn)了ICommandSource接口的控件,,其中包括繼承自ButtonBase類的控件(Button和CheckBox等)、單獨的ListBoxItem對象,、HyperLink以及MenuItem,。

  ICommandSource接口定義了三個屬性,,如下表所示。

表 ICommandSource接口的屬性

 

   例如,,下面的按鈕使用Command屬性連接到ApplicationCommands.New命令:

 <Button Command="ApplicationCommands.New">New</Button>

  WPF的智能程度足夠高,,它能查找前面介紹的所有5個命令容器類,,這意味著可使用下面的縮寫的形式:

 <Button Command="New">New</Button>

  然而,由于沒有指明包含命令的類,,這種語法不夠明確,、不夠清晰。

二,、命令綁定

  當(dāng)將命令關(guān)聯(lián)到命令源時,,會看到一些有趣的現(xiàn)象。命令源將會被自動禁用,。

  例如,,如果創(chuàng)建上一節(jié)提到的New按鈕,該按鈕的顏色就會變淺并且不能被單擊,,就像將IsEnabled屬性設(shè)置為false那樣(如下圖所示),。這是因為按鈕已經(jīng)查詢了命令的狀態(tài),而且由于命令還沒有與其關(guān)聯(lián)的綁定,,所以按鈕被認(rèn)為是禁用的,。

 

 

   為改變這種狀態(tài),需要為命令創(chuàng)建綁定以明確以下三件事:

  當(dāng)命令被觸發(fā)時執(zhí)行什么操作,。

  如何確定命令是否能夠被執(zhí)行(這是可選的,。如果未提供這一細(xì)節(jié),只要提供了關(guān)聯(lián)的事件處理程序,,命令總是可用),。

  命令在何處起作用。例如,,命令可被限制在單個按鈕中使用,,或在整個窗口中使用(這種情況更常見)。

  下面的代碼片段為New命令創(chuàng)建綁定,??蓪⑦@些代碼添加到窗口的構(gòu)造函數(shù)中:

//Create the binding
CommandBinding binding=new CommandBinding(ApplicationCommands.New);

//Attach the event handler
binding.Executed+=NewCommand_Executed;

//Register the binding
this.CommandBinding.Add(binding);

  注意,上面創(chuàng)建的CommandBinding對象唄添加到包含窗口的CommandBindings集合中,,這通過事件冒泡進行工作,。實際上,當(dāng)單擊按鈕時,,CommandBinding.Executed事件從按鈕冒泡到包含元素,。

  盡管習(xí)慣上為窗口添加所有綁定,但CommandBindings屬性實際是在UIElement基類中定義的,。這意味著任何元素都支持該屬性,。例如,如果將命令綁定直接添加到使用它的按鈕中,,這個示例仍工作的很好(盡管不能在將該綁定重用與其他高級元素),。為得到最大的靈活性,,命令綁定通常被添加到頂級窗口。如果希望在多個窗口中使用相同相同的命令,,需要在這些窗口中分別創(chuàng)建命令綁定,。

  上面的代碼假定在同一個類中已有名為NewCommand_Executed的事件處理程序,該處理程序已經(jīng)準(zhǔn)備好接收命令,。下面是一個示例,,該例包含一些顯示命令源的簡單代碼:

private void NewCommand_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("New command triggered by " + e.Source.ToString());
        }

  現(xiàn)在,如果允許應(yīng)用成功需,,按鈕處于啟用狀態(tài),。如果單擊按鈕,就會觸發(fā)Executed事件,,該事件冒泡至窗口,,并被上面給出的NewCommand_Executed()事件處理程序程序處理。這是,,WPF會告知事件源(按鈕),。通過ExecutedRoutedEventArgs對象還可獲得被調(diào)用的命令的引用(ExecutedRoutedEventArgs.Command),以及所有同時傳遞的額外數(shù)據(jù)(ExecutedRoutedEventArgs.Parameter),。在該例中,,因為沒有傳遞任何額外的數(shù)據(jù),所以參數(shù)為null(如果希望傳遞附加數(shù)據(jù),,贏設(shè)置命令源的CommandParameter屬性,;并且如果希望傳遞一些來自另一個控件的信息,還需要使用數(shù)據(jù)綁定表達(dá)式設(shè)置CommandParameter屬性),。

  在上面的示例中,,使用代碼生成了命令綁定。然而,,如果希望精簡代碼隱藏文件,,使用XAML以生命方式關(guān)聯(lián)命令同樣容易。下面是所需的標(biāo)記:

<Window x:Class="Commands.TestNewCommand"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TestNewCommand" Height="300" Width="300">
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.New" Executed="NewCommand"></CommandBinding>
    </Window.CommandBindings>
    <StackPanel>
        <Button Margin="5" Padding="5" Command="ApplicationCommands.New">New</Button>
    </StackPanel>
</Window>

  使用Visual Studio沒有為定義命令綁定提供任何設(shè)計時支持,。對連接控件和命令的支持也較弱,。可使用Properties窗口設(shè)置控件的Command屬性,,但需要輸入正確的命令名稱——由于并未提供包含命令的下拉列表,,因此不能方便地從列表中選擇命令。

三,、使用多命令源

  上面示例中觸發(fā)普通事件的方式看起來不那么直接。然而,,當(dāng)添加使用相同命令的更多控件時,,額外命令層的意義就提現(xiàn)出出來了,。例如,可添加如下也使用New命令的菜單項:

        <Menu >
            <MenuItem Header="File">
                <MenuItem Command="New"></MenuItem>
            </MenuItem>
        </Menu>

  注意,,New命令的這個MenuItem對象沒有設(shè)置Header屬性,。這是因為MenuItem類足夠智能,如果沒有設(shè)置Header屬性,,它將從命令中提取文本(Button控件不具有這一特性),。雖然該特性帶帶來的便利看起來不大,但如果計劃使用不同的語言本地化應(yīng)用程序,,這一特性就很重要了,。在這種情況下,只需要在一個地方修改文本即可(通過設(shè)置命令的Text屬性),。這比在整個窗口中進行跟蹤更容易,。

  MenuItem類還有一項功能:能自動提取Command.InputBinding集合中的第一個快捷鍵(如果存在的話)。對于ApplicationCommands.New命令對象,,這意味著在菜單文本的旁邊會顯示Ctrl+N快捷鍵(如下圖所示),。

 

 四、微調(diào)命令文本

  既然菜單具有自動提取命令項文本的功能,,肯恩改回好奇其他ICommandSource類是否也具有類似功能,,如Button控件。

  可以使用兩種技術(shù)重用命令文本,。一種選擇是直接從靜態(tài)命令對象中提取文本,。XAML可使用Static標(biāo)記擴展完成這一任務(wù)。下面的示例獲取命令名New,,并將它作為按鈕的文本:

<Button Margin="5" Padding="5" Command="New" Content="{x:Static ApplicationCommands.New}"></Button>

  該方法的問題在于,,它指示調(diào)用命令對象命令對象的ToString()方法。因此,,得到的是命令名,,而不是命令的文本(對于哪些名稱中包含多個單詞的命令,使用命令文本更好些,,因為命令文本包含空格),。雖然解決這一問題,但需要完成更多工作,。這種方法還存在一個問題,,一個按鈕將同一個命令使用兩次,可能會無意間從錯誤的命令獲取文本),。

  更好的解決方案是使用數(shù)據(jù)綁定表達(dá)式,。在此使用的數(shù)據(jù)綁定有些不尋常,因為他綁定到當(dāng)前元素嗎,,獲取正在使用的Command對象,,并提取Text屬性,。下面是非常復(fù)雜的語法:

 <Button Margin="5" Padding="5" Command="New" Content="{Binding RelativeSource={RelativeSource Self},Path=Command.Text}"></Button>

  可通過另一種更具想象力的方式使用該技術(shù)。例如,,可使用一幅小圖像設(shè)置按鈕的內(nèi)容,,而在按鈕的工具提示中使用數(shù)據(jù)綁定表達(dá)式顯示命令名:

<Button Margin="5" Padding="5" Command="ApplicationCommands.New" ToolTip="{Binding RelativeSource={RelativeSource Self},Path=Command.Text}">
     <Image Source="redx.jpg"  Stretch="None"></Image>
</Button>

  按鈕的內(nèi)容可以是形狀,也可以是顯示為縮略圖的位圖,。

  顯然,,這種方法比直接在標(biāo)記中放置命令文本更麻煩些。然而,,如果準(zhǔn)備使用不同的語言本地化應(yīng)用程序,,使用這個方法是值得的。當(dāng)應(yīng)用程序啟動時,,只需要為所有命令設(shè)置命令文本即可(如果在創(chuàng)建了命令綁定后改變命令文本,,不會產(chǎn)生任何效果。因為Text屬性不是依賴項屬性,,所以沒有自動的更改通知來更新用戶界面),。

五、直接調(diào)用命令

  并非只能使用實現(xiàn)了ICommandSource接口的類來觸發(fā)希望執(zhí)行的命令,。也可以用Execute()方法直接調(diào)用來自任何事件處理程序的方法,。這時需要傳遞參數(shù)值(或null引用)和對目標(biāo)元素的引用:

ApplicationCommands.New.Execute(null,targetElement);

  目標(biāo)元素是WPF開始查找命令綁定的地方??墒褂冒翱冢ň哂忻罱壎ǎ┗蚯短椎脑兀ɡ?,實際引發(fā)事件的元素)。

  也可在關(guān)聯(lián)的CommandBinding對象中調(diào)用Execute()方法,。在這種情況下,,不需要提供目標(biāo)元素,因為會自動將公開正在使用的CommandBindings集合的元素設(shè)置為目標(biāo)元素,。

this.CommandBindings[0].Command.Execute(null);

  這種方法只使用了半個命令模型,。雖然也觸發(fā)命令,但不能響應(yīng)命令的狀態(tài)變化,。如果希望實現(xiàn)該特性,,當(dāng)命令變?yōu)閱⒂没蚪脮r,也可能希望處理RoutedCommand.CanExecuteChanged事件進行響應(yīng),。當(dāng)引發(fā)CanExecuteChanged事件時,,需要調(diào)用RoutedCommand.CanExecute()方法檢查命令是否處于可用狀態(tài)。如果命令不可用,??山没蚋淖冇脩艚缑嬷械牟糠謨?nèi)容。

六、禁用命令

  如果想要創(chuàng)建狀態(tài)在啟用和禁用之間變化的命令,,你將體會到命令模型的真正優(yōu)勢,。例如,分析下圖中顯示的單窗口應(yīng)用程序,,它是有菜單、工具欄以及大文本框構(gòu)成的簡單文本編輯器,。該應(yīng)用程序可以打開文件,,創(chuàng)建新的(空白)文檔,以及保存所執(zhí)行的操作,。

 

   在該應(yīng)用程序中,,保持New、Open,、Save,、SaveAs以及Close命令一直可用是非常合理的。但還有一種設(shè)計,,只有當(dāng)某些操作使文本相對于原來的文件發(fā)生了變化時才啟用Save命令,。根據(jù)約定,可在代碼中使用簡單的Boolean值來跟蹤這一細(xì)節(jié):

private bool isDirty = false;

  然后當(dāng)文本發(fā)生變化時設(shè)置該標(biāo)志:

private void txt_TextChanged(object sender, RoutedEventArgs e)
        {
            isDirty = true;
        }

  現(xiàn)在需要從窗口命令綁定傳遞信息,,使鏈接的控件可根據(jù)需要進行更新,。技巧是處理命令綁定的CanExecute事件??赏ㄟ^下面的代碼為該事件關(guān)聯(lián)事件處理程序:

CommandBinding binding = new CommandBinding(ApplicationCommands.Save);
            binding.Executed += SaveCommand_Executed;
            binding.CanExecute += SaveCommand_CanExecute;
            this.CommandBindings.Add(binding);

  或使用聲明方式:

<Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Save" 
                        Executed="SaveCommand_Executed" 
                        CanExecute="SaveCommand_CanExecute"></CommandBinding>
    </Window.CommandBindings>

  在事件處理程序中,,只需要檢查isDirty變量,并相應(yīng)地設(shè)置CanExecuteRoutedEventArgs.CanExecute屬性:

private void SaveCommand_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = isDirty;
        }

  如果isDirty的值時false,,就禁用命令,。如果isDirty的值為true,就啟用命令(如果沒有設(shè)置CanExecute標(biāo)志,,就會保持最近的值),。

  當(dāng)使用CanExecute事件時,還需要理解一個問題,,由WPF負(fù)責(zé)調(diào)用RoutedCommand.CanExecute()方法來觸發(fā)事件處理程序,,并確定命令的狀態(tài)。當(dāng)WPF命令管理器探測到某個確信十分重要的變化——例如,,當(dāng)焦點從一個控件移到另一個控件上時,,或執(zhí)行了某個命令后,WPF命令管理器就會完成該工作,??丶€能引發(fā)CanExecuteChanged事件以通知WPF重新評估命令——例如,當(dāng)用戶在文本框中按下一個鍵時會發(fā)生該事件??傊?,CanExecute事件會被頻繁地觸發(fā),并且不應(yīng)在該事件的處理程序中使用耗時的代碼,。

  然而,,其他因素可能影響命令狀態(tài)。在當(dāng)前示例中,,為響應(yīng)其他操作,,可能會修改isDirty標(biāo)志。如果發(fā)現(xiàn)命令狀態(tài)未在正確的時間被更新,,可強制WPF為所有正在使用的命令調(diào)用CanExecute()方法,。通過調(diào)用靜態(tài)方法CommandManager.InvalidateRequerySuggested()完成該工作。然后命令管理器觸發(fā)RequerySuggested事件,,通知窗口中的命令源(按鈕,、菜單項等)。此后命令源會重新查詢它們鏈接的命令并相應(yīng)地更新它們的狀態(tài),。

七,、具有內(nèi)置命令的控件

  一個輸入控件可自行處理命令事件。例如,,TextBox類處理Cut,、Copy以及Paste命令(還有Undo、Redo命令,,以及一些來自EditingCommd類的用于選擇文本以及將光標(biāo)移到不同位置的命令),。

  當(dāng)控件具有自己的硬編碼命令邏輯時,為使命令工作不需要做其他任何事情,。例如,,對于上節(jié)示例的簡單編輯器,添加如下工具欄按鈕,,就會自動獲取對剪切,、復(fù)制和粘貼文本的支持:

<ToolBar>
     <Button Command="Cut">Cut</Button>
     <Button Command="Copy">Copy</Button>
     <Button Command="Paste">Paste</Button>
 </ToolBar>

  現(xiàn)在淡季這些按鈕中的任意一個(當(dāng)文本框具有焦點時),就可以復(fù)制,、剪切或從剪貼板粘貼文本,。有趣的是,文本框還處理CanExecute事件,。如果當(dāng)前未在文本框中選中任何內(nèi)容,,就會禁用剪切和復(fù)制命令。當(dāng)焦點移到其他不支持這些命令的控件時,,會自動禁用所有這三個命令(除非關(guān)聯(lián)自己的CanExecute事件處理程序以啟動這些命令),。

  該例有一個有趣的細(xì)節(jié),。Cut、Copy和Paste命令被具有焦點的文本框處理,。然而,,由工具欄上的按鈕觸發(fā)的命令時完全獨立的元素。在該例中,,這個過程之所以能夠無縫工作,,是因為按鈕被放到工具欄上,ToolBar類提供了一些內(nèi)置邏輯,,可將其子元素的CommandTarget屬性動態(tài)設(shè)置為當(dāng)前具有焦點的控件(從技術(shù)角度看,,ToolBar控件一直在關(guān)注著其父元素,即窗口,,并在上下文中查找最近具有焦點的控件,即文本框,。ToolBar控件有單獨的焦點范圍(focus scope),,并且在其上下文中按鈕是具有焦點的)。

如果在不同容器(不是ToolBar或Menu控件)中放置按鈕,,就不會獲得這些優(yōu)勢,。這意味著除非手動設(shè)置CommanTarget屬性,否則按鈕不能工作,。為此,,必須使用命令目標(biāo)元素的綁定的表達(dá)式。例如,,如果文本框被命名為txtDocument,,就應(yīng)該像下面這樣定義按鈕:

<Button Command="Cut" CommandTarget="{Binding ElementName=txtDocument}">Cut</Button>
<Button Command="Copy" CommandTarget="{Binding ElementName=txtDocument}">Copy</Button>
<Button Command="Paste" CommandTarget="{Binding ElementName=txtDocument}">Paste</Button>

  另一個較簡單的選擇是使用附加屬性FocusManager.IsFocusScope創(chuàng)建新的焦點范圍。當(dāng)觸發(fā)命令時,,該焦點范圍會通知WPF在父元素的焦點范圍內(nèi)查找元素:

<StackPanel FocusManager.IsFocusScope="True">
    <Button Command="Cut">Cut</Button>
    <Button Command="Copy">Copy</Button>
    <Button Command="Paste">Paste</Button>
</StackPanel>

  該方法還有一個附加優(yōu)點,,即相同的命令可應(yīng)用于多個控件,不像上個示例那樣對CommandTarget進行硬編碼,。此外,,Menu和ToolBar控件默認(rèn)將FocusManager.IsFocusScope屬性設(shè)置為true,但如果希望簡化命令路由行為,,不在父元素上下文中查找具有焦點的元素,,也可將該屬性設(shè)為false。

  在極少數(shù)情況下,,你可能發(fā)現(xiàn)控件支持內(nèi)置命令,,而你并不想啟用它。在這種情況下,,可以采用三種方法禁用命令,。

  理想情況下,控件提供用于關(guān)閉命令支持的屬性,從而確??丶瞥@些特性并連貫地調(diào)整自身,。例如,TextBox控件提供了IsUndoEnabled屬性,,為阻止Undo特性,,可將該屬性設(shè)置為false(如果IsUndoEnabled屬性為true,Ctrl+Z組合鍵將觸發(fā)Undo命令),。

  如果這種做法行不通,,可為希望禁用的命令添加新的命令綁定。然后該命令綁定可提供新的CanExecute事件處理程序,,并總是響應(yīng)false,。下面舉一個使用該技術(shù)刪除文本框Cut特性支持的示例:

CommandBinding commandBinding=new CommandBinding(ApplicationCommands.Cut,null,SuppressCommand);
txt.CommandBindings.Add(commandBinding);

  而且該事件處理程序設(shè)置CanExecute狀態(tài):

private void SupressCommand(object sender,CanExecuteRoutedEventArgs e)
{
  e.CanExecute=false;
  e.Handled=false;    
}

  注意,上面的代碼設(shè)置了Handled標(biāo)志以阻止文本框自我執(zhí)行計算,,而文本框可能將CanExecute屬性設(shè)置為true,。

  該方法并不完美。它可成功地為文本框禁用Cut快捷鍵(Ctrl+X)和上下文菜單中的Cut命令,。然而,,仍會在上下文菜單中顯示處理禁用狀態(tài)的該選項。

  最后一種選擇是,,使用InputBinding集合刪除觸發(fā)命令的輸入,。例如,可使用帶阿媽禁用觸發(fā)TextBox控件中的Copy命令的Ctrl+C組合鍵,,如下所示:

KeyBinding keyBinding=new KeyBinding(ApplicationCommands.NotACommand,Key.C,ModifierKeys.Control);
txt.InputBinding.Add(keyBinding);

  技巧是使用特定的ApplicationCommands.NotACommand值,,該命令什么都不做,它專門用于禁用輸入綁定,。

  當(dāng)使用這種方法時,,仍啟用Copy命令??赏ㄟ^自己創(chuàng)建的按鈕觸發(fā)該命令(或使用文本框的上下文菜單觸發(fā)命令,,除非也通過將ContextMenu屬性設(shè)置為null刪除了上下文菜單)。

 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請點擊一鍵舉報,。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多