WPF MVVM入門系列教程(五、命令和用戶輸入)

?🧭 WPF MVVM入門系列教程

  • 一、MVVM模式介紹
  • 二、依賴屬性
  • 三、數據綁定
  • 四、ViewModel
  • 五、命令和用戶輸入
  • 六、ViewModel案例演示

WPF中的命令模型

在WPF中,我們可以使用事件來響應鼠標和鍵盤動作。

但使用事件會具備一定的局限性,例如:我想通過鍵盤快捷鍵觸發事件、或者在某個時刻禁用事件。

如果使用代碼去編寫這些控制邏輯,會變得非常枯燥。因此WPF提供了命令模型

命令具有多個用途。

第一個用途是分隔語義和從執行命令的邏輯調用命令的對象。

這可使多個不同的源調用同一命令邏輯,并且可針對不同目標自定義命令邏輯。

例如,許多應用程序中均有的編輯操作“復制”、“剪切”和“粘貼”若通過使用命令來實現,那么可通過使用不同的用戶操作來調用它們。

應用程序可允許用戶通過單擊按鈕、選擇菜單中的項或使用組合鍵(例如 Ctrl+X)來剪切所選對象或文本。

通過使用命令,可將每種類型的用戶操作綁定到相同邏輯。

命令的另一用途是指示操作是否可用。

繼續以剪切對象或文本為例,此操作只有在選擇了內容時才會發生作用。

如果用戶在未選擇任何內容的情況下嘗試剪切對象或文本,則不會發生任何操作。

為了向用戶指示這一點,許多應用程序通過禁用按鈕和菜單項來告知用戶是否可以執行某操作。

命令可以通過實現CanExecute方法來指示操作是否可行。 按鈕可以訂閱?CanExecuteChanged事件,如果CanExecute返回?false?則禁用,如果CanExecute返回?true?則啟用。

通俗點來說,命令模型就是事件的“升級版本”,

它可以讓多個不同的源調用同一個邏輯

例如我一有個打印功能,我們將它封裝成PrintDocument,當在菜單選擇時按鈕點擊時快捷鍵按下時,我們都去執行這個功能。

它還可以控制這個功能是否可以被執行,例如,我當前未選中要打印的文檔,我設置CanExecute方法返回false,打印功能是無法被執行的。當選中了要打印的文檔,設置CanExecute方法返回true,這時候,打印功能又可以被執行了。

WPF 命令中的四個主要概念

WPF中的命令模型可分解為四個主要概念:命令、命令源、命令目標和命令綁定:

  • 命令要執行的操作。

  • 命令源調用命令的對象。

  • 命令目標:在其上執行命令的對象。

  • 命令綁定將命令邏輯映射到命令的對象。

命令

命令表示應用程序任務,并且跟蹤任務是否能夠被執行。然而,命令實際上不包含執行應用程序任務的代碼。

命令綁定

每個命令綁定針對用戶界面的具體區域,將命令連接到相關的應用程序邏輯。這種分解的設計是非常重要的,因為單個命令可用于應用程序中的多個地方,并且在每個地方具有不同的意義。為處理這一問題,需要將同一命令與不同的命令綁定。

命令源

命令源觸發命令。例如,Menultem和?Button都是命令源。單擊它們都會執行綁定命令。

命令目標

命令目標是在其中執行命令的元素。例如,Paste命令可在TextBox控件中插入文本,而OpenFile命令可在?DocumentViewer中打開文檔。根據命令的本質,目標可能很重要,也可能不重要。

注意:如果對于這些基礎概念理解起來有困難,可以先暫時跳過,直接學習后面的部分。等掌握以后,再回頭來看這些基礎概念。

在MVVM中使用命令的快速示例

在前面的文章中,我們學習了數據綁定,可以在DataContext中,取到界面上的值。如果我們需要在DataContext(ViewModel層)去響應控件的事件,就需要用到Command

假設有如下界面,我們想在點擊按鈕后,彈框輸出文本框的值。

1 <StackPanel>
2     <Label Content="輸入"></Label>
3     <TextBox Name="tbox"></TextBox>
4 
5     <Button Content="獲取輸入"></Button>
6 </StackPanel>

在WPF的基于事件模式的開發中,一般會響應按鈕的Click事件

1 <Button Content="獲取輸入" Click="Button_Click"></Button>

然后在后臺代碼中對事件進行處理

1         private void Button_Click(object sender, RoutedEventArgs e)
2         {
3             MessageBox.Show(this.tbox.Text);
4         }

在MVVM模式開發中,我們會直接綁定到一個命令

1  <StackPanel>
2      <Label Content="輸入"></Label>
3      <TextBox Text="{Binding InputText}"></TextBox>
4 
5      <Button Content="獲取輸入" Command="{Binding GetInputCommand}"></Button>
6  </StackPanel>

ViewModel中對命令進行處理

 1 public class MainWindowViewModel 2 {3     public ICommand GetInputCommand { get; private set; }4 5     public MainWindowViewModel()6     {7         GetInputCommand = new RelayCommand(GetInput);8     }9 
10     public void GetInput()
11     {
12         MessageBox.Show(InputText);
13     }
14 }

運行效果

使用MVVM模式進行開發時,從View層ViewModel層獲取用戶輸入是MVVM開發的核心知識點之一。

接下來我們會詳細介紹這一點。首先我們需要了解在MVVM中如何自定義命令。

ICommand接口

WPF命令模型的核心是System.Windows.Input.ICommand接口,該接口定義了命令的工作原理。

定義如下:

它包含了兩個方法和一個事件

 1     //2     // 摘要: 3     //     定義一個命令4     public interface ICommand5     {6         //7         // 摘要:8         //    當命令執行條件發生更改時觸發9         event EventHandler? CanExecuteChanged;
10 
11  
12         //
13         // 摘要:
14         //    定義確定命令是否可以在其當前狀態下執行的方法。 
15         //
16         // 參數:
17         //   parameter:
18         //    命令使用的數據。如果命令不需要傳遞數據,可為空
19         //
20         // 返回結果:
21         //     true - 命令能被執行 false-命令不能被執行
22         //
23         bool CanExecute(object? parameter); 
24 
25         // 摘要:
26         //     定義調用命令時要調用的方法。
27         //
28         // 參數:
29         //   parameter:
30         //     
31         //   命令使用的數據。如果命令不需要傳遞數據,則可以將此對象設置為null。
32         void Execute(object? parameter);
33     }

以我們前面的GetInputCommand邏輯為為例,

Execute()方法將包含彈出文本框文本的邏輯。

CanExecute()方法返回命令的狀態-如果命令可用,就返回true;如果不可用,就返回False。

ExecuteCanExecute方法都接受一個附加的參數對象,可以使用該對象傳遞所需要的任何附加信息。

當命令狀態改變時引發CanExecuteChanged事件。對于使用命令的任何控件,這是指示信號,

表示它們應當調用CanExecute()方法檢查命令的狀態。

通過使用該事件,當命令可用時,命令源(如?Button或?Menultem)可自動啟用自身;當命令不可用時,禁用自身。

RelayCommand

在MVVM模式中使用命令時,我們需要自定義命令類RelayCommand,該類實例了ICommand接口。

定義如下

 1  /// <summary>2  /// 一種命令,其唯一目的是通過調用委托將其功能傳遞給其他對象。3  /// CanExecute方法的默認返回值為"true"。4  /// 此類不允許在Execute和CanExecute回調方法中接受命令參數。5  /// 目前只用于演示,所以不增加支持傳遞參數的版本6  /// 正式使用時,會使用Prism/CommunityToolkit.MVVM等包7  /// </summary>8  public class RelayCommand : ICommand9  {
10      /// <summary>
11      /// 命令綁定的回調
12      /// </summary>
13      private readonly Action _execute;
14 
15      /// <summary>
16      /// 命令是否可以被執行綁定的回調
17      /// </summary>
18      private readonly Func<bool> _canExecute;
19 
20      /// <summary>
21      /// 當命令執行條件發生更改時觸發
22      /// </summary>
23      public event EventHandler CanExecuteChanged
24      {
25          add
26          {
27              if (_canExecute != null)
28              {
29                  CommandManager.RequerySuggested += value;
30              }
31          }
32          remove
33          {
34              if (_canExecute != null)
35              {
36                  CommandManager.RequerySuggested -= value;
37              }
38          }
39      }
40 
41      /// <summary>
42      ///  實例化RelayCommand
43      /// </summary>
44      /// <param name="execute"></param>
45      public RelayCommand(Action execute)
46          : this(execute, null)
47      {
48      }
49 
50      /// <summary>
51      /// 實例化RelayCommand
52      /// </summary>
53      /// <param name="execute">命令綁定的回調</param>
54      /// <param name="canExecute">命令是否可以被執行的回調</param>
55      public RelayCommand(Action execute, Func<bool> canExecute)
56      {
57          if (execute == null)
58          {
59              throw new ArgumentNullException("execute");
60          }
61 
62          _execute = execute;
63          _canExecute = canExecute;
64      }
65 
66      /// <summary>
67      ///  觸發CanExecuteChanged事件.
68      /// </summary>
69      public void RaiseCanExecuteChanged()
70      {
71          CommandManager.InvalidateRequerySuggested();
72      }
73 
74      /// <summary>
75      /// 定義確定命令是否可以在其當前狀態下執行的方法。
76      /// </summary>
77      /// <param name="parameter"></param>
78      /// <returns></returns>
79      public bool CanExecute(object parameter)
80      {
81          return _canExecute == null || _canExecute();
82      }
83 
84      /// <summary>
85      /// 定義調用命令時要調用的方法。
86      /// </summary>
87      /// <param name="parameter"></param>
88      public void Execute(object parameter)
89      {
90          _execute();
91      }
92  }

在類的內部我們定義了兩個委托:?Action _executeFunc _canExecute,并通過構造函數傳遞,_execute在命令被執行時調用,_canExecute在判斷命令是否可以被執行時調用。

使用RelayCommand

我們在界面上放置一個按鈕,并綁定GetTimeCommand

MainWindow.xaml

1 <Window x:Class="UseRelayCommand.MainWindow"
2         xmlns:local="clr-namespace:UseRelayCommand"
3         mc:Ignorable="d"
4         Title="MainWindow" Height="450" Width="800">
5     <StackPanel>
6         <Button Content="獲取當前時間" Command="{Binding GetTimeCommand}"></Button>
7     </StackPanel>
8 </Window>

創建ViewModel

MainWindowViewModel.cs

 1     public class MainWindowViewModel2     {3         /// <summary>4         /// 獲取時間5         /// </summary>6         public ICommand GetTimeCommand { get; private set; }7 8         public MainWindowViewModel()9         {
10             GetTimeCommand = new RelayCommand(GetTime);
11         }
12 
13         private void GetTime()
14         {
15             MessageBox.Show(DateTime.Now.ToString());
16         }
17     }

將ViewModel綁定到DataContext

1     public partial class MainWindow : Window
2     {
3         public MainWindow()
4         {
5             InitializeComponent();
6             this.DataContext = new MainWindowViewModel();
7         }
8     }

運行后,點擊按鈕,就可以看到消息框顯示當前時間。

我們將這個例子進行升級,再增加一個復選框,只有界面鉤選了復選框,才能執行GetTimeCommand

在創建GetTimeCommand時,我們傳遞一個Func類型的回調,而這個回調就是返回界面上復選框綁定的值。

MainWindow.xaml

1 <Window x:Class="UseRelayCommandCanExecute.MainWindow"
2         mc:Ignorable="d"
3         Title="MainWindow" Height="450" Width="800">
4     <StackPanel>
5         <CheckBox Content="是否允許獲取時間" IsChecked="{Binding CanGetTime}"></CheckBox>
6         <Button Content="獲取當前時間" Command="{Binding GetTimeCommand}"></Button>
7     </StackPanel>
8 </Window>

MainWindowViewModel

 1 public class MainWindowViewModel : INotifyPropertyChanged2 {3     private bool canGetTime;4 5     public bool CanGetTime6     {7         get => canGetTime;8         set9         {
10             canGetTime = value;
11             PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CanGetTime"));
12         }
13     }
14 
15     /// <summary>
16     /// 獲取時間
17     /// </summary>
18     public ICommand GetTimeCommand { get; private set; }
19 
20     public MainWindowViewModel()
21     {
22         GetTimeCommand = new RelayCommand(GetTime, CanGetTimeExecute);
23     }
24 
25     /// <summary>
26     /// GetTimeCommand是否可以被執行的回調函數
27     /// </summary>
28     /// <returns></returns>
29     public bool CanGetTimeExecute()
30     {
31         //返回CanGetTime變量,該變量綁定到界面上的CheckBox
32         return CanGetTime;
33     }
34 
35     public event PropertyChangedEventHandler PropertyChanged;
36 
37     private void GetTime()
38     {
39         MessageBox.Show(DateTime.Now.ToString());
40     }
41 }

運行效果如下:

使用CommunityToolkit.MVVM包中的命令

在前面的示例中,我們自己封裝了一個RelayCommand,在正式場景中,一般還是推薦使用三方MVVM包中帶的命令。

本文以CommunityToolkit.MVVM包中的RelayCommand進行演示。

首先我們看一下這個包里的RelayCommand是如何封裝的

跟前面的寫法基本差不多,因為這里最核心的還是ICommand接口。

 1 public sealed class RelayCommand : IRelayCommand, ICommand2 {3 4     private readonly Action execute;5 6     private readonly Func<bool>? canExecute;7 8     public event EventHandler? CanExecuteChanged;9 
10     public RelayCommand(Action execute)
11     {
12         ArgumentNullException.ThrowIfNull(execute, "execute");
13         this.execute = execute;
14     }
15 
16 
17     public RelayCommand(Action execute, Func<bool> canExecute)
18     {
19         ArgumentNullException.ThrowIfNull(execute, "execute");
20         ArgumentNullException.ThrowIfNull(canExecute, "canExecute");
21         this.execute = execute;
22         this.canExecute = canExecute;
23     }
24 
25     public void NotifyCanExecuteChanged()
26     {
27         this.CanExecuteChanged?.Invoke(this, EventArgs.Empty);
28     }
29 
30     [MethodImpl(MethodImplOptions.AggressiveInlining)]
31     public bool CanExecute(object? parameter)
32     {
33         return canExecute?.Invoke() ?? true;
34     }
35 
36     public void Execute(object? parameter)
37     {
38         execute();
39     }
40 }

使用方法跟前面自己封裝的RelayCommand也是一樣的。

MainWindow.xaml

1 <Window x:Class="UseRelayCommand.MainWindow"
2         Title="MainWindow" Height="450" Width="800">
3     <StackPanel>
4         <Button Content="獲取當前時間" Command="{Binding GetTimeCommand}"></Button>
5     </StackPanel>
6 </Window>

MainWindowViewModel.cs

 1     public class MainWindowViewModel2     {3         /// <summary>4         /// 獲取時間5         /// </summary>6         public ICommand GetTimeCommand { get; private set; }7 8         public MainWindowViewModel()9         {
10             GetTimeCommand = new RelayCommand(GetTime);
11         }
12 
13         private void GetTime()
14         {
15             MessageBox.Show(DateTime.Now.ToString());
16         }
17     }

綁定數據上下文

1     public partial class MainWindow : Window
2     {
3         public MainWindow()
4         {
5             InitializeComponent();
6             this.DataContext = new MainWindowViewModel();
7         }
8     }

運行效果

傳遞命令參數

在前面我們自己封裝RelayCommand時,只提供了基礎的命令功能,并不具備參數傳遞的功能。

在很多場景下,我們需要將參數傳遞到命令里。所以我們需要一個帶參數的泛型RelayCommand版本。這個泛型就是我們要傳遞的參數。

這里就不自行封裝了,我們直接使用CommunityToolkit.MVVM包中的RelayCommand版本。感興趣的小伙伴可以訪問以下鏈接閱讀源碼:

dotnet/src/CommunityToolkit.Mvvm/Input/RelayCommand{T}.cs at main · CommunityToolkit/dotnet · GitHub

在使用RelayCommand命令時,我們可以根據需要傳遞的參數類型,使用對應的泛型參數。同時,命令綁定的回調函數也需要傳遞對應類型的參數。

例如我想傳遞一個string類型:

1 RelayCommand<string> MyCommand {get;set;}

它綁定的回調函數也需要增加string類型的參數

1 void MyFunction(string parameter)
2 {
3     
4 }

下面我們演示一下如何向命令中傳遞參數。

我們在界面上放置3個按鈕,分別設置為按鈕1、2、3

然后這三個按鈕都綁定到ShowMessageCommand,并通過CommandParameter屬性將按參數傳遞到ShowMessageCommand

MainWindow.xaml

 1 <Window x:Class="PassParameterToCommand.MainWindow"2         mc:Ignorable="d"3         Title="MainWindow" Height="450" Width="800">4     <StackPanel Orientation="Horizontal">5         <!--可以直接指定命令參數-->6         <Button Content="按鈕1" Command="{Binding ShowMessageCommand}" CommandParameter="按鈕1" VerticalAlignment="Center" Width="128" Height="28" Margin="10"></Button>7         <!--也可以綁定自身-->8         <Button Content="按鈕2" Command="{Binding ShowMessageCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self},Path=Content}" VerticalAlignment="Center" Width="128" Height="28" Margin="10"></Button>9         <!--也可以綁定到指定控件的指定屬性-->
10         <Button Content="按鈕3" Name="btn3" Command="{Binding ShowMessageCommand}" CommandParameter="{Binding ElementName=btn3,Path=Content}" VerticalAlignment="Center" Width="128" Height="28" Margin="10"></Button>
11     </StackPanel>
12 </Window>

MainWindowViewModel

 1     public class MainWindowViewModel : ObservableObject2     {3         public RelayCommand<string> ShowMessageCommand { get; set; }4 5         public MainWindowViewModel()6         {7             ShowMessageCommand = new RelayCommand<string>(ShowMessage);8         }9 
10         private void ShowMessage(string? obj)
11         {
12             MessageBox.Show("消息來自-" + obj);
13         }
14     }

綁定到數據上下文

1   public partial class MainWindow : Window
2   {
3       public MainWindow()
4       {
5           InitializeComponent();
6           this.DataContext = new MainWindowViewModel();
7       }
8   }

運行效果:

將任意事件綁定到命令

在前面的示例中,我們大量使用了ButtonCommand屬性來進行命令綁定,Button.Command屬性的作用是獲取或設置按下此按鈕時要調用的命令。

在WPF中,具備Command屬性的的還有MenuItem控件。

但是對于沒有Command屬性的控件應該如何處理呢,又或者我想處理控件的其它事件呢,如選中項切換?

例如我有一個ListBox,我想在ListBox.SelectionChanged事件觸發的時候調用一個命令。

這里我們可以借助Microsoft XAML Behaviors包里面的EventTriggerInvokeCommandAction來實現。

EventTrigger是一種監聽源上指定事件并在事件觸發時觸發的觸發器,而InvokeCommandAction是在觸發器觸發時執行綁定命令的一種動作。

關于Microsoft XAML Behaviors的詳細使用可以參考我前面寫的文章:WPF中的Microsoft XAML Behaviors包功能詳解 - zhaotianff - 博客園

創建一個WPF工程,并使用nuget安裝Microsoft.Xaml.Behaviors.Wpf包和CommunityToolkit.Mvvm包

然后我們在界面上放置一個ListBox,將使用EventTriggerInvokeCommandActionSelectionChanged事件綁定到OnSelectionChangedCommand命令。

MainWindow.xaml

 1 <Window x:Class="BindingEventToCommand.MainWindow"2         xmlns:local="clr-namespace:BindingEventToCommand"3         xmlns:i="http://schemas.microsoft.com/xaml/behaviors"4         mc:Ignorable="d"5         Title="MainWindow" Height="450" Width="800">6     <Grid>7         <ListBox Name="listbox">8             <i:Interaction.Triggers>9                 <i:EventTrigger EventName="SelectionChanged">
10                     <i:InvokeCommandAction Command="{Binding OnSelectionChangedCommand}" CommandParameter="{Binding ElementName=listbox,Path=SelectedValue}"></i:InvokeCommandAction>
11                 </i:EventTrigger>
12             </i:Interaction.Triggers>
13             <ListBoxItem>1234</ListBoxItem>
14             <ListBoxItem>5678</ListBoxItem>
15             <ListBoxItem>9112</ListBoxItem>
16         </ListBox>
17     </Grid>
18 </Window>

MainWindowViewModel.cs

 1     public class MainWindowViewModel : ObservableObject2     {3         public RelayCommand<object> OnSelectionChangedCommand { get; set; }4 5         public MainWindowViewModel()6         {7             OnSelectionChangedCommand = new RelayCommand<object>(OnSelectionChanged);8         }9 
10         private void OnSelectionChanged(object? obj)
11         {
12             var listboxItem = obj as ListBoxItem;
13 
14             if(listboxItem != null)
15             {
16                 MessageBox.Show(listboxItem.Content.ToString());
17             }
18         }
19     }

綁定到數據上下文

1   public partial class MainWindow : Window
2   {
3       public MainWindow()
4       {
5           InitializeComponent();
6           this.DataContext = new MainWindowViewModel();
7       }
8   }

運行效果

參考資料:

命令概述 - WPF .NET Framework | Microsoft Learn

示例代碼

WPF-MVVM-Beginner/5_CommandAndUserInput at main · zhaotianff/WPF-MVVM-Beginner · GitHub

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/904401.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/904401.shtml
英文地址,請注明出處:http://en.pswp.cn/news/904401.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

2025年01月09日德美醫療前端面試

目錄 vue2 的雙向綁定的原理vue3 的雙向綁定原理vue 的生命周期vue 子組件為何不能修改父組件的值js delete 刪除數組的某一個值會怎么樣vue 和 react 的 diff 算法什么是閉包原型鏈this指向 vue2 的雙向綁定的原理 以下是 Vue 2 雙向綁定的原理&#xff1a; 1. 核心概念 …

知識圖譜 + 大語言模型:打造更聰明、更可靠的AI大腦 —— 探索 GraphRAG 中文優化與可視化實踐

大語言模型&#xff08;LLMs&#xff09;無疑是近年來人工智能領域最耀眼的明星。它們強大的自然語言理解和生成能力&#xff0c;在文本創作、代碼生成、對話交互等眾多領域展現了驚人的潛力。然而&#xff0c;當前的 LLMs 并非完美無缺&#xff0c;它們常常面臨著“幻覺”&…

【uniapp】在UniApp中檢測手機是否安裝了某個應用

1. 使用plus.runtime.isApplicationExist&#xff08;僅限App端&#xff09; // 判斷應用是否安裝 function checkAppInstalled(packageName) {if (uni.getSystemInfoSync().platform android || uni.getSystemInfoSync().platform ios) {// 僅App端可用if (typeof plus ! u…

使用 Vue + Axios 構建與后端交互的高效接口調用方案

使用 Vue Axios 構建與后端交互的高效接口調用方案 在 Vue 前端開發中&#xff0c;與后端接口的數據交互是非常核心的部分。而 Axios 是 Vue 項目中最常用的 HTTP 客戶端&#xff0c;具備基于 Promise、攔截器、自定義實例等諸多優勢。 本篇將深入介紹如何基于 Vue 搭配 Axi…

RN學習筆記 ?

太無聊了最近&#xff0c;找點事做&#xff0c;學一下RN豐富一下技術棧&#x1fae1;。但是開發APP除了RN&#xff0c;還有一種選擇就是WebView&#xff0c;但是基于WebView的APP的性能被普遍認為不如RN&#xff0c;因為WebView本質上是一個容器&#xff0c;用于在應用中嵌入網…

聊天助手提示詞調優案例

一、背景 今天有粉絲說自己的聊天助手提示詞輸出的效果不好&#xff0c;輸出的內容不是太呆板就是太浮夸&#xff0c;希望更像真人一樣。 本文介紹幾個調優方法&#xff0c;希望對大家有啟發。 二、調優 《系統掌握大語言模型提示詞 - 從理論到實踐》提示詞小冊中介紹了很多…

5.6 react組件化開發基礎

react 組件開發基礎 組件分類與組件使用 組件傳參 父傳子 【函數數據傳值 實參 形參對應關系】 子傳父 插槽 透傳 useContext 上下文&#xff08;作用域&#xff09; 跨層級調用方法 通過子組件的實例對象useRef 直接調用子組件的方法 和數據 狀態管理&#xff08;非常多…

【SF順豐】順豐開放平臺API對接(Java對接篇)

對接前置篇&#xff1a; 【SF順豐】順豐開放平臺API對接&#xff08;注冊、API測試篇&#xff09;_順豐api接口對接指南-CSDN博客 1.實現效果展示 2.SF順豐開放平臺&#xff0c;JDK資源下載。 下載地址&#xff1a;順豐開放平臺 3.將下載的JDK放入項目中。 4.將JDK資源引入p…

我用cursor 搭建了臨時郵箱服務-Temp Mail 365

用業余時間搭建了一個臨時郵箱&#xff0c;對于后端程序員出身的我&#xff0c;對前端了解的不太多&#xff0c;有了cursor的幫助&#xff0c;補齊了自己的短板&#xff0c;搭建了這個服務&#xff0c;下面對臨時郵箱架構設計與安全性做一個分析。 https://temp-mail-365.com 臨…

破解工業3D可視化困局,HOOPS Visualize助力高效跨平臺協作與交互!

一、當前3D可視化面臨的痛點 &#xff08;1&#xff09;性能瓶頸 現有的許多3D可視化工具在處理大型復雜模型時往往力不從心。例如在航空航天、汽車制造等高端制造業&#xff0c;動輒涉及數以億計的三角面片和海量的紋理細節。這些超大規模的模型在渲染時常常出現卡頓、延遲&…

1、Kafka與消息隊列核心原理詳解

消息隊列&#xff08;Message Queue, MQ&#xff09;作為現代分布式系統的基礎組件&#xff0c;極大提升了系統的解耦、異步處理和削峰能力。本文以Kafka為例&#xff0c;系統梳理消息隊列的核心原理、架構細節及實際應用。 Kafka 基礎架構及術語關系圖 術語簡要說明 Produce…

2025年北京市職工職業技能大賽第六屆信息通信行業網絡安全技能大賽初賽-wp

- -考試當場沒做出來 后面做的 misc ? cd misc ? ls num.docx num.zip ? unzip num.docx Archive: num.docxinflating: [Content_Types].xmlinflating: _rels/.relsinflating: word/document.xmlinflating: word/_rels/document.xml.relsextracting: word/media/image1.jp…

JavaScript 到命令和控制 (C2) 服務器惡意軟件分析及防御

攻擊始于一個經過混淆的JavaScript文件,該文件從開源服務中獲取編碼字符串以執行PowerShell腳本。然后,該腳本從一個IP地址和一個URL縮短器下載一個JPG圖像和一個文本文件,這兩個文件都包含使用隱寫術嵌入的惡意MZ DOS可執行文件。這些有效載荷一旦執行,就會部署Stealer惡意…

【計網】ipconfig、ping、arp、tracert

目錄 ipconfig ping arp tracert cmd ipconfig ipcofig -all IPv4 物理地址 ping 檢測網絡連通情況&#xff0c;分析網絡速度 根據域名得到服務器IP 根據TTL判斷對方所使用的操作系統以及數據包經過路由器數量 byte數據包大小 time響應時間 TTLDNS記錄在DNS服務器上存在…

WiFi那些事兒(八)——802.11n

目錄 802.11n 技術簡介與測試項 一、802.11n 技術簡介 &#xff08;一&#xff09;標準概述 &#xff08;二&#xff09;關鍵技術特性 1. MIMO&#xff08;多輸入多輸出&#xff09;技術 2. 信道綁定&#xff08;Channel Bonding&#xff09; 3. 幀聚合&#xff08;Fram…

碼蹄集——直角坐標到極坐標的轉換、射線、線段

目錄 MT1052 直角坐標到極坐標的轉換 MT1066 射線 MT1067 線段 MT1052 直角坐標到極坐標的轉換 思路&#xff1a; arctan()在c中是atan()&#xff0c;結果是弧度要轉換為度&#xff0c;即乘與180/PI 拓展&#xff1a;cos()、sin()在c代碼中表示方式不變 #include<bits/…

深入解析 Linux/Unix 通信機制:從原理到觀測實踐

深入解析 Linux/Unix 通信機制&#xff1a;從原理到觀測實踐 配圖建議&#xff1a;Linux系統架構與通信機制全景示意圖 一、開篇&#xff1a;理解“一切皆文件”的哲學 Unix/Linux 操作系統的核心靈魂在于其獨特的設計哲學。當 Dennis Ritchie 和 Ken Thompson 在貝爾實驗室開…

spring上傳文件添加水印

1、實現 MultipartFile package com.pojo.common.core.domain;import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream;import org.springframework.lang.Nullable; import org.springframework.util.Assert; im…

嵌入式MCU語音識別算法及實現方案

在嵌入式MCU&#xff08;微控制器單元&#xff09;中實現語音識別&#xff0c;由于資源限制&#xff08;如處理能力、內存、功耗等&#xff09;&#xff0c;通常需要輕量級算法和優化技術。以下是常見的語音識別算法及實現方案&#xff1a; 一、傳統語音識別算法 動態時間規整&…

【論文閱讀】DETR+Deformable DETR

可變形注意力是目前transformer結構中經常使用的一種注意力機制&#xff0c;最近補了一下這類注意力的論文&#xff0c;提出可變形注意力的論文叫Deformable DETR&#xff0c;是在DETR的基礎上進行的改進&#xff0c;所以順帶著把原本的DETR也看了一下。 一、DETR DETR本身是…