WPF MVVM框架

一、MVVM简介

MVC Model View Control

MVP

MVVM即Model-View-ViewModel,MVVM模式与MVP(Model-View-Presenter)模式相似,主要目的是分离视图(View)和模型(Model),具有低耦合、可重用性、独立开发、可测试性等优点。

MVVM框架有很多,开源的主要有:

  • PRISM:由微软提供,和MEF/Unity一起用于依赖注入,支持组合命令,可以扩展。MSDN上有详细的教程和演练。

  • MVVM Light Toolkit:有visual Studio和Expression Blend的项目和项的模板。更多信息请看这里,另外可以参考VS和Expression Blend的使用教程。

  • Caliburn Micro:支持视图模型先行(ViewModel-First)和视图先行(View-First)两种开发方式,通过co-routine支持异步编程。

  • Simple MVVM Toolkit:提供VS项目和项的模板,依赖注入,支持深拷贝以及模型和视图模型之间的属性关联。

  • Catel:包含项目和项的模板,用户控件和企业类库。支持动态视图模型注入,视图模型的延迟加载和验证。还支持WP7专用的视图模型服务。

闭源框架主要有:

  • Intersoft ClientUI:付费的,只支持WPF和Silverlight,但是,除了MVVM框架,它还提供其它一些特性。

  • Vidyano:免费但不开源。带有实体映射/虚拟持久化对象(数据容器),业务规则以及内置基于ACL的安全特性。

二、原生版本的MVVM实例

Models 存放的是数据模型

Service存放的是业务逻辑

ViewModels存放的便是视图模型

Views存放WPF窗口

2.1 Models文件夹中创建一个用户模型User.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
​
namespace Wpfmvvm_demo.Models
{public class User{/// <summary>/// 用户名/// </summary>public string? Name { get; set; }/// <summary>/// 密码/// </summary>public string? Password { get; set; }}
}

2.2 在Services文件夹中添加用户的业务逻辑UserService.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Wpfmvvm_demo.Models;
​
namespace Wpfmvvm_demo.Services
{public class UserService{/// <summary>/// 获取所有用户方法/// </summary>/// <returns></returns>public List<User> GetAllUser(){List<User> users = new ();
​for (int i = 0; i < 3; i++){var user = new User();user.Name = "用户" + i;user.Password = "密码" + i;users.Add(user);}
​return users;}}
}

2.3 在ViewModels中创建NotificationObject.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
​
namespace Wpfmvvm_demo.ViewModels
{public class NotificationObject : INotifyPropertyChanged{public event PropertyChangedEventHandler? PropertyChanged;
​public void RaisePropertyChanged(string propertyName){if (PropertyChanged != null){PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));}}}
}

2.4 在ViewModels文件中创建DelegateCommand.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
​
namespace Wpfmvvm_demo.ViewModels
{public class DelegateCommand : ICommand{public event EventHandler? CanExecuteChanged;public Func<object?,bool>? DoCanExecute { get; set; }public Action<object?>? DoExecute { get; set; }
​public bool CanExecute(object? parameter){if (DoCanExecute != null){return DoCanExecute(parameter);}return true;}
​public void Execute(object? parameter){if (DoExecute != null){DoExecute.Invoke(parameter);}}}
}

2.5 ViewModels中创建主窗口的视图模型MainWindowViewModel.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Wpfmvvm_demo.Models;
using Wpfmvvm_demo.Services;
​
namespace Wpfmvvm_demo.ViewModels
{public class MainWindowViewModel : NotificationObject{/// <summary>/// 用户List/// </summary>private List<User>? users;public List<User>? Users{get { return users; }set{users = value;RaisePropertyChanged("Users");}}
​/// <summary>/// 程序名/// </summary>public string AppName { get; set; }
​/// <summary>/// 电话/// </summary>private string? phone;public string? Phone{get { return phone; }set{phone = value;RaisePropertyChanged("Phone");}}
​/// <summary>/// 获取所有用户命令/// </summary>public DelegateCommand? GetAllUsersCommand { get; set; }
​/// <summary>/// 构造初始化/// </summary>public MainWindowViewModel(){AppName = "WPF MVVM 模式测试";Phone = "123456";GetAllUsersCommand = new DelegateCommand{DoExecute = new Action<object?>(GetAllUsersCommandExecute)};}
​/// <summary>/// 获取所有用户命令执行方法/// </summary>private void GetAllUsersCommandExecute(object? paramater){Phone = Phone!.Equals("123456") ? "1234567" : "123456";UserService userService = new UserService();Users = userService.GetAllUser();}}
}

2.6 设计MainWindow.xaml界面

<Window x:Class="Wpfmvvm_demo.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:Wpfmvvm_demo"mc:Ignorable="d"Title="MainWindow" Height="350" Width="550"><Grid><StackPanel Orientation="Vertical"><StackPanel Orientation="Horizontal"><Label Content="程序名"></Label><Label Content="{Binding AppName}"></Label></StackPanel><StackPanel Orientation="Horizontal"><Label Content="电话"></Label><Label Content="{Binding Phone}"></Label></StackPanel><StackPanel><Button Content="获取所有用户" Command="{Binding GetAllUsersCommand}"></Button></StackPanel><DataGrid ItemsSource="{Binding Users}" AutoGenerateColumns="False" GridLinesVisibility="All" CanUserDeleteRows="False" CanUserAddRows="False" ><DataGrid.Columns><DataGridTextColumn Header="用户名" Binding="{Binding Name}"></DataGridTextColumn><DataGridTextColumn Header="密码" Binding="{Binding Password}"></DataGridTextColumn></DataGrid.Columns></DataGrid></StackPanel></Grid>
</Window>

2.7 把ViewModel数据绑定到窗口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Wpfmvvm_demo.ViewModels;
​
namespace Wpfmvvm_demo
{/// <summary>/// Interaction logic for MainWindow.xaml/// </summary>public partial class MainWindow : Window{public MainWindow(){InitializeComponent();this.DataContext = new MainWindowViewModel();}}
}

三、MVVM Toolkit

微软虽然提出了 MVVM,但又没有提供一个官方的 MVVM 库(多年前有过 Prism,但已经离家出走了)。每次有人提起 MVVM 库,有些人会推荐 Prism(例如我),有些人会推荐 MVVMLight。可是现在 Prism 已经决定不再支持 UWP , 而 MVVMLight 又不再更新,在这左右为难的时候 Windows Community Toolkit 挺身而出发布了 MVVM Toolkit。 MVVM Toolkit 延续了 MVVMLight 的风格,是一个轻量级的组件,而且它基于 .NET Standard 2.0,可用于UWP, WinForms, WPF, Xamarin, Uno 等多个平台。相比它的前身 MVVMLight,它有以下特点:

  • 更高:版本号更高,一出手就是 7.0。

  • 更快:速度更快,MVVM Toolkit 从一开始就以高性能为实现目标。

  • 更强:后台更强,MVVM Toolkit 的全称是 'Microsoft.Toolkit.Mvvm',根正苗红。

这个包主要提供了如下的

  • Microsoft.Toolkit.Mvvm.ComponentModel

    • ObservableObject

    • ObservableRecipient

    • ObservableValidator

  • Microsoft.Toolkit.Mvvm.DependencyInjection

    • Ioc

  • Microsoft.Toolkit.Mvvm.Input

    • RelayCommand

    • AsyncRelayCommand

    • IRelayCommand

    • IAsyncRelayCommand

  • Microsoft.Toolkit.Mvvm.Messaging

    • IMessenger

    • WeakReferenceMessenger

    • StrongReferenceMessenger

    • IRecipient

    • MessageHandler

  • Microsoft.Toolkit.Mvvm.Messaging.Messages

    • PropertyChangedMessage

    • RequestMessage

    • AsyncRequestMessage

    • CollectionRequestMessage

    • AsyncCollectionRequestMessage

    • ValueChangedMessage

3.1 可观察对象

public class UserVM : ObservableObject
{private string name;
​public string Name{get => name;set => SetProperty(ref name, value);}
​private int age;
​public int Age{get => age;set => SetProperty(ref age, value);}
}

页面的类中添加

public partial class MainWindow : Window
{private UserVM userVM = new UserVM();
​public MainWindow(){InitializeComponent();DataContext = userVM;Task.Run(() =>{while (true){userVM.Age += 1;Thread.Sleep(1000);}});}
}

页面中

<Grid><StackPanel><TextBlock FontSize="30" Text="{Binding Age}" /></StackPanel>
</Grid>

我们就可以看到数字就会一直递增了。

3.2 命令

页面中我们添加命令

<StackPanel Height="40" Orientation="Horizontal"><TextBlock FontSize="30" Text="{Binding Name}" /><TextBlock FontSize="30" Text="{Binding Age}" />
​<Button Command="{Binding IncrementAgeCommand}" Content="年龄递增" />
</StackPanel>

对应的ViewModel中添加命令及响应的事件

public class UserVM : ObservableObject
{private string name;
​public string Name{get => name;set => SetProperty(ref name, value);}
​private int age;
​public int Age{get => age;set => SetProperty(ref age, value);}
​public ICommand IncrementAgeCommand { get; }public UserVM(){IncrementAgeCommand = new RelayCommand(IncrementAge);}private void IncrementAge() => Age++;
}

这样只要我们点击按钮,年龄就会递增1。

3.3 消息机制

3.3.1 注册与发送

添加传递消息的类

public class ZMessage
{public int Code { get; set; }
​public string Message { get; set; }
​public ZMessage(int code, string msg){Code = code;Message = msg;}
}

消息接收与发送

public MainWindow()
{InitializeComponent();initMessage();
}
​
private void initMessage()
{WeakReferenceMessenger.Default.Register<ZMessage>(this,(r, m) =>{Console.WriteLine("接收到信息:" + m.Message);});
​WeakReferenceMessenger.Default.Send(new ZMessage(100, "Hello"));
}
3.3.2 可接收消息的类

当然我们也可以让我们的ViewModel接收消息

public class UserVM : ObservableRecipient, IRecipient<ZMessage>
{private string name;
​public string Name{get => name;set => SetProperty(ref name, value);}
​private int age;
​public int Age{get => age;set => SetProperty(ref age, value);}
​public UserVM(){IsActive = true;}
​public void Receive(ZMessage message){Name = message.Message;Age = message.Code;}
}

这里一定要注意

  • 要继承ObservableRecipient类,实现IRecipient<>接口。

  • 只有设置IsActive = true;,才能接收消息。

我们还是在页面的类中发送消息

WeakReferenceMessenger.Default.Send(new ZMessage(18, "XiaoMing"));

页面也稍做修改

<StackPanel Orientation="Horizontal"><TextBlock FontSize="30" Text="{Binding Name}" /><TextBlock FontSize="30" Text="{Binding Age}" />
</StackPanel>

我们会发现页面上已经变更为我们发送消息的数据了。

3.4 控制反转(IOC)

添加依赖库Microsoft.Extensions.DependencyInjection

Install-Package Microsoft.Extensions.DependencyInjection -Version 6.0.0

创建我们要自动注入的类

加入如下是我们用户相关的服务

public interface IUserService
{string getUserName();
}

public class UserService : IUserService
{public string getUserName(){return "XiaoMing";}
}

添加注入的控制

public partial class App : Application
{public App(){Services = ConfigureServices();
​this.InitializeComponent();}
​public new static App Current => (App)Application.Current;
​public IServiceProvider Services { get; }
​private static IServiceProvider ConfigureServices(){var services = new ServiceCollection();
​services.AddSingleton<IUserService, UserService>();
​// ViewModelsservices.AddTransient<UserVM>();
​return services.BuildServiceProvider();}
}

其中

  • AddSingleton 单一实例服务

  • AddScoped 范围内的服务

  • AddTransient 暂时性服务

权重:

AddSingleton`→`AddTransient`→`AddScoped

生命周期:

  • AddSingleton 项目启动-项目关闭 相当于静态类 只会有一个 每一次获取的对象都是同一个

  • AddScoped 请求开始-请求结束 在这次请求中获取的对象都是同一个 请求时创建

  • AddTransient 请求获取-(GC回收-主动释放) 获取时创建 每一次获取的对象都不是同一个

注意:

由于AddScoped对象是在请求的时候创建的 所以不能在AddSingleton对象中使用 甚至也不能在AddTransient对象中使用

使用

private UserVM userVM = (UserVM)App.Current.Services.GetService(typeof(UserVM));
private IUserService userService = (IUserService)App.Current.Services.GetService(typeof(IUserService));

这样是不是感觉还麻烦了

但是如果我们的ViewModel是这样的

public class UserVM : ObservableObject
{private string name;
​public string Name{get => name;set => SetProperty(ref name, value);}
​private int age;
​public int Age{get => age;set => SetProperty(ref age, value);}
​public ICommand IncrementAgeCommand { get; }
​public IUserService userService { get; }
​public UserVM(IUserService _userService){userService = _userService;IncrementAgeCommand = new RelayCommand(IncrementAge);}
​private void IncrementAge() => Age++;
}

这里的IUserService的实例并没有传入但是就可以用了,因为IOC框架已经自动注入了。

四、WPF Prism

4.1 常见的MVVM框架

众所周知, 如果你了解WPF当中的ICommand, INotifyPropertyChanged的作用, 就会发现众多框架都是基于这些进行扩展, 实现其通知、绑定、命令等功能。

对于不同的MVVM框架而言, 大体使用上会在声明方式上的差异, 以及特定功能上的差别。

下面列举了常用的3个MVVM框架,他们的一些差异。如下所示:

功能↓ / →框架名PrismMvvmlightMicorosoft.Toolkit.Mvvm
通知BindableBaseViewModelBaseObservableObject
命令DelegateCommandRelayCommandAsync/RelayCommand
聚合器IEventAggregatorIMessengerIMessenger
模块化××
容器××
依赖注入××
导航××
对话××

正如你所见, 各个框架之间都有各自的通知、绑定、事件聚合器等基础的功能, 而Prsim自带的依赖注入、容器、以及导航会话等功能, 可以为你提供更加强大的功能。

当然,在实际的开发过程当中, 可以根据实际的功能需求, 对不同的框架选型, 同时这也需要你对各个框架之间的优缺点进行判断。

那么, 下面将主要介绍Prism

4.2 BindableBase

在Prism当中, 你需要继承于BindableBase

public class TestViewModel : BindableBase
{private string _message;
​public string Message{get { return _message; }set { _message = value; RaisePropertyChanged(); }}
}

在Prism当中, 你可以使用DelegateCommand及带参数的Command

    public class TestViewModel : ViewModelBase{public DelegateCommand SendCommand { get; set; }
​public DelegateCommand<string> SendMessageCommand { get; set; }}
4.3 CompositeCommand

对于单个Command而言, 只是触发单个对应的功能, 而复合命令是Prism当中非常强大的功能, CompositeCommand简单来说是一个父命令, 它可以注册N个子命令

当父命令被激活, 它将触发对所有的子命令, 如果任意一个命令CanExecute=false,它将无法被激活,如下所示:

public class MyViewModel : NotificationObject
{private readonly CompositeCommand saveAllCommand;
​public ArticleViewModel(INewsFeedService newsFeedService,IRegionManager regionManager,IEventAggregator eventAggregator){this.saveAllCommand = new CompositeCommand();this.saveAllCommand.RegisterCommand(new SaveProductsCommand());this.saveAllCommand.RegisterCommand(new SaveOrdersCommand());}
​public ICommand SaveAllCommand{get { return this.saveAllCommand; }}
}
4.4 IEventAggregator
  • 松耦合基于事件通讯

  • 多个发布者和订阅者

  • 微弱的事件

  • 过滤事件

  • 传递参数

  • 取消订阅

该功能主要作用为, 事件聚合器负责接收订阅以及发布消息。订阅者可以接收到发布者发送的内容。

 
//创建事件
public class SavedEvent : PubSubEvent<string> { }
​
//发布
IEventAggregator.GetEvent<SavedEvent>().Publish("some value");
​
//订阅
IEventAggregator.GetEvent<SavedEvent>().Subscribe(.Subscribe(message=>{//do something});
4.5 Filtering Events

在实际的开发过程当中,我们往往会在多个位置订阅一个事件, 但是对于订阅者而言, 他并不需要接收任何消息, 如下所示:

在Prism当中, 我们可以指定为事件指定过滤条件, 如下所示:

eventAggregator.GetEvent<MessageSentEvent>().Subscribe(arg =>{//do something},ThreadOption.PublisherThread,false,//设置条件为token等于“MessageListViewModel” 则接收消息message => message.token.Equals(nameof(MessageListViewModel)));

关于Subscribe当中的4个参数, 详解:

  • 1.action: 发布事件时执行的委托。

  • 2.ThreadOption枚举: 指定在哪个线程上接收委托回调。

  • 3.keepSubscriberReferenceAlive: 如果为true,则Prism.Events.PubSubEvent保留对订阅者的引用因此它不会收集垃圾。

  • 4.filter: 进行筛选以评估订阅者是否应接收事件。

4.6 Unsubscribe

为注册的消息取消订阅, Prism提供二种方式取消订阅,如下:

1.通过委托的方式取消订阅

var event = IEventAggregator.GetEvent<MessageSentEvent>();
​
event.Subscribe(OnMessageReceived);
​
event.Unsubscribe(OnMessageReceived);

2.通过获取订阅者token取消订阅

var _event = eventAggregator.GetEvent<MessageSentEvent>();
​
var token = _event.Subscribe(OnMessageReceived);
​
_event.Unsubscribe(token);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/474544.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PH热榜 | 2024-11-19

DevNow 是一个精简的开源技术博客项目模版&#xff0c;支持 Vercel 一键部署&#xff0c;支持评论、搜索等功能&#xff0c;欢迎大家体验。 在线预览 1. Layer 标语&#xff1a;受大脑启发的规划器 介绍&#xff1a;体验一下这款新一代的任务和项目管理系统吧&#xff01;它…

【ArcGISPro】使用AI模型提取要素-提取车辆(目标识别)

示例数据下载 栅格数据从网上随便找一个带有车辆的栅格数据 f094a6b1e205cd4d30a2e0f816f0c6af.jpg (1200799) (588ku.com) 添加数据

联通光猫(烽火通信设备)改桥接教程

一、获得超级密码 1.打开telnet连接权限 http://192.168.1.1/telnet?enable1&key9070D3BECD70&#xff08;MAC地址&#xff09;2.连接光猫获取密码 telnet 192.168.1.1 用户名&#xff1a;admin 密码&#xff1a;Fh9070D3BECD70连接成功后 load_cli factory show admin_…

掌握SEO提升网站流量的关键在于长尾关键词的有效运用

内容概要 在现代数字营销中&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;被广泛视为提升网站流量的核心策略之一&#xff0c;而其中长尾关键词的运用显得尤为重要。长尾关键词通常由三个或更多个词组成&#xff0c;具有更高的针对性和精确度&#xff0c;可以更好地满足…

【期权懂|个股期权中的备兑开仓策略是如何进行的?

期权小懂每日分享期权知识&#xff0c;帮助期权新手及时有效地掌握即市趋势与新资讯&#xff01; 个股期权中的备兑开仓策略是如何进行的&#xff1f; 个股期权备兑开仓的优点和风险‌&#xff1a; ‌&#xff08;1&#xff09;优点‌&#xff1a;备兑开仓可以增强持股收益&…

汽车安全再进化 - SemiDrive X9HP 与环景影像系统 AVM 的系统整合

当今汽车工业正面临著前所未有的挑战与机遇&#xff0c;随著自动驾驶技术的迅速发展&#xff0c;汽车的安全性与性能需求日益提高。在这样的背景下&#xff0c;汽车 AVM&#xff08;Automotive Visual Monitoring&#xff09;标准应运而生&#xff0c;成为促进汽车智能化和安全…

MongoDB聚合操作

管道的聚合 管道在Unix和Linux中一般用于将当前命令的输出结果作为下一个命令的参数。 MongoDB的聚合管道将MongoDB文档在一个管道处理完毕后将结果传递给下一个管道处理。管道操作是可以重复的。 表达式&#xff1a;处理输入文档并输出。表达式是无状态的&#xff0c;只能用…

向量数据库FAISS之五:原理(LSH、PQ、HNSW、IVF)

1.Locality Sensitive Hashing (LSH) 使用 Shingling MinHashing 进行查找 左侧是字典&#xff0c;右侧是 LSH。目的是把足够相似的索引放在同一个桶内。 LSH 有很多的版本&#xff0c;很灵活&#xff0c;这里先介绍第一个版本&#xff0c;也是原始版本 Shingling one-hot …

https(day30)

1.配置需要配置端口为443 2.配置需要配置证书 ssl_certificate /path/to/your/fullchain.pem; # 证书文件 ssl_certificate_key /path/to/your/private.key; # 私钥文件 3.其他优化

【WPF】Prism学习(七)

Prism Dependency Injection 1.注册类型&#xff08;Registering Types&#xff09; 1.1. Prism中的服务生命周期&#xff1a; Transient&#xff08;瞬态&#xff09;&#xff1a;每次请求服务或类型时&#xff0c;都会获得一个新的实例。Singleton&#xff08;单例&#xf…

服务器数据恢复—热备盘未激活导致硬盘掉线的raid5阵列崩溃的数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌X3850服务器中有一组由数块SAS硬盘组建的RAID5阵列&#xff0c;该阵列中有一块盘是热备盘。操作系统为linux redhat&#xff0c;上面跑着一个基于oracle数据库的oa。 服务器故障&#xff1a; 服务器raid5阵列中有一块硬盘离线&#xff0…

ADS 2022软件下载与安装教程

“ 本文以最新的Advanced Design System 2022为例介绍ADS软件的安装及crack教程 ” ADS 简介 先进设计系统 Advanced Design system&#xff08;ADS&#xff09;Agilent Technologies 是领先的电子设计自动化软件&#xff0c;适用于射频、微波和信号完整性应用。ADS 是获得商…

Chrome 浏览器 131 版本新特性

Chrome 浏览器 131 版本新特性 一、Chrome 浏览器 131 版本更新 1. 在 iOS 上使用 Google Lens 搜索 自 Chrome 126 版本以来&#xff0c;用户可以通过 Google Lens 搜索屏幕上看到的任何图片或文字。 要使用此功能&#xff0c;请访问网站&#xff0c;并点击聚焦时出现在地…

Unity 编辑器下 Android 平台 Addressable 加载模型粉红色,类似材质丢失

Unity 编辑器下 Android 平台 Addressable 加载模型粉红色&#xff0c;类似材质丢失 Addressable Play Mode Script加载模式 选择 Use Existiing Build 1.Unity 切换到 PC 平台&#xff0c;执行 Addressable Build 运行&#xff0c;加载 bundle 内的预制体 显示正常 2.Unit…

独立站干货:WordPress主机推荐

WordPress作为全球最受欢迎的独立站建设平台&#xff0c;提供了灵活性和强大的功能&#xff0c;使得建站变得简单而高效。本文将为您详细介绍WordPress建站的流程&#xff0c;并推荐几款实测后觉得好用的主机商。 WordPress建站流程 域名注册 首先需要注册一个域名&#xff0c…

每日OJ题_牛客_天使果冻_递推_C++_Java

目录 牛客_天使果冻_递推 题目解析 C代码 Java代码 牛客_天使果冻_递推 天使果冻 描述&#xff1a; 有 n 个果冻排成一排。第 i 个果冻的美味度是 ai。 天使非常喜欢吃果冻&#xff0c;但她想把最好吃的果冻留到最后收藏。天使想知道前 x个果冻中&#xff0c;美味…

C++AVL平衡树

1.AVL平衡树节点定义 每一个节点都配左右孩子和父节点&#xff0c;以及平衡因子和其所对应的值。 template<class K, class V> struct AVLTreeNode {// 需要parent指针&#xff0c;后续更新平衡因子可以看到pair<K, V> _kv;AVLTreeNode<K, V>* _left;AVLTr…

Vue3 pinia使用

Pinia 是一个现代的状态管理库&#xff0c;专为 Vue 3 设计。它提供了一种简单、直观的方式来管理应用中的全局状态 (就是不同组件都希望去共享的一些变量,函数等)。Pinia 的设计灵感来自于 Vuex&#xff08;Vue 2 的状态管理库&#xff09;&#xff0c;但进行了许多改进&#…

PHP开发全新UI多语言多商户跨境商城源码、支持一键铺货、一键下单

商家可在平台产品库选品&#xff0c;一键铺货到自己商店&#xff0c;用户下单后&#xff0c;商家提交订单给平台&#xff0c;扣除商家供货价所需余额&#xff0c;提交后由平台发货&#xff0c;收货后订单金额结算给商家. 源码开源完整&#xff0c;一切能跑通的逻辑流程都可以二…

移动应用开发:使用Android Studio 实现登录页与注册页跳转

文章目录 前期一&#xff0c;添加UI控件触发跳转二&#xff0c;编写LoginActivity活动代码三&#xff0c;运行程序查看效果 前期 需创建两个活动页面&#xff0c;登录页和注册页&#xff0c;可参考&#xff1a;《Android Studio实现简易登录页》《Android Studio实现简易注册页…