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.mzph.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本身是…