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.mzph.cn/web/59931.shtml

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

相关文章

【算法】【优选算法】前缀和(下)

目录 一、560.和为K的⼦数组1.1 前缀和1.2 暴力枚举 二、974.和可被K整除的⼦数组2.1 前缀和2.2 暴力枚举 三、525.连续数组3.1 前缀和3.2 暴力枚举 四、1314.矩阵区域和4.1 前缀和4.2 暴力枚举 一、560.和为K的⼦数组 题目链接&#xff1a;560.和为K的⼦数组 题目描述&#x…

两大新兴开发语言大比拼:Move PK Rust

了解 Move 和 Rust 的差异有助于开发者根据项目的具体需求选择最合适的语言。选择不恰当的语言可能会导致项目后期出现技术债务。不同语言有其独特的优势。了解 Move 和 Rust 的差异可以帮助开发者拓展技术视野&#xff0c;发现不同语言在不同领域的应用潜力。 咱们直奔主题&a…

Scaling Law的“终结“还是新起点?——开源实践者的深度思考

作者&#xff1a;宋大宝&#xff0c;与大宝同学因那篇《回顾总结展望「融合RL与LLM思想&#xff0c;探寻世界模型以迈向AGI」》结识于今年春天&#xff0c;虽我们当时某些思想观念有些出入&#xff0c;也碰撞出了很多火花与共鸣&#xff0c;并持续地相互启发的走到了现在。他是…

“fc-async”提供了基本的异步处理能力

在开发中,异步处理已经成为提升系统性能和用户体验的常用方式。然而,传统的@Async注解和基础的异步处理工具在面对复杂的任务场景时,存在局限性。这些局限性包括但不限于高并发环境下的稳定性、任务失败后的恢复机制、以及任务的监控和管理。 开源项目“fc-async”提供了基…

Ubuntu 的 ROS 操作系统 turtlebot3 导航仿真

引言 导航仿真是机器人自动化系统中不可或缺的一部分&#xff0c;能够帮助开发者在虚拟环境中测试机器人在复杂场景下的运动与路径规划。 在 Gazebo 仿真环境中&#xff0c;TurtleBot3 配合 ROS 操作系统提供了强大的导航功能。在进行导航仿真时&#xff0c;首先需要准备地图&…

FFmpeg 4.3 音视频-多路H265监控录放C++开发十三.2:avpacket中包含多个 NALU如何解析头部分析

前提&#xff1a; 注意的是&#xff1a;我们这里是从avframe转换成avpacket 后&#xff0c;从avpacket中查看NALU。 在实际开发中&#xff0c;我们有可能是从摄像头中拿到 RGB 或者 PCM&#xff0c;然后将pcm打包成avframe&#xff0c;然后将avframe转换成avpacket&#xff0…

java八股-jvm入门-程序计数器,堆,元空间,虚拟机栈,本地方法栈,类加载器,双亲委派,类加载执行过程

文章目录 PC Register堆虚拟机栈方法区(Metaspace元空间双亲委派机制类加载器 类装载的执行过程 PC Register 程序计数器&#xff08;Program Counter Register&#xff09;是 Java 虚拟机&#xff08;JVM&#xff09;中的一个组件&#xff0c;它在 JVM 的内存模型中扮演着非常…

使用Web Animations API实现复杂的网页动画效果

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Web Animations API实现复杂的网页动画效果 使用Web Animations API实现复杂的网页动画效果 使用Web Animations API实现复杂…

本草纲目数字化:Spring Boot在中药实验管理中的应用

1系统概述 1.1 研究背景 随着计算机技术的发展以及计算机网络的逐渐普及&#xff0c;互联网成为人们查找信息的重要场所&#xff0c;二十一世纪是信息的时代&#xff0c;所以信息的管理显得特别重要。因此&#xff0c;使用计算机来管理中药实验管理系统的相关信息成为必然。开发…

无人机挂载超细干粉灭火装置技术详解

无人机挂载超细干粉灭火装置技术是一种创新的灭火方式&#xff0c;结合了无人机的远程操控能力和超细干粉灭火剂的高效灭火性能。以下是对该技术的详细解析&#xff1a; 一、技术背景与原理 背景&#xff1a;高层建筑灭火救援困难一直是公认的世界性难题。无人机技术的发展为…

Linux下MySQL的简单使用

Linux下MySQL的简单使用 导语MySQL安装与配置MySQL安装密码设置 MySQL管理命令myisamchkmysql其他 常见操作 C语言访问MYSQL连接例程错误处理使用SQL 总结参考文献 导语 这一章是MySQL的使用&#xff0c;一些常用的MySQL语句属于本科阶段内容&#xff0c;然后是C语言和MySQl之…

多端校园圈子论坛小程序,多个学校同时代理,校园小程序分展示后台管理源码

社团活动与组织 信息发布&#xff1a;系统支持社团发布活动信息、招募新成员等&#xff0c;方便社团进行线上线下活动的组织和管理。 增强凝聚力&#xff1a;通过系统&#xff0c;社团成员可以更好地交流和互动&#xff0c;增强社团的凝聚力和影响力。 生活服务功能 二手市场…

androidstudio入门到放弃配置

b站视频讲解传送门 android_studio安装包&#xff1a;https://developer.android.google.cn/studio?hlzh-cn 下载安装 开始创建hello-world 1.删除缓存 文件 下载gradle文件压缩&#xff1a;gradle-8.9用自己创建项目时自动生成的版本即可&#xff0c;不用和我一样 https://…

深入理解 Redis跳跃表 Skip List 原理|图解查询、插入

1. 简介 跳跃表 ( skip list ) 是一种有序数据结构&#xff0c;通过在每个节点中维持多个指向其他节点的指针&#xff0c;从而达到快速访问节点的目的。 在 Redis 中&#xff0c;跳跃表是有序集合键的底层实现之一&#xff0c;那么这篇文章我们就来讲讲跳跃表的实现原理。 2. …

如何在算家云搭建Peach-9B-8k-Roleplay(文本生成)

一、Peach-9B-8k-Roleplay简介 Peach-9B-8k-Roleplay 是一种聊天大型语言模型&#xff0c;它是通过我们的数据合成方法创建的超过 100K 的对话中微调 01-ai/Yi-1.5-9B 模型而获得的。 也许是 34B 以下参数最好的 LLM。 二、模型搭建流程 1. 创建容器镜像 进入算家云平台的“…

Flutter中的Material Theme完全指南:从入门到实战

Flutter作为一款热门的跨平台开发框架&#xff0c;其UI组件库Material Design深受开发者喜爱。本文将深入探讨Flutter Material Theme的使用&#xff0c;包括如何借助Material Theme Builder创建符合产品需求的主题风格。通过多个场景和代码实例&#xff0c;让你轻松掌握这一工…

基于Python的仓库管理系统设计与实现

背景&#xff1a; 基于Python的仓库管理系统功能介绍 本仓库管理系统采用Python语言开发&#xff0c;利用Django框架和MySQL数据库&#xff0c;实现了高效、便捷的仓库管理功能。 用户管理&#xff1a; 支持员工和管理员角色的管理。 用户注册、登录和权限分配功能&#x…

RabbitMQ的工作队列在Spring Boot中实现(详解常⽤的⼯作模式)

上文着重介绍RabbitMQ 七种工作模式介绍RabbitMQ 七种工作模式介绍_rabbitmq 工作模式-CSDN博客 本篇讲解如何在Spring环境下进⾏RabbitMQ的开发.&#xff08;只演⽰部分常⽤的⼯作模式&#xff09; 目录 引⼊依赖 一.工作队列模式 二.Publish/Subscribe(发布订阅模式) …

FastAPI

FastAPI 摘要概述快速开始基础应用路由注册和端点绑定路由端点传参与校验请求和响应报文后台异步任务执行异常与错误中间件数据库操作应用启动和关闭回调多应用挂载自定义配置swagger ui应用配置信息读取 继续学习与最佳实践安全认证机制*依赖注入PydanticPytest单元测试Linux部…

Nature Communications 基于触觉手套的深度学习驱动视触觉动态重建方案

在人形机器人操作领域&#xff0c;有一个极具价值的问题&#xff1a;鉴于操作数据在人形操作技能学习中的重要性&#xff0c;如何有效地从现实世界中获取操作数据的完整状态&#xff1f;如果可以&#xff0c;那考虑到人类庞大规模的人口和进行复杂操作的简单直观性与可扩展性&a…