主頁 > .NET開發 > WPF之命令

WPF之命令

2021-03-07 06:06:46 .NET開發

目錄
  • 命令系統的基本元素
  • 基本元素之間的關系
  • 小試命令
  • WPF的命令庫
  • 命令引數
  • 命令與Binding的結合
  • 近觀命令
    • ICommand介面與RoutedCommand
    • 自定義Command
      • 定義命令目標介面(IView )
      • 定義命令(實作ICommand介面)
      • 定義命令源(實作ICommandSource)
      • 定義命令目標(實作IView介面)
      • 使用自定義命令
  • 參考資料

命令系統的基本元素

WPF的命令系統由幾個基本要素構成:

  • 命令(Command):WPF的命令實際上就是實作了ICommand介面的類,平時使用最多的是RoutedCommand類,還可以使用自定義命令,
  • 命令源(Command Source):即命令的發送者,是實作了ICommandSource介面的類,很多界面元素都實作了這個介面,如Button、Menultem、ListBoxltem等,
  • 命令目標(Command Target):即命令將發送給誰,或者說命令將作用在誰身上,命令目標必須是實作了IInputElement介面的類,
  • 命令關聯(Command Binding):負責把一些外圍邏輯與命令關聯起來,比如執行之前對命令是否可以執行進行判斷、命令執行之后還有哪些后續作業等,

基本元素之間的關系

基本元素之間的關系體現在使用命令的程序中,命令的使用大概分為如下幾步:

  • 創建命令類:即獲得一個實作ICommand介面的類,命令與具體業務邏輯無關則使用WPF類別庫中的RoutedCommand類即可,與業務邏輯相關則需創建RoutedCommand(或者ICommand介面)的派生類,
  • 宣告命令實體:使用命令時需要創建命令類的實體,一般情況下程式中某種操作只需要一個命令實體與之對應即可,程式中的命令多使用單件模式(Singletone Pattern)
  • 指定命令的源:即指定由誰來發送這個命令,同一個命令可以有多個源,一旦把命令指派給命令源,那么命令源就會受命令的影響,各種控制元件發送命令的方法也不盡相同(如Buton是在單擊時發送命令、ListBoxltme雙擊時發送命令),
  • 指定命令目標:命令目標并不是命令的屬性而是命令源的屬性,指定命令目標是告訴命令源向哪個組件發送命令,無論這個組件是否擁有焦點它都會收到這個命令,沒有為命令源指定命令目標則WPF系統認為當前擁有焦點的物件就是命令目標,
  • 設定命令關聯:WPF命令需要CommandBinding在執行前來幫助判斷是不是可以執行、在執行后做一些事件來“打掃戰場”,

一旦某個UI組件被命令源“瞄上”,命令源就會不停地向命令目標“投石問路”,命令目標就會不停地發送出可路由的PreviewCanExecute和CanExecute附加事件,事件會沿著UI元素樹向上傳遞并被命令關聯所捕捉,命令關聯捕捉到這些事件后會把命令能不能發送實時報告給命令,

如果命令被發送出來并到達命令目標,命令目標就會發送PreviewExecuted和Executed兩個附加事件,這兩個事件也會沿著UI元素樹向上傳遞并被命令關聯所捕捉,命令關聯會完成一些后續的任務,對于那些與業務邏輯無關的通用命令,這些后續任務才是最重要的,

命令目標發出的PreviewCanExecute、CanExecute、PreviewExecuted和Executed這4個事件都是附加事件,是被CommandManager類“附加”給命令目標的,PreviewCanExecute和CanExecute的執行時機不由程式員控制,且執行頻率比較高,會給降低系統性能、引入比較難除錯的bug,

WPF命令系統基本元素的關系圖如下:

小試命令

定義一個命令,使用Button來發送這個命令,當命令送達TextBox時TextBox會被清空(如果TextBox中沒有文字則命令不可被發送),
XAML界面代碼如下:

<Window x:
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
        Title="MainWindow" Height="179.464" Width="438.393">
    <StackPanel x:Name="stackPanel">
        <Button x:Name="button1" Content="Send Command" Margin="5"/>
        <TextBox x:Name="textBoxA" Margin="5,0" Height="100"/>
    </StackPanel>
</Window>

C#后臺代碼如下:

public MainWindow()
{
    InitializeComponent();
    InitializeCommand();
}

//宣告并定義命令
private RoutedCommand clearCmd = new RoutedCommand("Clear",typeof(MainWindow));
private void InitializeCommand()
{
    //把命令賦值給命令源(發送者)并指定快捷鍵
    this.button1.Command=this.clearCmd;
    this.clearCmd.InputGestures.Add(new KeyGesture(Key.C, ModifierKeys.Alt));
    //指定命令目標
    this.button1.CommandTarget = this.textBoxA;
    //創建命令關聯
    CommandBinding cb = new CommandBinding();
    cb.Command = this.clearCmd;
    //只關注與clearCmd相關的事件
    cb.CanExecute += new CanExecuteRoutedEventHandler(cb_CanExecute);
    cb.Executed += new ExecutedRoutedEventHandler(cb_Executed);
    //把命令關聯安置在外圍控制元件上
    this.stackPanel.CommandBindings.Add(cb);
}

//當探測命令是否可以執行時,此方法被呼叫
void cb_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    if (string.IsNullOrEmpty(this.textBoxA.Text))
    {
        e.CanExecute = false;
    }
    else
    { 
        e.CanExecute = true; 
    }

    // 避免繼續向上傳而降低程式性能
    e.Handled = true; 
}

//當命令送達目標后,此方法被呼叫
void cb_Executed(object sender, ExecutedRoutedEventArgs e) 
{
    this.textBoxA.Clear();

    // 避免繼續向上傳而降低程式性能
    e.Handled = true;    
}

運行程式,在TextBox中輸入文字后Button在命令可執行狀態的影響下變為可用,此時單擊Buton 或者按Alt+C鍵,TextBox都會被清空,效果如下:

對于上面代碼有幾點需要注意的地方:

  • 使用命令可以避免自己寫代碼判斷Button是否可用以及添加快捷鍵,
  • RoutedCommand是一個與業務邏輯無關的類,只負責在程式中“跑腿”而并不對命令目標做任何操作,TextBox是由CommandBinding清空的
  • 因為CanExecute事件的激發頻率比較高,為了避免降低性能,在處理完后建議把e.Handled設為true
  • CommandBinding一定要設定在命令目標的外圍控制元件上,不然無法捕捉到CanExecute和Executed等路由事件,

WPF的命令庫

上面的例子中宣告定義了一個命令:

private RoutedCommand clearCmd = new RoutedCommand("Clear",typeof(MainWindow));

命令具有“一處宣告、處處使用”的特點,比如Save命令在程式的任何地方它都表示要求命令目標保存資料,微軟在WPF類別庫里準備了一些便捷的命令庫,這些命令庫包括:

  • ApplicationCommands:提供一組標準的與應用程式相關的命令,參考ApplicationCommands,
  • ComponentCommands:提供一組標準的與組件相關的命令,參考ComponentCommands,
  • NavigationCommands:提供一組標準的與導航相關的命令,參考NavigationCommands,
  • MediaCommands:提供一組標準的與媒體相關的命令,參考MediaCommands,
  • EditingCommands:提供一組標準的與編輯相關的命令,參考EditingCommands,

它們都是靜態類,而命令就是用這些類的靜態只讀屬性以單件模式暴露出來的,如ApplicationCommands類的原始碼如下:

public static class ApplicationCommands 
 {
     public static RoutedUICommand Cut { get; }
     public static RoutedUICommand Stop { get; }
     public static RoutedUICommand ContextMenu { get; }
     public static RoutedUICommand Properties { get; }
     public static RoutedUICommand PrintPreview { get; }
     public static RoutedUICommand CancelPrint { get; }
     public static RoutedUICommand Print { get; }
     public static RoutedUICommand SaveAs { get; }
     public static RoutedUICommand Save { get; }
     public static RoutedUICommand Close { get; }
     public static RoutedUICommand CorrectionList { get; }
     public static RoutedUICommand Open { get; }
     public static RoutedUICommand Help { get; }
     public static RoutedUICommand SelectAll { get; }
     public static RoutedUICommand Replace { get; }
     public static RoutedUICommand Find { get; }
     public static RoutedUICommand Redo { get; }
     public static RoutedUICommand Undo { get; }
     public static RoutedUICommand Delete { get; }
     public static RoutedUICommand Paste { get; }
     public static RoutedUICommand Copy { get; }
     public static RoutedUICommand New { get; }
     public static RoutedUICommand NotACommand { get; }
 }

其他幾個命令庫也與之類似,標準命令不用自己宣告,直接使用命令庫即可,

命令引數

命令源一定是實作了ICommandSource介面的物件,而ICommandSource有一個屬性就是CommandPrameter,CommandPrameter就相當于命令里的“訊息”,

實作一個需求,當TextBox中沒有內容時兩個按鈕均不可用;當輸入文字后按鈕變為可用,單擊按鈕,ListBox會加入不同條目,
XAML代碼如下:

<Grid Margin="6">
    <Grid.RowDefinitions>
        <RowDefinition Height="24"/>
        <RowDefinition Height="4"/>
        <RowDefinition Height="24"/>
        <RowDefinition Height="4"/>
        <RowDefinition Height="24"/>
        <RowDefinition Height="4"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <!--命令和命令引數-->
    <TextBlock Text="Name:" VerticalAlignment="Center" HorizontalAlignment="Left" Grid.Row="0"/>
    <TextBox x:Name="nameTextBox" Margin="60,0,0,0" Grid.Row="0"/>
    <Button Content="New Teacher" Command="New" CommandParameter="Teacher" Grid.Row="2"/>
    <Button Content="New Student" Command="New" CommandParameter="Student" Grid.Row="4"/>
    <ListBox x:Name="listBoxNewltems" Grid.Row="6"/>
</Grid>
<!--為表單添加CommandBinding-->
<Window.CommandBindings>
    <CommandBinding Command="New" CanExecute="New_CanExecute" Executed="New_Executed"/>
</Window.CommandBindings>

CommandBinding的兩個事件處理器代碼如下:

private void New_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    if (string.IsNullOrEmpty(this.nameTextBox.Text))
    {
        e.CanExecute = false;
    }
    else 
    { 
        e.CanExecute = true; 
    }
}
private void New_Executed(object sender, ExecutedRoutedEventArgs e) 
{
    string name = this.nameTextBox.Text;
    if (e.Parameter.ToString() == "Teacher") 
    {
        this.listBoxNewltems.Items.Add(string.Format("New Teacher:{0},學而不厭、海人不倦,",name));
    }
    if (e.Parameter.ToString() == "Student") 
    {
        this.listBoxNewltems.Items.Add(string.Format("New Student:{0},好好學習、天天向上,", name));
    }
        
}

效果如下:

命令與Binding的結合

控制元件有很多事件可以進行各種各樣不同的操作,可控制元件只有一個Command屬性,而命令庫中卻有數十種命令,使用Binding可以使用Command屬性來呼叫多種命令,

例如,如果一個Buton所關聯命令有可能根據某些條件而改變,可以把代碼寫成這樣:

<Buton x:Name="dynamicCmdBtn" Command="{Binding Path=ppp,Source=sss}" Content="Command"/>

大多數命令按鈕都有相對應的圖示來表示固定的含義,日常作業中一個控制元件的命令一經確定就很少改變,

近觀命令

一般情況下,程式中使用與邏輯無關的RoutedCommand就足夠了,但為了使程式的結構更加簡潔(比如去掉外圍的CommandBinding和與之相關的事件處理器),常需要定義自己的命令,
接下來,先由剖析RoutedCommand入手,再創建自己的命令,

ICommand介面與RoutedCommand

WPF的命令是實作了ICommand介面的類,ICommand介面只包含兩個方法和一個事件:

  • Execute方法:命令執行,或者說命令作用于命令目標之上,
  • CanExecute方法:在執行之前用來探知命令是否可被執行,
  • CanExecuteChanged事件:當命令可執行狀態發生改變時,可激發此事件來通知其他物件,

RoutedCommand在實作ICommand介面時,并未向Execute和CanExecute方法中添加任何邏輯,它是通用的、與具體業務邏輯無關的

從外部來看,當一個命令到達命令目標后,具體是執行Copy還是Cut(即業務邏輯)不是由命令決定的,而是外圍的CommandBinding捕獲到命令目標受命令激發而發送的路由事件后在其Executed事件處理器中完成,

從內部分析,RoutedCommand類與命令執行相關的代碼簡化如下:

public class RoutedCommand : ICommand
{
    //由lCommand繼承而來,僅供內部使用
    private void ICommand.Execute(object parameter)
    {
        Execute(parameter, FilterInputElement(Keyboard.FocusedElement));
    }

    //新定義的方法,可由外部呼叫
    //第一個引數向命令傳遞一些資料,第二個引數是命令的目標
    public void Execute(object parameter, IInputElement target)
    {            
        //命令目標為空,選定當前具有焦點的控制元件作為目標
        if ((target != null) && !InputElement.IsValid(target))
        {
            throw new InvalidOperationException(SR.Get(SRID.Invalid_IInputElement, target.GetType()));
        }

        if (target == null)
        {
            target = FilterInputElement(Keyboard.FocusedElement);
        }

        //真正執行命令的邏輯
        ExecuteImpl(parameter, target, false);
    }

    //真正執行命令的邏輯,僅供內部使用
    private bool ExecuteImpl(object parameter, IInputElement target, bool userInitiated)
    {
        //..
        UIElement targetUIElement = target as UIElement;
        //..
        ExecutedRoutedEventArgs args = new ExecutedRoutedEventArgs(this, parameter);
        args.RoutedEvent = CommandManager.PreviewExecutedEvent;

        if (targetUIElement != null)
        {
            targetUIElement.RaiseEvent(args, userInitiated);
        }
        //..
        return false;
    }

    //另一個呼叫Executelmpl方法的函式,依序集級別可用
    internal bool ExecuteCore(object parameter, IInputElement target, bool userInitiated)
    {
        if (target == null)
        {
            target = FilterInputElement(Keyboard.FocusedElement);
        }

        return ExecuteImpl(parameter, target, userInitiated);
    }     
}

從ICommand介面繼承來的Execute并沒有被公開(可以說是廢棄了),僅僅是呼叫新宣告的帶兩個引數的Execute方法,新的Execute方法會呼叫命令執行邏輯的核心——Executelmpl方法(Executelmpl是Execute Implement的縮寫),這個方法“借用”命令目標的RaiseEvent把RoutedEvent發送出去,事件會被外圍的CommandBinding捕獲到然后執行程式員預設的與業務相關的邏輯,

以ButtonBase為例,ButtonBase是在Click事件發生時發送命令的,而Click事件的激發是放在OnClick方法里,ButonBase的OnClick方法如下:

public class ButtonBase : ContentControl, ICommandSource 
{
    //激發Click路由事件,然后發送命令
    protected virtual void OnClick()
    {
        RoutedEventArgs newEvent = new RoutedEventArgs(BuonBase.ClickEvent, this);
        RaiseEvent(newEvent);

        //呼叫內部類CommandHelpers的ExecuteCommandSource方法
        MS.Internal.Commands.CommandHelpers.ExecuteCommandSource(this);
    }
}

ButonBase 呼叫了一個.NET Framework內部類(這個類沒有向程式員暴露)CommandHelpers的ExecuteCommandSource方法,并把ButtonBase物件自己當作引數傳了進去,

ExecuteCommandSource方法實際上是把傳進來的引數當作命令源、呼叫命令源的ExecuteCore 方法(本質上是呼叫其Executelmpl方法)、獲取命令源的CommandTarget屬性值(命令目標)并使命令作用于命令目標之上,

CommandHelpers部分原始碼如下:

internal static class CommandHelpers
{
    //..
    internal static void ExecuteCommandSource(ICommandSource commandSource)
    {
        CriticalExecuteCommandSource(commandSource, false);
    }
    internal static void CriticalExecuteCommandSource(ICommandSource commandSource, bool userInitiated)
    {
        ICommand command = commandSource.Command;
        if (command != null)
        {
            object parameter = commandSource.CommandParameter;
            IInputElement target = commandSource.CommandTarget;

            RoutedCommand routed = command as RoutedCommand;
            if (routed != null)
            {
                if (target == null)
                {
                    target = commandSource as IInputElement;
                }
                if (routed.CanExecute(parameter, target))
                {
                    routed.ExecuteCore(parameter, target, userInitiated);
                }
            }
            else if (command.CanExecute(parameter))
            {
                command.Execute(parameter);
            }
        }
    }
}

自定義Command

“自定義命令”可以分兩個層次來理解:

  • 第一個層次是指的是當WPF命令庫中沒有包含想要的命令時宣告定義自己的RoutedCommand實體,如定義一個名為Laugh的RoutedCommand實體,實際是對RoutedCommand的使用,
  • 第二個層次是指實作ICommand介面、定義自己的命令并且把某些業務邏輯也包含在命令之中,真正意義上的自定義命令,

WPF自帶的命令源和CommandBinding就是專門為RoutedCommand而撰寫的,如果想使用自己的ICommand派生類就必須連命令源一起實作(即實作ICommandSource介面),需要根據專案的實際情況進行權衡,

下面自定義一個名為Clear的命令,當命令到達命令目標的時候先通過命令目標的IsChanged屬性判斷命令目標的內容是否已經被改變,如果已經改變則命令可以執行,命令的執行會直接呼叫命令目標的Clear方法、驅動命令目標以自己的方式清除資料(同時改變IsChanged屬性值),

命令直接在命令目標上起作用,而不像RoutedCommand那樣先在命令目標上激發出路由事件等外圍控制元件捕捉到事件后再“翻過頭來”對命令目標加以處理

定義命令目標介面(IView )

在程式中定義這樣一個介面:

public interface IView 
{
    //屬性
    bool IsChanged{get; set;}

    //方法
    void SetBinding();
    void Refresh();
    void Clear();
    void Save();

    //...
}

要求每個需要接受命令的組件都必須實作這個介面,確保命令可以成功地對它們執行操作,

定義命令(實作ICommand介面)

接下來實作ICommand介面,創建一個專門作用于IView派生類的命令:

//自定義命令
public class ClearCommand : ICommand
{
    //當命令可執行狀態發送改變時,應當被激發
    public event EventHandler CanExecuteChanged;

    //用來判斷命令是否可以執行
    public bool CanExecute(object parameter)
    {
        bool canExecute = false;
        IView view = parameter as IView;
        if (view != null)
        {
            canExecute = view.IsChanged;
        }
        return canExecute;
    }        

    //命令執行時,帶有與業務相關的Clear邏輯
    public void Execute(object parameter)
    {
        IView view = parameter as IView;
        if (view != null)
        {
            view.Clear();
        }
    }
}

命令實作了ICommand介面并繼承了CanExecuteChanged事件、CanExecute方法和Execute方法,在實作CanExecute方法和Execute方法時將唯一的引數作為命令的目標:

  • Execute方法中,如果目標是IView介面的派生類則呼叫其Clear方法(把業務邏輯引入了命令的Execute方法中),
  • CanExecute方法中,如果目標是IView介面的派生類則回傳其IsChanged屬性值(根據專案需求定義),

定義命令源(實作ICommandSource)

WPF命令系統的命令源是專門為RoutedCommand準備的并且不能重寫,所以只能通過實作ICommandSource介面來創建自己的命令源,代碼如下:

//自定義命令源
public partial class MyCommandSource : UserControl, ICommandSource
{

    // 繼承自ICommand的3個屬性
    public ICommand Command { get; set; }
    public object CommandParameter { get; set; }
    public IInputElement CommandTarget { get; set; }

    //建構式
    public MyCommandSource() 
    {
        //命令重繪的時機
        CommandManager.RequerySuggested += RequeryCanExecute;
        //如果初次重繪不及時,可在此手動呼叫一次
        RequeryCanExecute(null, null);
    }


    //在組件被單擊時連帶執行命令
    protected override void onm ouseLeftButtonDown(MouseButtonEventArgs e)
    {
        base.OnMouseLeftButtonDown(e);
        if (this.CommandTarget != null)
        {
            if (this.Command.CanExecute(CommandTarget)) 
            {
                this.Command.Execute(CommandTarget);
            }
        }
    }

    //查詢并顯示命令目標的可執行狀態,顯示方式根據實際需求定義
    private void RequeryCanExecute(object sender, EventArgs e)
    {
        if (this.CommandTarget != null)
        {
            if (this.Command.CanExecute(CommandTarget))
            {                    
                this.Background = System.Windows.Media.Brushes.Green;
            }
            else 
            {                    
                this.Background = System.Windows.Media.Brushes.Orange;
            }
                       
        }
    }
}

ICommandSource介面只包含Command、CommandParameter和CommandTarget三個屬性,三個屬性之間的關系取決于實作,
在本例中,CommandParameter完全沒有被用到,而CommandTarget被當作引數傳遞給了Command的Execute、CanExecute方法,在控制元件被左單擊時執行命令,

定義命令目標(實作IView介面)

ClearCommand專門作用于IView的派生類,合格的ClearCommand命令目標必須實作IView介面,

設計這種既有UI又需要實作介面的類可以先用XAML編輯器實作其UI部分再找到它的后臺C#代碼實作介面(WPF會自動為UI元素類添加partial關鍵字修飾),XAML代碼會被翻譯成類的一個部分,后臺代碼是類的另一個部分(甚至可以再多添加幾個部分),可以在后臺代碼部分指定基類或實作介面,最終這些部分會被編譯到一起,

組件的XAML部分如下:

<UserControl x:
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Height="114" Width="200">
    <Border CornerRadius="5" BorderBrush="GreenYellow" BorderThickness="2">
        <StackPanel TextBoxBase.TextChanged="TextBoxBase_TextChanged">
            <TextBox x:Name="textBox1" Margin="5"/>
            <TextBox x:Name="textBox2" Margin="5,0"/>
            <TextBox x:Name="textBox3" Margin="5"/>
            <TextBox x:Name="textBox4" Margin="5,0"/>
        </StackPanel>
    </Border>
</UserControl>

組件的后臺代碼部分如下:

public partial class MniView : UserControl, IView
{
    public MniView()
    {
        InitializeComponent();
    }

    //繼承自IView的成員們
    public bool IsChanged { get; set; } 
    public void SetBinding(){}
    public void Refresh(){}
    public void Save() {}

    /// <summary>
    /// 用于清除內容的業務邏輯
    /// </summary>
    public void Clear()
    {
        this.textBox1.Clear();
        this.textBox2.Clear();
        this.textBox3.Clear();
        this.textBox4.Clear();
        IsChanged = false;
    }

    private void TextBoxBase_TextChanged(object sender, TextChangedEventArgs e)
    {
        IsChanged = true;
    }
}

當Clear方法被呼叫的時候,它的幾個TextBox會被清空,

使用自定義命令

把自定義命令、命令源、命令目標集成起來,表單的XAML代碼如下:

<Window x:
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
        xmlns:local="clr-namespace:WpfApp"      
        Title="MainWindow" Height="171.464" Width="297.06">
    <StackPanel>
        <local:MyCommandSource  x:Name="ctrlClear">
            <TextBlock Text="清除" Margin="10" Width="80" FontSize="16" TextAlignment="Center" Background="LightGreen"/>
        </local:MyCommandSource>
        <local:MniView x:Name="mniView1" />
    </StackPanel>
</Window>

本例中使用簡單的文本作為命令源的顯示內容,用OnMouseLeftButtonDown的方法來執行命令,需要根據顯示內容的種類適當更改激發命令的方法,如使用按鈕時應該捕獲button的Click事件并在事件處理器中執行方法(Mouse事件會被Button吃掉),

后臺C#代碼:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        //宣告命令并使命令源和目標與之關聯
        ClearCommand clearCommand = new ClearCommand();
        this.ctrlClear.Command = clearCommand;
        this.ctrlClear.CommandTarget = mniView1;
    }
}

首先創建了一個ClearCommand實體并把它賦值給自定義命令源的Command屬性(正規的方法應該是把命令宣告為靜態全域的地方供所有物件呼叫),自定義命令源的CommandTarget屬性目標是MiniView的實體,

運行程式,在TextBox里輸入然后再單擊清除控制元件,效果如下圖:

參考資料

WPF學習之深入淺出話命令
【WPF】Command 自定義命令
WPF 的命令的自動重繪時機

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/266882.html

標籤:WPF

上一篇:ASP.NET中使用JObject和JArray決議Json資料

下一篇:.net core Console 程式如何在在控制臺某一個位置固定輸出一些內容?Linux下

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more