当前位置: 首页 > article >正文

WPF【11_10】WPF实战-重构与美化(配置Material UI框架)

11-16 【UI美化】配置Material UI框架

三种比较主流的 UI 设计规范,分别是:
苹果的扁平化 UI 设计、安卓或者说谷歌 的 Material Design 以及微软的 Metro 风格。

这三种风格都极具特色,不过我们接下来将会使用的是 Material Design 。在 WPF 中有一个基于 Material UI 风格的开源框架,我们可以直接使用。
“WPF_CMS”项目右击 - Manage NuGet Packages... - 搜索“MaterialDesign”找到:MaterialDesignThemes ,安装完之后,找到文档页面看看,找到:
Getting Started
Checkout the Super Quick Start 【点击】这里就是要处理的安装步骤了,接下来编辑 App.xaml 

拷贝下面到 <Application.Resources> 标签内:
<ResourceDictionary>
    <ResourceDictionary.MergedDictionaries>
        <materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="DeepPurple" SecondaryColor="Lime" />
        <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
    </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

此时,VS会报错,点击“更改意义(波浪线提示)”会自动加入:
<Application …………
    xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"

运行项目,UI 一下子就变了。我们的按钮变了,字体也变了,甚至是我们在点击切换客户的时候,客户列表也能产生 Material UI 特有的波纹效果了。

接下来我们学习如何使用这个 UI 框架来美化用户界面。
回到项目我们首先来修改主页的 UI ,打开 MainWindow.xaml 先来修改 Window 元素的属性,首先是主页背景变透明
<Window x:Class="WPF_CMS.MainWindow"
    …………
    xmlns:MaterialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
    mc:Ignorable="d"
    Title="CMS客户管理系统" Height="600" Width="900" Background="Transparent" AllowsTransparency="True" WindowStyle="None" WindowStartupLocation="CenterScreen" FontFamily="Cambria">

接下来我们需要给这个页面添加一点点底色和边框,添加边框使用 <Border> 元素,我们用 Border 把整个页面内容全部包裹起来,底色设置为白色,四个角加上圆弧形的设计,CornerRadius="30" 。

运行一下项目看看效果,页面运行起来整体效果稍微好看一点。

接下来我们来更换内容 UI ,首先我们把这个各种的按钮给它改小一点,位置稍微修理一下。
接下来处理客户信息,为了让这个内容显得更加立体我们可以选择使用 Material Design 的卡片组件,把整个客户信息都包裹起来,找到客户信息的部分第二个是 StackPanel ,使用 <MaterialDesign:Card > 这个元素。

用这个 <MaterialDesign:Card > 元素包裹整个 StackPanel ,并且把 StackPanel 的 【Grid.Row="1" Grid.Column="1"】 向上移动一个级别,程序报错没有关系,请使用 Visual Studio 的建议:添加 Material Design 的主题命名空间。

回到 card 元素继续补充一点属性 【Width="250" Height="440" Margin="10"】 
好了,运行一下代码我们看看效果,可以看到在加上 card 元素以后我们的客户信息界面变得立体了。

同样的方法我们来更新一下客户预约的 UI ,…… 客户详情页面还是比较丑的,那么我们加上一张贴图吧。
……客户详情的 StackPanel 中我们加上一个 Border 如下:
<StackPanel >
    <Border Margin="10" CornerRadius="20" Background="#FFFFEEFA">
        <Image Source="/Images/cartoon.png" Stretch="Uniform" Height="150" />
    </Border>

添加好图片以后还要更新:姓名、身份证和地址的输入框。 Material UI 已经帮我们处理好文本框的样式了,我们直接使用就可以。
接下来我们可以删掉所有的这个 TextBox ,等会我们会利用 Material Design 来把这个文字标签和输入框整合到一起去。
更新一下姓名的 TextBox 如下:
<TextBox 
    Name="NameTextBox" 
    Margin="10" 
    Style="{StaticResource MaterialDesignOutlinedTextBox}"
    MaterialDesign:HintAssist.Hint="姓名"
    Text="{Binding SelectedCustomer.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

使用类似的方法我们来处理:身份证和住址 的 TextBox 。


11-17 【UI美化】预约日历:自定义依赖属性

首先我们来注释掉这一行预约列表,然后添加一个日历 Calendar 元素。
<Calendar Name="AppointmentCalender" Height="320" Width="300"></Calendar>

运行一下看看效果整体的效果还是不错的,使用日历可以让整个预约列表看起来更加直观、更加友好。
接下来我们希望能在日历上显示客户的预约日期,如果日历上某一天客户已经有预约了,那么这一天需要显示在日历上并且变为灰色,而且这一天不可以再进行选择。

在 WPF 中有一个内部元素叫做 BlackoutDates 可以满足我们的需求,我们可以试试看。
<Calendar Name="AppointmentCalender" Height="320" Width="300">
    <Calendar.BlackoutDates>
        <CalendarDateRange Start="3/1/2022" End="3/7/2022" />
    </Calendar.BlackoutDates>
</Calendar>

如上面的,那么 3 月 1 号到 3 月 7 号之间的日期全部都会被灰掉,无法再进行选择。

不过问题来了 WPF 中这个默认的 BlackoutDates 是不支持 MVVM 数据绑定的,也就是说我们不能通过 ViewModel 来对 BlackoutDates 进行动态的变化。
比如说我们回到代码在 Calendar 的元素中使用 BlackoutDates (如下),
<Calendar Name="AppointmentCalender" Height="320" Width="300" BlackoutDates="{Binding Appointments, Mode=TwoWay}">
</Calendar>

那么这个时候 Visual Studio 会报错它会告诉我们 【The property "BlackoutDates" does not have an accessible setter.】

也就是说 BlackoutDates 的属性是无法更改的,它是只读的。这是微软官方给我们的解释,在得知到这个情况以后我不由得对微软产品的品控产生了怀疑。

因为
第一,从业务的角度来说微软没有任何理由把这个 BlackoutDates 设置为只读属性;
第二,这么常用的一个功能居然没有官方的解决方案来处理数据的绑定;
第三,这种情况是一个非常普遍的现象,WPF 中很多原生的组件都有这样类似的问题,无法进行 ViewModel 的绑定。比如说日历组件中的 SelectedDates 多选日期,也同样是因为这个原因无法进行数据绑定。所以难怪有人说微软东西不好用,它的产品设计不完善确实令人很头痛。

但是天无绝人之路解决的办法还是有的,我们有两种方案:
第一种也是最简单的就是对于日历组件我们可以放弃 MVVM ,直接在 View 中访问数据库,通过 View 来控制 UI 的显示,
比如在 MainWindow.cs 文件中通过 UI 调用的方式来设置 BlackoutDays :

private void AddAppointment_Click(object sender, RoutedEventArgs e)
{
    AppointmentCalender.BlackoutDays = ……
}

但是这绝对不是我们希望的,我们还是希望能够统一使用 MVVM 的架构来处理所有的业务。

对于一个程序员来说,只要是技术层面的问题总是会有解决方案的。
还记得“9-7 【操作】依赖属性与数据处理”学到的【DependencyProperty】吗?

其实在这里我们就可以通过一个自定义的属性依赖来解决数据绑定的问题,那么有了这个方向我们实现起来就有希望了。
不过对于程序员来说除了具备问题分析能力和扎实技术水平以外,我们还需要具备另外两个辅助的能力:就是问题的搜索能力和阅读理解能力。

在实际工作中会发现有很多的代码问题在中文圈子里可能找不到答案,那么这个时候请一定要善于利用手边的各种搜索工具,不仅要能搜索中文,同样也要能进行简单的英文搜索。

搜索关键词 "WPF Blackout Dates Binding" ,一般来说我们在实际工作中所遇到的问题99% 都能在这个叫做 stackoverflow.com 的网站上得到解决的思路。这个 StackOverflow 汇集了全世界几乎所有的程序员各种稀奇古怪的问题。建议一定要学会善于利用这个网站。
https://stackoverflow.com/questions/1638128/how-to-bind-blackoutdates-in-wpf-toolkit-calendar-control

页面这里有三个答案,
其中第一条有 18 个认同,那这就代表至少有 18 个人通过这个问题解决了类似的实际问题。
不过先不要着急我们继续看看其他的答案,第二个答案有 8 个认同,而答案的第一句话 【Here is an improved version for 某某某 answer】 这是对上面第一个答案的改进,那它改进的内容是什么呢? 
抓重点【allow to work with ObservableCollection<DateTime>】中使用 DateTime 来进行日历的绑定,那这不就正是我们需要的答案吗。

或许这个答案值得我们一试,复制代码,在根目录下创建一个新文件夹“ArrachedProperties”这里将会存放我们自定义的依赖属性,在文件夹中新建一个文件命名为 CalendarAttachedProperties.cs ,把代码一字不落全部粘贴进来。

好了我们先不要去考虑代码的正确性,只要不报错就是好代码。不过还有个小问题需要修改一下我们找到【添加 calendar.BlackoutDates.Clear();】:

private static void CalendarBindings_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    ObservableCollection<DateTime> blackoutDates = sender as ObservableCollection<DateTime>;

    Calendar calendar = _calendars.First(c => c.Tag == blackoutDates);
    if (e.Action == NotifyCollectionChangedAction.Reset)
    {
        calendar.BlackoutDates.Clear();
    }

    if (e.Action == NotifyCollectionChangedAction.Add)
    {
        foreach (DateTime date in e.NewItems)
        {
            calendar.BlackoutDates.Add(new CalendarDateRange(date));
        }
    }
}

接下来我们回到 MainViewModel ,前面我们说到填充 Appointments 这个列表所需要的是 DateTime 时间,而不再是 ViewModel 了。所以我们需要改一下:

public ObservableCollection<AppointmentViewModel> Appointments { get; set; } = new();
改为
public ObservableCollection<DateTime> Appointments { get; set; } = new();

在 LoadAppointments 这个方法中,同样也需要修改一下。

回到 MainWindow.xaml 文件现在我们就可以进行数据绑定了。
但在数据绑定之前需要在 Window 根元素下引入刚刚所创建的文件的命名空间,引入命名空间的语法与引入 Material Design 的语法结构类似,使用 xmlns 加上冒号然后输入一个自己喜欢的名称来表示这个命名空间,可以叫做 alex 如下:
<Window x:Class="WPF_CMS.MainWindow"
    …………
    xmlns:MaterialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
    xmlns:alex="clr-namespace:WPF_CMS.ArrachedProperties"
    mc:Ignorable="d"
    …………>
<Border Background="White" CornerRadius="30">
    <Grid>
        …………
        <Calendar Name="AppointmentCalender" Height="320" Width="300"></Calendar>
        …………
    </Grid>
</Border>
</Window>

好了命名空间引入完毕,接下来回到日历控件,那么现在我们就可以像使用普通属性一样来使用刚刚创建的自定义依赖属性来绑定视图模型了。输入命名空间 alex: 如下:
        <Calendar Name="AppointmentCalender" Height="320" Width="300" alex:CalendarAttachedProperties.RegisterBlackoutDates="{Binding Appointments, Mode=OneWay}" SelectedDate="{Binding SelectedDate, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></Calendar>

报错不要紧,我们 Ctrl + B 构建一下项目就可以了。好的现在报错消失代码完成,我们运行一下试试看。选择客户xxx现在的感觉就很好了,预约列表切换成了预约日历,界面更加直观、更加友好,而且客户xxx他的预约日期全部都以灰色的形式显示在日历上了。

接下来,最后一个功能添加客户预约。因为我们已经使用了这样一个日历组件了,所以接下来我们就不再需要 DatePicker 了。我们只需要在日历上选定一个日期,点击预约就可以了。

那么开始改造吧,为了能够对应日历的日期选择,我们首先应该在视图模型中添加一个日期类一个私有的 DateTime 成员变量,变量名称 _selectedDate ;对应私有成员变量我们还需要有一个外部可以使用的 DateTime 属性 SelectedDate,Set 时我们需要注意一下需要对它做一个判断,尤且仅当日期发生变化的时候我们才会执行页面的更新逻辑。
……当属性变化的时候我们需要触发 UI 组件的更新,所以 UpdateSourceTrigger=PropertyChanged 。

接下来删掉 DatePicker ,也删掉添加新预约的 Textbox ,最后进入这个 AddAppointment_Click ,首先咱们删掉 DateTime 的参数,因为这个参数将会来自视图模型,然后进入 AddAppointment 方法,同样因为 SelectedDate 来自 ViewModel ,所以我们把参数删掉而在创建新预约的过程中我们需要把视图模型的 ViewModel 传进来。不过注意这个 SelectedDate 实际上是一个可空类型,所以请回到 SelectedDate 我们给它加上问号,让它变成一个可空类型。

public class MainViewModel : INotifyPropertyChanged
{
    …………
    private DateTime? _selectedDate;
    public DateTime? SelectedDate { 
        get => _selectedDate; 
        set
        {
            if(_selectedDate != value)
            {
                _selectedDate = value;
                RaisePropertyChanged(nameof(SelectedDate));
            }
        } 
    }
    …………

    public void AddAppointment()
    {
        if (SelectedCustomer == null)
        {
            return;
        }

        using (var db = new AppDbContext())
        {
            var newAppointment = new Appointment()
            {
                Time = SelectedDate.Value,
                CustomerId = SelectedCustomer.Id
            };
            db.Appointments.Add(newAppointment);
            db.SaveChanges();
        }
        SelectedDate = null;
        LoadAppointments(SelectedCustomer.Id);
    }
}

相关文章:

WPF【11_10】WPF实战-重构与美化(配置Material UI框架)

11-16 【UI美化】配置Material UI框架 三种比较主流的 UI 设计规范&#xff0c;分别是&#xff1a; 苹果的扁平化 UI 设计、安卓或者说谷歌 的 Material Design 以及微软的 Metro 风格。 这三种风格都极具特色&#xff0c;不过我们接下来将会使用的是 Material Design 。在 W…...

(自用)Java学习-5.16(取消收藏,批量操作,修改密码,用户更新,上传头像)

1. 取消收藏功能 前端实现&#xff1a; 用户点击“取消收藏”按钮时&#xff0c;前端通过变量status判断当前状态&#xff08;0为未收藏&#xff0c;1为已收藏&#xff09;。 发送AJAX请求到后端接口&#xff1a; 添加收藏&#xff1a;/favoriteise/addFavoriteise?pid商品ID…...

【Node.js】部署与运维

个人主页&#xff1a;Guiat 归属专栏&#xff1a;node.js 文章目录 1. Node.js 部署概述1.1 部署的核心要素1.2 Node.js 部署架构全景 2. 传统服务器部署2.1 Linux 服务器环境准备系统更新与基础软件安装创建应用用户 2.2 应用部署脚本2.3 环境变量管理2.4 Nginx 反向代理配置2…...

【Java Web】速通JavaScript

参考笔记:JavaWeb 速通JavaScript_javascript 速通-CSDN博客 目录 一、JavaScript快速入门 1. 基本介绍 2. JavaScript特点 3. JavaScript的引入方式(重要) 3.1 写在script标签中 ​​​​​3.2 以外部文件方式引入 二、JS的数据类型 1. 变量 2. 常用数据类型 3.特殊值 三、…...

TDengine 运维——巡检工具(安装前预配置)

背景 TDengine 的安装部署对环境系统有一定的依赖和要求&#xff0c;安装部署前需要进行环境预配置操作&#xff0c;本文档旨在说明安装前预配置工具在安装 TDengine 前对环境的预配置内容和工具的使用方法。 预配置工具使用方法 工具支持通过 help 参数查看支持的语法 Usa…...

C#索引器详解:让对象像数组一样被访问

索引器是C#中一个强大而实用的特性&#xff0c;它允许我们像访问数组一样访问类的成员。本文将全面介绍索引器的概念、语法、实现方式以及实际应用场景。 索引器基础概念 索引器&#xff08;Indexer&#xff09;是一组get和set访问器&#xff0c;与属性类似&#xff0c;但有以…...

机器学习课设

&#x1f393; 图像处理课程设计任务书 课程名称&#xff1a; 图像处理与模式识别 课设题目&#xff1a; 基于手工特征提取与传统机器学习方法的图像分类系统实现 一、课设目的 本课程设计旨在加深对图像处理与分类算法的理解&#xff0c;提升图像特征提取、传统机器学习模…...

vue 如何对 div 标签 设置assets内本地背景图片

在 Vue 中为 <div> 设置 assets 目录下的本地背景图片&#xff0c;需要通过 Webpack 或 Vite 等构建工具 处理路径引用。以下是详细实现方法&#xff1a; 一、项目结构说明 假设你的项目结构如下&#xff1a; src/assets/images/bg.jpg # 背景图片components/…...

wsl2 docker重启后没了

参考这篇文章&#xff1a;wsl2 docker重启后没了_mob64ca12f55920的技术博客_51CTO博客...

ubuntu 22.04 配置静态IP、网关、DNS

1、打开配置文件 vi /etc/netplan/00-installer-config.yaml 2、修改文件内容 # This is the network config written by subiquity network:ethernets:ens33:dhcp4: false # 禁用 dhcpaddresses:- 192.168.12.15/24 # 静态IProutes:- to: defaultvia: 192.168.12.254 …...

RDS PostgreSQL手动删除副本集群副本的步骤

由于PostgreSQL不支持直接删除副本集群&#xff0c;而是需要先将副本集群升级到主实例(区域集群)&#xff0c;然后在逐一将写入器实例删除&#xff0c;然后才可以删除副本集群 查看现有的主从实例集群 将副本集群提升到区域集群 选择副本集群–>操作–>提升 提升只读副本…...

MySQL 自增主键重置详解:保持 ID 连续性

目录 前言正文 前言 爬虫神器&#xff0c;无代码爬取&#xff0c;就来&#xff1a;bright.cn Java基本知识&#xff1a; java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&#xff09;【Java项目】实战CRUD的功能整理&#xff08;持续更新&#xff09…...

Vue Hook Store 设计模式最佳实践指南

Vue Hook Store 设计模式最佳实践指南 一、引言 在 Vue 3 组合式 API 与 TypeScript 普及的背景下&#xff0c;Hook Store 设计模式应运而生&#xff0c;它结合了 Vue 组合式 API 的灵活性与状态管理的最佳实践&#xff0c;为开发者提供了一种轻量级、可测试且易于维护的状态…...

国产化Word处理控件Spire.Doc教程:通过Java简单快速的将 HTML 转换为 PDF

在处理 HTML 文件时&#xff0c;你可能会发现它们在不同的浏览器和屏幕尺寸下的显示效果并不一致。而将 HTML 转换为 PDF 则可以有效地保留其布局和格式&#xff0c;从而确保内容在不同设备和平台上的呈现保持一致。本文将介绍如何在 Spire.Doc for Java 的帮助下通过 Java 将 …...

Spring AI 1.0 GA深度解析与最佳实践

随着人工智能技术的快速发展&#xff0c;Spring AI 1.0 GA 的发布标志着 Spring 生态在 AI 领域迈出了重要一步。本文将从原理、全景架构设计、最佳实践、性能测试对比等维度&#xff0c;全面解析如何基于 Spring AI 构建企业级 AI 应用&#xff0c;并以接入 DeepSeek 大模型为…...

Java求职面试:从Spring到微服务的技术挑战

Java求职面试&#xff1a;从Spring到微服务的技术挑战 在这个故事中&#xff0c;我们将进入一个模拟的互联网大厂Java求职者面试现场。面试官严肃而专业&#xff0c;而求职者谢飞机则以其幽默和捉摸不透的回答&#xff0c;让面试过程充满了趣味。 第一轮&#xff1a;基础框架…...

鸿蒙OSUniApp 开发的图文混排展示组件#三方框架 #Uniapp

使用 UniApp 开发的图文混排展示组件 在移动应用开发中&#xff0c;图文混排展示是资讯、社区、电商、教育等场景中极为常见的需求。一个灵活、美观的图文混排组件&#xff0c;不仅能提升内容的可读性&#xff0c;还能增强用户的视觉体验。随着 HarmonyOS&#xff08;鸿蒙&…...

WHAT - 学习 WebSocket 实时 Web 开发

文章目录 一、基础知识了解1. WebSocket 是什么&#xff1f;2. 它的优势&#xff1a; 二、基本工作流程三、快速体验&#xff1a;使用原生 WebSocket客户端&#xff08;浏览器端 JS&#xff09;&#xff1a;服务端&#xff08;Node.js 示例&#xff0c;使用 ws 库&#xff09; …...

5G NTN卫星通信发展现状(截止2025年3月)

今天咱们用实实在在的数据唠唠卫星通信这事儿—这些数字可比科幻片还刺激&#xff0c;直接告诉你这玩意儿现在有多火&#xff0c;未来能有多野&#xff01; 先甩个大数字&#xff1a;截至2025年3月&#xff0c;全球已经有143个运营商和卫星厂商的合作项目&#xff0c;覆盖53个国…...

【计算机网络】第2章:应用层—DNS

目录 一、PPT 二、总结 DNS&#xff08;域名系统&#xff09;详解 &#xff08;一&#xff09;DNS核心概念 &#xff08;二&#xff09;DNS查询过程&#xff08;重点❗&#xff09; &#xff08;三&#xff09;DNS资源记录&#xff08;RR&#xff09;类型…...

[Linux]虚拟地址到物理地址的转化

[Linux]虚拟地址到物理地址的转化 水墨不写bug 文章目录 一、再次认识地址空间二、页表1、页表的结构设计2、页表节省了空间&#xff0c;省在哪里&#xff1f;3、页表的物理实现 一、再次认识地址空间 OS和磁盘交互的内存基本单位是4KB&#xff0c;这4KB通常被称为内存块。OS对…...

Linux线程入门

目录 Linux线程概念 什么是线程 重新理解进程 线程的优点 线程的缺点 线程的异常 线程用途 Linux线程概念 什么是线程 在一个程序里的一个执行路线就叫做线程&#xff08;thread&#xff09;。更准确的定义是&#xff1a;线程是“一个进程内部的控制序列”。一切进程至…...

Kubernetes超详细教程,一篇文章帮助你从零开始学习k8s,从入门到实战

k8s 概述 k8s github地址&#xff1a;https://github.com/kubernetes/kubernetes 官方文档&#xff1a;https://kubernetes.io/zh-cn/docs/home/ k8s&#xff0c;全程是 kubernetes&#xff0c;这个名字源于希腊语&#xff0c;意为"舵手"或"飞行员” k8s 这…...

Docker基础 -- Ubuntu 22.04 AArch64 交叉编译 Docker 镜像构建指南

Ubuntu 22.04 AArch64 交叉编译 Docker 镜像构建指南 作者&#xff1a; &#xff08;填写作者&#xff09; 发布日期&#xff1a; 2025‑05‑26 1 背景与目标 在企业内网&#xff08;需要代理&#xff09;环境下&#xff0c;我们需要一套可靠、可复用的 Ubuntu 22.04 交叉编…...

【Elasticsearch】使用脚本删除索引中的某个字段

在 Elasticsearch 中&#xff0c;删除索引中的某个字段可以通过以下几种方式实现&#xff0c;具体取决于你的需求和场景。以下是几种常见的方法&#xff1a; 方法 1&#xff1a;使用 _update_by_query API 删除字段 _update_by_query API 可以对索引中的文档执行批量更新操作&…...

OpenHarmony平台驱动使用(二),CLOCK

OpenHarmony平台驱动使用&#xff08;二&#xff09; CLOCK 概述 功能简介 CLOCK&#xff0c;时钟是系统各个部件运行的基础&#xff0c;以CPU时钟举例&#xff0c;CPU 时钟是指 CPU 内部的时钟发生器&#xff0c;它以频率的形式工作&#xff0c;用来同步和控制 CPU 内部的各…...

我们是如何为 ES|QL 重建自动补全功能的

作者&#xff1a;来自 Elastic Drew Tate Elasticsearch 拥有许多新功能&#xff0c;可以帮助你根据使用场景构建最佳搜索方案。浏览我们的示例笔记本了解更多内容&#xff0c;开始免费试用云服务&#xff0c;或者立即在本地机器上尝试 Elastic。 对于我们开发者来说&#xff0…...

Keepalived 配置 VIP 的核心步骤

Keepalived 配置 VIP 的核心步骤主要涉及安装软件、主备节点配置及服务管理。以下是具体操作指南: 一、安装 Keepalived ‌Ubuntu/Debian 系统‌ sudo apt update sudo apt install keepalived ‌CentOS/RHEL 系统‌ sudo yum install keepalived 注:需确保已配置 EPE…...

如何使用 Redis 快速实现排行榜?

Redis 的 Sorted Set&#xff08;有序集合&#xff09; 是实现排行榜的高效工具&#xff0c;其天然支持按分数排序、范围查询和原子操作。以下是快速实现排行榜的步骤和核心方案&#xff1a; 一、核心数据结构&#xff1a;Sorted Set 特性&#xff1a; 每个成员&#xff08;me…...

MATLAB在逐渐被Python淘汰吗

MATLAB在学术研究、工程仿真、数值计算等传统领域仍占据一席之地&#xff0c;但Python因其开源免费、生态丰富、易于集成的优势&#xff0c;正在快速崛起&#xff0c;逐步蚕食MATLAB的市场份额。尤其在人工智能、数据分析和科学计算等领域&#xff0c;Python的优势愈发明显。例…...