WPF/C#:理解與實現WPF中的MVVM模式

MVVM模式的介紹

MVVM(Model-View-ViewModel)是一種設計模式,特別適用于WPF(Windows Presentation Foundation)等XAML-based的應用程序開發。MVVM模式主要包含三個部分:Model(模型)、View(視圖)和ViewModel(視圖模型)。

  1. Model(模型):模型代表的是業務邏輯和數據。它包含了應用程序中用于處理的核心數據對象。模型通常包含業務規則、數據訪問和存儲邏輯。
  2. View(視圖):視圖是用戶看到和與之交互的界面。在WPF中,視圖通常由XAML定義,并且包含各種用戶界面元素,如按鈕、文本框、列表等。
  3. ViewModel(視圖模型):視圖模型是視圖的抽象,它包含視圖所需的所有數據和命令。視圖模型通過實現INotifyPropertyChanged接口和使用ICommand對象,將視圖的狀態和行為抽象化,從而實現了視圖和模型的解耦。

MVVM模式的主要優點是分離了視圖和模型,使得視圖和業務邏輯之間的依賴性降低,提高了代碼的可維護性和可測試性。此外,通過數據綁定和命令綁定,MVVM模式可以減少大量的樣板代碼,使得代碼更加簡潔和易于理解。

image-20240527095704838

不使用MVVM模式的例子

要真正理解為什么要使用MVVM,使用MVVM有什么好處,肯定要與不使用MVVM的情況進行對比。在Winform中我們使用了事件驅動編程,同樣在WPF中我們也可以使用事件驅動編程。

Windows Forms(WinForms)是一種基于事件驅動的圖形用戶界面(GUI)框架。在WinForms中,用戶與應用程序的交互主要通過事件來驅動。

事件驅動編程是一種編程范式,其中程序的執行流程由外部事件(如用戶操作或系統事件)決定。在WinForms中,事件可以是用戶的各種操作,如點擊按鈕、選擇菜單項、輸入文本等,也可以是系統的事件,如窗口加載、大小改變等。

當一個事件發生時,會觸發與之關聯的事件處理器(Event Handler)。事件處理器是一個函數或方法,用于響應特定的事件。例如,當用戶點擊一個按鈕時,可以觸發一個事件處理器,執行一些特定的操作。

在WinForms中,你可以為各種控件添加事件處理器,以響應用戶的操作。這種事件驅動的方式使得你可以很容易地創建交互式的GUI應用程序,而無需關心程序的執行流程。

事件驅動的簡圖如下圖所示:

image-20240527100814935

  1. 事件源(Event Source):事件源是產生事件的對象。在WinForms中,事件源通常是用戶界面元素,如按鈕、文本框、菜單項等。當用戶與這些元素進行交互(如點擊按鈕、輸入文本等)時,這些元素就會產生相應的事件。
  2. 事件(Event):事件是由事件源產生的一個信號,表示某種特定的事情已經發生。例如,當用戶點擊一個按鈕時,按鈕就會產生一個Click事件。事件通常包含一些關于該事件的信息,例如事件發生的時間、事件的源對象等。
  3. 事件處理器(Event Handler):事件處理器是一個函數或方法,用于響應特定的事件。當一個事件發生時,與該事件關聯的事件處理器就會被調用。在事件處理器中,你可以編寫代碼來定義當事件發生時應該執行的操作。例如,你可以在按鈕的Click事件處理器中編寫代碼,定義當用戶點擊按鈕時應該執行的操作。

現在我們通過一個例子在WPF中使用事件驅動編程。

首先看一下我們的示例xaml頁面:

 <Window x:Class="WPF_MVVM_Pattern.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WPF_MVVM_Pattern"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"Loaded="Window_Loaded"><StackPanel><ToolBar><Label Content="姓名:"></Label><TextBox x:Name="nameTextBox" Width="50"></TextBox><Label Content="郵箱:"></Label><TextBox x:Name="emailTextBox" Width="100"></TextBox><Button Content="添加"Click="AddUser"></Button></ToolBar><StackPanel><DataGrid x:Name="dataGrid1"></DataGrid></StackPanel></StackPanel>
</Window>

image-20240527141918081

使用了兩個事件,分別是窗體加載事件:

 Loaded="Window_Loaded"

與button點擊事件:

<Button Content="添加"Click="AddUser"></Button>

實現該操作與兩個類有關:

 public class User{public string? Name { get; set; }public string? Email { get; set; }}
 public static class UserManager{public static ObservableCollection<User> DataBaseUsers = new       ObservableCollection<User>(){new User() { Name = "小王", Email = "123@qq.com" },new User() { Name = "小紅", Email = "456@qq.com" },new User() { Name = "小五", Email = "789@qq.com" }};public static ObservableCollection<User> GetUsers(){return DataBaseUsers;}public static void AddUser(User user){DataBaseUsers.Add(user);}}

窗體加載事件處理程序:

 private void Window_Loaded(object sender, RoutedEventArgs e){dataGrid1.ItemsSource =  UserManager.GetUsers();}

"添加"按鈕點擊事件處理程序:

 private void AddUser(object sender, RoutedEventArgs e){User user = new User();user.Name = nameTextBox.Text;user.Email = emailTextBox.Text;UserManager.AddUser(user);MessageBox.Show("成功添加用戶!");}

實現的效果如下所示:

使用MVVM的例子

剛剛我們使用的是事件驅動編程,我們在winform開發中經常這樣干。對于一些小項目或者demo程序這樣做很方便,但是如果業務邏輯很多,這樣做就不好維護,因為UI與業務邏輯嚴重耦合了。

我們經常在cs文件中使用xaml中的元素,也就是經常在cs中引用xaml中的元素,如下所示:

image-20240527155929453

在C#代碼文件中直接引用XAML元素,會導致代碼與界面元素之間的耦合度增加,這是一種不良的編程實踐。以下是這種做法的一些潛在問題:

  1. 耦合度高:代碼與界面元素緊密耦合,這使得代碼更難以維護和重用。如果你更改了界面元素(例如更改了元素的名稱或類型),你可能需要修改引用這個元素的所有代碼。
  2. 測試困難:由于代碼直接依賴于界面元素,這使得單元測試變得困難。你可能需要創建一個界面元素的實例,或者使用復雜的模擬技術,才能測試這些代碼。
  3. 違反MVVM模式:在WPF中,推薦使用MVVM(Model-View-ViewModel)模式來組織代碼。在MVVM模式中,視圖(View)和模型(Model)之間的交互是通過視圖模型(ViewModel)來進行的,而不是直接在代碼中引用界面元素。

開始使用MVVM模式

RelayCommand

首先新建一個Commands文件夾,新建一個RelayComand類:

image-20240528084137467

RelayCommand如下:

public class RelayCommand : ICommand
{public event EventHandler? CanExecuteChanged;private Action<object> _Excute { get; set; }private Predicate<object> _CanExcute { get;set; }public RelayCommand(Action<object> ExcuteMethod, Predicate<object> CanExcuteMethod){_Excute = ExcuteMethod;_CanExcute = CanExcuteMethod;}public bool CanExecute(object? parameter){return _CanExcute(parameter);}public void Execute(object? parameter){_Excute(parameter);}
}

RelayCommand實現了ICommand接口。

先來介紹一下ICommand接口。

ICommand

在WPF(Windows Presentation Foundation)中,ICommand是一個接口,它定義了一種機制,用于在用戶界面(UI)中處理事件,這種機制與用戶界面的具體行為進行了解耦。這是實現MVVM(Model-View-ViewModel)設計模式的關鍵部分。

ICommand接口包含兩個方法和一個事件:

  • Execute(object parameter):當調用此命令時,應執行的操作。
  • CanExecute(object parameter):如果可以執行Execute方法,則返回true;否則返回false。這可以用于啟用或禁用控件,例如按鈕。
  • CanExecuteChanged事件:當CanExecute的返回值可能發生更改時,應引發此事件。

ICommand的結構圖如下所示:

image-20240528084534354

代碼如下所示:

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

現在再來看看RelayCommand

RelayCommand

RelayCommand是一種常用于WPF和MVVM模式的設計模式,它是一種特殊的命令類型。在MVVM模式中,RelayCommand允許將命令的處理邏輯從視圖模型中分離出來,使得視圖模型不需要知道命令的具體執行邏輯,從而實現了視圖模型和命令處理邏輯的解耦。

RelayCommand通常包含兩個主要部分:CanExecuteExecuteCanExecute是一個返回布爾值的函數,用于確定命令是否可以執行。Execute是一個執行命令的函數,當CanExecute返回true時,Execute將被調用。

這種設計模式使得你可以在不改變視圖模型的情況下,更改命令的處理邏輯,提高了代碼的可維護性和可重用性。

簡單理解就是RelayCommandICommand接口的一個常見實現,它允許你將ExecuteCanExecute的邏輯定義為委托,從而實現對命令的靈活處理。

在RelayCommand中我們定義了兩個委托:

private Action<object> _Excute { get; set; }private Predicate<object> _CanExcute { get;set; }

Action<object>是一個委托,它封裝了一個接受單個參數并且沒有返回值的方法。這個參數的類型是object

對應于這一部分:

image-20240528085200268

Predicate<object>是一個委托,它封裝了一個接受單個參數并返回一個bool值的方法。這個參數的類型是object

對應于這一部分:

image-20240528085237548

RelayCommand的構造函數為:

 public RelayCommand(Action<object> ExcuteMethod, Predicate<object> CanExcuteMethod){_Excute = ExcuteMethod;_CanExcute = CanExcuteMethod;}

現在去看看View—ViewModel

View—ViewModel

ViewModel是一個抽象,它代表了View的狀態和行為。ViewModel包含了View所需的數據,并提供了命令以響應View上的用戶操作。ViewModel不知道View的具體實現,它只知道如何提供View所需的狀態和行為。

ViewModel的主要職責包括:

  • 數據綁定:ViewModel提供了View所需的數據。這些數據通常是以屬性的形式提供的,當這些屬性的值改變時,ViewModel會通過實現INotifyPropertyChanged接口來通知View。
  • 命令綁定:ViewModel提供了命令以響應View上的用戶操作。這些命令通常是以ICommand接口的實現的形式提供的。
  • 視圖邏輯:ViewModel包含了View的邏輯,例如,決定何時顯示或隱藏某個元素,何時啟用或禁用某個按鈕等。

新建一個ViewModel文件夾,在該文件夾中新建一個MainViewModel類:

image-20240528093058019

目前寫的MainViewModel如下:

public class MainViewModel
{public ObservableCollection<User> Users { get; set; }public ICommand AddUserCommand { get; set; }public string? Name { get; set; }public string? Email { get; set; }public MainViewModel(){Users = UserManager.GetUsers();AddUserCommand = new RelayCommand(AddUser, CanAddUser);}private bool CanAddUser(object obj){return true;}private void AddUser(object obj){User user = new User();user.Name = Name;user.Email = Email;UserManager.AddUser(user);}
}

現在我們結合這張圖,理解View與ViewModel之間的關系:

image-20240528093349406

一個一個來理解,首先最重要的就是數據綁定。

現在View的xaml如下:

<Window x:Class="WPF_MVVM_Pattern.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:WPF_MVVM_Pattern"mc:Ignorable="d"Title="MainWindow" Height="450" Width="800"><StackPanel><ToolBar><Label Content="姓名:"></Label><TextBox Text="{Binding Name}"  Width="50"></TextBox><Label Content="郵箱:"></Label><TextBox Text="{Binding Email}" Width="100"></TextBox><Button Content="添加"Command="{Binding AddUserCommand }"></Button>          </ToolBar><StackPanel><DataGrid ItemsSource="{Binding Users}"></DataGrid></StackPanel></StackPanel>
</Window>

cs如下:

public partial class MainWindow : Window
{      public MainWindow(){InitializeComponent();MainViewModel mainViewModel = new MainViewModel();this.DataContext = mainViewModel;}}

將MainWindow的DataContext賦值給了mainViewModel。

 <TextBox Text="{Binding Name}"  Width="50"></TextBox><TextBox Text="{Binding Email}" Width="100"></TextBox><DataGrid ItemsSource="{Binding Users}"></DataGrid>

中進行了數據綁定,對應于圖中的這一部分:

image-20240528094205054

現在來看看命令綁定。

 <Button Content="添加"Command="{Binding AddUserCommand }"></Button>  

進行了命令綁定,對應于圖中這一部分:

image-20240528094348003

現在先來看看效果:

實現的效果

現在已經實現了與前面基于事件驅動同樣的效果,但是上面那張圖中的Send Notifications還沒有體現。

Send Notifications表示ViewModel中的更改會通知View。

現在我們來以一個例子說明一下Send Notifications是如何實現的。

首先添加一個測試命令:

 public ICommand TestCommand { get; set; }

在構造函數中添加:

 TestCommand = new RelayCommand(Test, CanTest);

實現Test與CanTest方法:

private bool CanTest(object obj)
{return true;
}private void Test(object obj)
{Name = "小1";Email = "111@qq.com";
}

View中修改如下:

 <Button Content="測試"Command="{Binding TestCommand }"></Button>

現在去嘗試,我們會發現沒有效果,原因是我們的ViewModel沒有實現INotifyPropertyChanged接口。

INotifyPropertyChanged接口介紹

在WPF(Windows Presentation Foundation)中,INotifyPropertyChanged接口用于實現數據綁定中的屬性更改通知。當綁定到UI元素的數據源中的屬性值發生更改時,INotifyPropertyChanged接口可以通知UI元素更新。

INotifyPropertyChanged接口只定義了一個事件:PropertyChanged。當屬性值發生更改時,應觸發此事件。事件參數PropertyChangedEventArgs包含更改的屬性的名稱。

現在我們的MainViewModel實現一下INotifyPropertyChanged接口,如下所示:

 public class MainViewModel : INotifyPropertyChanged{public ObservableCollection<User> Users { get; set; }public ICommand AddUserCommand { get; set; }public ICommand TestCommand { get; set; }private string? _name;public string? Name{get { return _name; }set{if (_name != value){_name = value;OnPropertyChanged(nameof(Name));}}}private string? _email;public string? Email{get { return _email; }set{if (_email != value){_email = value;OnPropertyChanged(nameof(Email));}}}public MainViewModel(){Users = UserManager.GetUsers();AddUserCommand = new RelayCommand(AddUser, CanAddUser);TestCommand = new RelayCommand(Test, CanTest);}private bool CanTest(object obj){return true;}private void Test(object obj){Name = "小1";Email = "111@qq.com";}private bool CanAddUser(object obj){return true;}private void AddUser(object obj){User user = new User();user.Name = Name;user.Email = Email;UserManager.AddUser(user);}public event PropertyChangedEventHandler? PropertyChanged;protected virtual void OnPropertyChanged(string propertyName){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}}

現在再嘗試一下,會發現ViewModel中的更改會成功通知View了,如下所示:

對應于圖中的這一部分:

image-20240528101649982

現在我們來看看ViewModel—Model。

ViewModel—Model

現在我們來看看ViewModel與Model之間的關系,可以根據下面這張圖進行理解:

image-20240528101926207

Model(模型):Model代表了業務邏輯和數據。它包含了應用程序中的數據和對數據的操作,例如,從數據庫中獲取數據,或者向數據庫中添加數據。Model是獨立于UI的,它不知道UI的存在。

ViewModel(視圖模型):ViewModel是Model和View之間的橋梁。它包含了View所需的數據(這些數據來自于Model),并提供了命令以響應View上的用戶操作。ViewModel將Model的數據轉換為View可以顯示的數據,同時,它也將View上的用戶操作轉換為對Model的操作。

在我們這個例子中我們的數據來源于Model文件夾下的User類與UserManager類:

image-20240528103959230

這里的Send Notifications又該如何理解呢?

我們也是以一個小例子進行說明。

首先將ViewModel中的Test方法修改為:

 private void Test(object obj){Users[0].Name = "小1";Users[0].Email = "111@qq.com";}

會發現現在并不會發送通知,實現View上的修改,這是因為User類并沒有實現INotifyPropertyChanged接口,現在修改User類實現INotifyPropertyChanged接口:

public class User : INotifyPropertyChanged
{private string? _name;public string? Name{get { return _name; }set{if (_name != value){_name = value;OnPropertyChanged(nameof(Name));}}}private string? _email;public string? Email{get { return _email; }set{if (_email != value){_email = value;OnPropertyChanged(nameof(Email));}}}public event PropertyChangedEventHandler? PropertyChanged;protected virtual void OnPropertyChanged(string propertyName){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}
}

現在可以實現通知了,效果如下所示:

使用MVVM庫

我們會發現如果全部都手動實現MVVM模式的話,代碼有點多,有點麻煩。這時候就可以使用一些MVVM庫來簡化我們的操作。

這里以CommunityToolkit.Mvvm為例,進行說明。

CommunityToolkit.Mvvm介紹

CommunityToolkit.Mvvm是Microsoft Community Toolkit的一部分,它是一個輕量級但功能強大的MVVM(Model-View-ViewModel)庫,旨在幫助開發者更容易地實現MVVM設計模式。

該庫提供了一些基礎類,如ObservableObjectObservableRecipient,這些類實現了INotifyPropertyChanged接口,并提供了SetProperty方法,可以在屬性值改變時觸發PropertyChanged事件。這使得數據綁定變得更加簡單和高效。

此外,該庫還提供了ICommand接口的實現,如RelayCommandAsyncRelayCommand,這些類可以幫助你創建命令,命令是MVVM模式中的一個重要組成部分。

CommunityToolkit.Mvvm還提供了一些其他有用的特性,如消息傳遞、設計時數據支持等,這些特性可以幫助你更好地組織和管理你的代碼。

CommunityToolkit.Mvvm是一個強大的工具,它可以幫助你更容易地實現MVVM模式,從而提高你的代碼質量和開發效率。

image-20240528112612211

修改之后的ViewModel如下所示:

 public partial class MainViewModel : ObservableObject{public ObservableCollection<User> Users { get; set; }    [ObservableProperty]private string? name;[ObservableProperty]private string? email;public MainViewModel(){Users = UserManager.GetUsers();         }[RelayCommand]private void Test(object obj){Users[0].Name = "小1";Users[0].Email = "111@qq.com";}[RelayCommand]private void AddUser(object obj){User user = new User();user.Name = Name;user.Email = Email;UserManager.AddUser(user);}}

修改之后的User類如下所示:

 public partial class User : ObservableObject{[ObservableProperty]private string? _name;[ObservableProperty]private string? _email;            }

用到了CommunityToolkit.Mvvm庫中的三個東西,分別是ObservableObject、[ObservableProperty]與[RelayCommand]。

先來看一下ObservableObject。

ObservableObjectCommunityToolkit.Mvvm庫中的一個基礎類,它實現了INotifyPropertyChanged接口。這個接口是.NET數據綁定基礎架構的一部分,當對象的一個屬性改變時,它會通知綁定到該屬性的任何元素。

image-20240528120932293

image-20240528121004023

具體見:ObservableObject - Community Toolkits for .NET | Microsoft Learn

在這里我們使用

 [ObservableProperty]private string? name;

它將生成一個像這樣的可觀察屬性:

public string? Name
{get => name;set => SetProperty(ref name, value);
}

具體見:ObservableProperty attribute - Community Toolkits for .NET | Microsoft Learn

我們使用

[RelayCommand]
private void AddUser(object obj)
{User user = new User();user.Name = Name;user.Email = Email;UserManager.AddUser(user);
}

代碼生成器會生成一個命令如下所示:

private RelayCommand? addUserCommand;public IRelayCommand AddUserCommand => addUserCommand ??= new RelayCommand(AddUser);

具體見:RelayCommand attribute - Community Toolkits for .NET | Microsoft Learn

現在我們的ViewModel與Model就可以簡化了,現在再來看看效果:

總結

本文先總體介紹了一下MVVM模式,關于MVVM模式可以根據這張圖幫助理解:

image-20240527095704838

由于很多同學可能與我一樣,是從winform到wpf的,因此在wpf中使用winform中的事件驅動編程范式完成了一個小例子,關于事件驅動編程,可以根據這張圖幫助理解:

image-20240527100814935

由于這種模式耦合比較多,我們想要松耦合,因此開始學習MVVM模式。我們創建了實現ICommand接口的RelayCommand類,實現INotifyPropertyChanged接口的MainViewModel類與User類。使用數據綁定與命令綁定改寫xaml頁面。

最后由于手動實現MVVM模式,需要寫很多代碼,看過去比較復雜與麻煩,我們可以使用MVVM庫來簡化MVVM模式的實現。

以上,就是本次分享的全部內容,希望對正在學習wpf中mvvm模式的同學有所幫助,如果有什么不對的地方,懇請批評指正,共同進步!

參考

1、What is the MVVM pattern, What benefits does MVVM have? (youtube.com)

2、WPF MVVM Tutorial: Build An App with Data Binding and Commands (youtube.com)

3、Model-View-ViewModel - .NET | Microsoft Learn

4、Introduction to the MVVM Toolkit - Community Toolkits for .NET | Microsoft Learn

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

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

相關文章

期權具體怎么交易詳細的操作流程?

期權就是股票&#xff0c;唯一區別標的物上證指數&#xff0c;會看大盤吧&#xff0c;交易兩個方向認購做多&#xff0c;認沽做空&#xff0c;雙向t0交易&#xff0c;期權具體交易流程可以理解選擇方向多和空&#xff0c;選開倉的合約&#xff0c;買入開倉和平倉沒了&#xff0…

【Spring Cloud】API網關

目錄 什么是API網關為什么需要API網關前言問題列表 API網關解決了什么問題常見的網關解決方案NginxLuaSpring Cloud Netflix ZuulSpringCloud Zuul的IO模型弊端 Spring Cloud Gateway 第二代網關——GatewayGateway的特征Spring Cloud Gateway的處理流程Spring Cloud Gateway的…

數據集要點和難點以及具體應用案例

數據集(Data set),又稱為資料集、數據集合或資料集合,是一種由數據所組成的集合。它通常以表格形式出現,其中每一列代表一個特定變量,每一行對應于某一成員的數據集的問題。數據集列出的價值觀為每一個變量,如身高和體重的一個物體或價值的隨機數,每個數值被稱為數據資…

我的又一個神奇的框架——Skins換膚框架

為什么會有換膚的需求 app的換膚&#xff0c;可以降低app用戶的審美疲勞。再好的UI設計&#xff0c;一直不變的話&#xff0c;也會對用戶體驗大打折扣&#xff0c;即使表面上不說&#xff0c;但心里或多或少會有些難受。所以app的界面要適當的改版啊&#xff0c;要不然可難受死…

Android Surface對應的Buffer怎么傳遞給HWC

Android Surface對應的Buffer怎么傳遞給HWC 引言 因為要預研Android Video overlay&#xff0c;需要將SurfaceView對應的GraphicBuffer從drm_hwcomposer中剝離出來&#xff0c;這就需要們了解SurfaceView對應的GraphicBuffer的前世今生&#xff0c;以及它的數據流向以及在各個…

輕兔推薦 —— vfox

簡介 vfox 是一個跨平臺且可擴展的版本管理工具&#xff0c;終于有一個可以管理所有運行環境的工具了 - 支持一鍵安裝 Java、Node.js、Flutter、.Net、Golang、PHP、Python等多種環境 - 支持一鍵切換不同版本 特點 支持Windows(非WSL)、Linux、macOS! 支持不同項目不同版本、…

(四)事件系統

視頻鏈接:尚硅谷2024最新版微信小程序 文章目錄 事件綁定和事件對象事件分類以及阻止事件冒泡事件傳參-data-*自定義數據事件傳參-mark 自定義數據事件綁定和事件對象 小程序中綁定事件與在網頁開發中綁定事件幾乎一致,只不過在小程序不能通過 on 的方式綁定事件,也沒有 cli…

C# 9.0的init訪問器

不控制可變性 下面是我們最常見的屬性聲明方式&#xff0c;允許屬性在類的內部和外部都可以讀取和修改 public int Id { get; set; }namespace Demo {public class Company{public int Id { get; set; }public Company(){}public Company(int id){Id id; // 可以在構造函數中…

22.Volatile原理

文章目錄 Volatile原理1.Volatile語義中的內存屏障1.1.volatile寫操作的內存屏障1.1.1.StoreStore 屏障1.1.2.StoreLoad 屏障 1.2.volatile讀操作的內存屏障1.2.1.LoadStore屏障1.2.2.LoadLoad屏障 2.volatile不具備原子性2.1.原理 Volatile原理 1.Volatile語義中的內存屏障 在…

用于生成 Avatar 的文本引導式情感和運動控制-InstructAvatar

網址 https://wangyuchi369.github.io/InstructAvatar/ 用于生成 Avatar 的文本引導式情感和運動控制 官網翻譯 最近的會說話的頭像生成模型在實現與音頻的真實和準確的嘴唇同步方面取得了長足的進步&#xff0c;但在控制和傳達頭像的詳細表情和情感方面往往存在不足&#…

APM2.8如何做加速度校準

加速度的校準建議準備一個六面平整&#xff0c;邊角整齊的方形硬紙盒或者塑料盒&#xff0c;如下圖所示&#xff0c;我們將以它作為APM校準時的水平垂直姿態參考&#xff0c;另外當然還需要一塊水平的桌面或者地面 首先用雙面泡沫膠或者螺絲將APM主板正面向上固定于方形盒子上&…

JavaScrip原型對象

參考 JavaScrip原型對象 | LogDicthttps://www.logdict.com/archives/javascripyuan-xing-mo-shi

每天寫兩道(二)LRU緩存、

146.LRU 緩存 . - 力扣&#xff08;LeetCode&#xff09; 請你設計并實現一個滿足 LRU (最近最少使用) 緩存 約束的數據結構。 實現 LRUCache 類&#xff1a; LRUCache(int capacity) 以 正整數 作為容量 capacity 初始化 LRU 緩存int get(int key) 如果關鍵字 key 存在于緩存…

如何使用Python和大模型進行數據分析和文本生成

如何使用Python和大模型進行數據分析和文本生成 Python語言以其簡潔和強大的特性&#xff0c;成為了數據科學、機器學習和人工智能開發的首選語言之一。隨著大模型&#xff08;Large Language Models, LLMs&#xff09;如GPT-4的崛起&#xff0c;我們能夠利用這些模型實現諸多…

Revit——(2)模型的編輯、軸網和標高

目錄 一、關閉縮小的隱藏窗口 二、標高&#xff08;可創建平面&#xff0c;其他標高線復制即可&#xff09; 三、軸網 周圍的四個圈和三角表示四個里面&#xff0c;可以移動&#xff0c;不要刪除 一、關閉縮小的隱藏窗口 二、標高&#xff08;可創建平面&#xff0c;其他標…

計算機體系結構期末快速復習

文章目錄 前言CPI&#xff0c;MIPS&#xff08;大題1&#xff09;加速比&#xff08;大題2&#xff09;流水線&#xff08;大題3&#xff09;CRAY-1向量機&#xff08;大題4&#xff09;Tomasulo算法&#xff08;大題5&#xff09;概念簡答題計算機系統結構的經典定義什么是透明…

深入分析 Android Activity (二)

文章目錄 深入分析 Android Activity (二)1. Activity 的啟動模式&#xff08;Launch Modes&#xff09;1.1 標準模式&#xff08;standard&#xff09;1.2 單頂模式&#xff08;singleTop&#xff09;1.3 單任務模式&#xff08;singleTask&#xff09;1.4 單實例模式&#xf…

利用邊緣計算網關的工業設備數據采集方案探討-天拓四方

隨著工業4.0時代的到來&#xff0c;工業設備數據采集成為了實現智能制造、提升生產效率的關鍵環節。傳統的數據采集方案往往依賴于中心化的數據處理方式&#xff0c;但這種方式在面對海量數據、實時性要求高的工業場景時&#xff0c;往往顯得力不從心。因此&#xff0c;利用邊緣…

CSS實現一個雨滴滑落效果

使用純CSS來實現一個真實的雨滴滑落效果可能會有些挑戰&#xff0c;因為CSS主要關注于靜態樣式和簡單的動畫效果。然而&#xff0c;你可以使用CSS動畫和keyframes來模擬一個雨滴滑落的簡化效果。 以下是一個基本的示例&#xff0c;展示如何使用CSS來模擬雨滴從頂部滑落到底部的…

AI學習指南數學工具篇-MATLAB中的凸優化工具

AI學習指南數學工具篇-MATLAB中的凸優化工具 在人工智能領域&#xff0c;凸優化是一個非常重要的數學工具&#xff0c;它在機器學習、深度學習、數據分析等領域都有著廣泛的應用。而MATLAB作為一款強大的數學工具軟件&#xff0c;提供了豐富的凸優化工具和函數&#xff0c;為用…