<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      回顧一下WPF原生實現命令

      前言

      最近在學習Stylet中Command="{s:Action 方法名}"的設計與實現,但要弄明白這個之前,必須對原生實現命令比較熟悉,一想我也很久沒有自己實現原生的命令了,之前都是用Community.Mvvm庫來實現,所以今天先來回顧一下,在WPF中如何實現原生的命令。

      借助AI使用原生的WPF寫法實現了一個跟Stylet例子Hello一樣的效果:

      WPF中如何使用命令

      WPF命令是實現用戶界面交互的核心機制,通過實現ICommand接口來封裝可執行的操作。命令支持松耦合的UI設計,可以綁定到按鈕、菜單等控件,實現統一的執行邏輯。WPF提供了豐富的內置命令如ApplicationCommandsNavigationCommands等,同時也支持自定義命令,便于實現撤銷/重做、數據綁定等復雜功能。

      現在先來看看這個例子中是如何使用命令的吧!!

       public class RelayCommand : ICommand
       {
           private readonly Action<object?> _execute;
           private readonly Predicate<object?>? _canExecute;
      
           public RelayCommand(Action<object?> execute, Predicate<object?>? canExecute = null)
           {
               _execute = execute ?? throw new ArgumentNullException(nameof(execute));
               _canExecute = canExecute;
           }
      
           public event EventHandler? CanExecuteChanged
           {
               add => CommandManager.RequerySuggested += value;
               remove => CommandManager.RequerySuggested -= value;
           }
      
           public bool CanExecute(object? parameter)
           {
               return _canExecute == null || _canExecute(parameter);
           }
      
           public void Execute(object? parameter)
           {
               _execute(parameter);
           }
      
           public void RaiseCanExecuteChanged()
           {
               CommandManager.InvalidateRequerySuggested();
           }
       }
      

      這個例子中自己實現了一個實現ICommand接口的RelayCommand類。

      先來看看ICommand接口:

          public interface ICommand
          {
              event EventHandler? CanExecuteChanged;
              bool CanExecute(object? parameter); 
              void Execute(object? parameter);
          }
      

      這個ICommand接口起到了什么作用呢?

      • 統一命令規范:定義了命令的標準結構,包含執行方法Execute和狀態判斷方法CanExecute
      • 實現命令綁定:允許UI控件(如Button、MenuItem)通過Command屬性綁定到具體命令實現
      • 控制可用性:CanExecute方法動態控制控件的啟用/禁用狀態,CanExecuteChanged事件通知UI更新狀態
      • 參數傳遞:通過parameter參數在UI和命令邏輯間傳遞數據
      • 解耦UI與業務邏輯:將界面操作與具體實現分離,提高代碼的可維護性和可測試性

      RelayCommand中:

       private readonly Action<object?> _execute;
       private readonly Predicate<object?>? _canExecute;
      

      _execute (Action<object?>): 存儲要執行的操作委托

      _canExecute (Predicate<object?>?): 存儲判斷命令是否可執行的謂詞委托,可為 null

       public event EventHandler? CanExecuteChanged
       {
           add => CommandManager.RequerySuggested += value;
           remove => CommandManager.RequerySuggested -= value;
       }
      

      這里出現了一個CommandManager

      WPF 中的 CommandManager 是一個幫助類,位于System.Windows.Input命名空間。它并不負責“執行命令”,而是為整個命令系統(RoutedCommand / RoutedUICommand)提供基礎支撐,核心職責可以概括為四類:

      1、處理路由命令的 4 個附加事件

      CommandManager 預定義了 4 個 static 的 RoutedEvent,都是附加事件,所有 UIElement 都可以通過它們監聽或引發命令相關路由事件:

      附加事件 觸發時機 典型用途
      PreviewCanExecuteEvent 準備詢問某命令能否執行時觸發(隧道) 用于全局或父級攔截“能否執行”判斷
      CanExecuteEvent 同上,但為冒泡階段 本地邏輯判斷命令當前是否可用
      PreviewExecutedEvent 準備執行命令時觸發(隧道) 做執行前的統一攔截,例如日志、撤銷棧
      ExecutedEvent 同上,但為冒泡階段 實際執行業務邏輯(如 Save、Cut、Paste)

      這里出現了隧道冒泡兩個概念,該如何理解呢?

      在 WPF 路由事件體系中,隧道(Tunneling)冒泡(Bubbling)是指事件在可視化樹上傳遞的兩個方向,想象成“從上到下”還是“從下到上”即可。與命令系統結合時,理解這兩個方向就等于知道“誰先被通知”、“誰可以打斷誰”。

      樹結構:

      Window → Grid → StackPanel → Button

      這是典型的一棵可視化樹。

      隧道(Preview……)→ 從根向葉

      PreviewCanExecute / PreviewExecuted 這類以 Preview 開頭的事件,先由 Window 收到,再依次 Grid、StackPanel,最后才到達實際聲明 CommandBinding / 聲明 InputBindings 的那個 Button。

      作用:你可以在高層(例如 Window 一級)攔截事件,做“統一處理”或“統一否決”,比如給所有按鈕加日志、在全局禁止某些快捷鍵等。只要沿途某級標記 e.Handled = true,它就終止繼續向下傳遞。

      冒泡(……無 Preview)→ 從葉向根

      隧道階段結束后如果仍然 Handled == false,則進入冒泡階段。方向反過來:Button 先收到,再依次 StackPanel、Grid、Window。

      作用:一般在最具體元素(Button)里決定命令是否可用或執行,而父容器只做輔助行為,如更新狀態欄、刷新菜單對勾等。同樣可以用 e.Handled = true 阻止再向上傳。

      2、提供 4 組 Add xxx Handler / Remove xxx Handler 的快捷方法

      這些只是對 UIElement.AddHandler、RemoveHandler 的二次封裝,方便掛接或注銷上述 4 種附加事件,省去記憶事件標識符或強制轉換類型的麻煩。

      3、維護全局命令“有效性”通知:RequerySuggested

      事件定義:public static event EventHandler RequerySuggested;

      作用:當系統條件變化(鍵盤焦點變化、文本被修改、網絡狀態變更等)時,所有命令需要重新詢問“是否能執行”。WPF 內部的按鈕、菜單項等在訂閱此事件后,就會再次調用 ICommand.CanExecute 來決定 IsEnabled。

      手動觸發:CommandManager.InvalidateRequerySuggested(); 會立即引發該事件,從而強制刷新所有綁定命令的可執行狀態。

      4、提供“類級別” CommandBinding / InputBinding 注冊

      RegisterClassCommandBinding(Type type, CommandBinding commandBinding)

      為指定類型(而不僅是某個實例)注冊 CommandBinding,在所有實例共享同一組綁定邏輯,等同于在靜態構造函數里寫:

      CommandManager.RegisterClassCommandBinding(
            typeof(MyControl),
            new CommandBinding(ApplicationCommands.Save, OnSaveExecuted, OnSaveCanExecute));
      RegisterClassInputBinding(Type type, InputBinding inputBinding)
      

      同樣道理,為某個控件類統一注冊快捷鍵:

      CommandManager.RegisterClassInputBinding(
            typeof(MyWindow),
            new KeyBinding(ApplicationCommands.Save, Key.S, ModifierKeys.Control));
      

      現在來看看整體流程:

        <Button Content="Say Hello" 
                Command="{Binding SayHelloCommand}"
                Height="30"
                FontSize="14"/>
      

      在View中綁定這個命令。

      剛開始這個命令不可執行:

      是因為在ViewModel中是這樣寫的,首先在構造函數中這樣寫:

        public ShellViewModel()
        {
            SayHelloCommand = new RelayCommand(
                execute: _ => ShowHelloMessage(),
                canExecute: _ => CanSayHello
            );
        }
      

      其中控制是否能執行的,設置了一個屬性來管理:

       public bool CanSayHello => !string.IsNullOrEmpty(Name);
      

      命令執行的方法為:

        private void ShowHelloMessage()
        {
            MessageBox.Show($"Hello, {Name}", "Hello, Native WPF", MessageBoxButton.OK, MessageBoxImage.Information);
        }
      

      剛開始Name屬性為空,所以CanSayHello為false,所以命令不能執行。

      為什么輸入東西就可以變成執行了呢?

       public string Name
       {
           get => _name;
           set
           {
               if (SetProperty(ref _name, value))
               {
                   ((RelayCommand)SayHelloCommand).RaiseCanExecuteChanged();
               }
           }
       }
      

      RelayCommand中有一個RaiseCanExecuteChanged方法:

         public void RaiseCanExecuteChanged()
         {
             CommandManager.InvalidateRequerySuggested();
         }
      

      CommandManager.InvalidateRequerySuggested(); 是 WPF 中用于強制刷新命令的可執行狀態的方法。所有綁定了ICommand的控件(如 Button、MenuItem 等)馬上重新評估自己的 CanExecute 狀態。

      然后因為Name不為空,CanSayHello為True,這個命令就可以執行了。

      點擊按鈕就會觸發RelayCommand中的Execute方法:

      在ViewModel的構造函數中。實例化了一個RelayCommand對象,并且將_ => ShowHelloMessage()這個委托賦值給了execute,所以觸發命令之后就會執行ShowHelloMessage方法。

      以上就是使用WPF原生的方法實現的一個使用命令的例子。

      posted @ 2025-08-20 11:20  mingupupup  閱讀(417)  評論(3)    收藏  舉報
      主站蜘蛛池模板: 国产精品呻吟一区二区三区| 亚洲熟女片嫩草影院| 夜夜添狠狠添高潮出水| 国产精品自在自线免费观看| 亚洲精品国男人在线视频| 内射老阿姨1区2区3区4区| 久久精品国产九一九九九| 无码人妻aⅴ一区二区三区蜜桃| 在线无码午夜福利高潮视频| www免费视频com| 欧美福利电影A在线播放| 精品国产伦理国产无遮挡| 久久五月丁香激情综合| 亚洲另类激情专区小说图片| jk白丝喷浆| 国产亚洲精品第一综合另类| 人妻少妇偷人无码视频| 综合久久av一区二区三区| 97香蕉碰碰人妻国产欧美| 久久热在线视频精品视频| 亚洲熟妇自偷自拍另欧美| 亚洲成人av在线高清| 国产精品国产三级国产试看| 亚洲国产精品一区二区视频| 狠狠色丁香婷婷综合尤物| 日韩精品一二三黄色一级| 激情自拍校园春色中文| 动漫AV纯肉无码AV电影网| 高清在线一区二区三区视频| 扒开粉嫩的小缝隙喷白浆视频| 成年男女免费视频网站| 久久精产国品一二三产品| 久久精品国产福利一区二区| 色婷婷日日躁夜夜躁| 内射视频福利在线观看| 男女扒开双腿猛进入爽爽免费看| 国产亚洲精品久久久久蜜臀| 粉嫩av蜜臀一区二区三区| 欧美人与动欧交视频| 国产精品剧情亚洲二区| 日韩有码中文字幕国产|