WPF复习知识点记录

这篇具有很好参考价值的文章主要介绍了WPF复习知识点记录。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

WPF复习知识点记录

由于近几年主要在做Web项目,客户端的项目主要是以维护为主,感觉对于基础知识的掌握没有那么牢靠,趁着这个周末重新复习下WPF的相关知识。

文章内容主要来自大佬刘铁锰老师的经典著作《深入浅出WPF》。

因为是复习,所以知识内容不会一一记录,如有需要了解更多可以看书中内容。

注意:博客中的代码示例我是以avalonia为UI框架写的。代码可能部分跟WPF的稍有不同。

1.从零起步认识XAML

1.什么是XAML

XAML(读作zaml)是WPF技术中专门用于设计UI 的语言

2.优点

  • 实现界面与代码的分离
  • 可以设计出专业的UI和动画
  • 基于XML的标记语言,简单易懂,结构清晰

3.XAML剖析

1.最简单的XAML代码

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
</Window>

这个示例中,Window是一个XAML元素,它表示窗口组件。xmlns属性定义了XML命名空间,即指明XAML所使用的命名空间。在这里,http://schemas.microsoft.com/winfx/2006/xaml/presentation是WPF的命名空间。

这个示例中的XAML代码只有一个Window元素,它是一个空的容器。可以在Window元素中添加其他界面元素,例如按钮、文本框等,来构建应用程序的用户界面。同样,可以在XAML中设置属性来更改元素的外观和行为。

2.property和attribute

先不说WPF中两个属性的定义,我们先看看对应一个类的对象。

1)属性是指类体里用get或set封装好的属性。属性是面向对象的理论范畴。比如说一个盒子,盒子的高度,长度,都是这个盒子的属性。在C#中实现的时候可以通过GET SET 封装。

2)特性是指应用于类,字段,方法,接口的进一步说明,用专业的术语就是给类,字段,方法,接口补充元数据,说的再白一点就是给它们打上标记,打了标记后编译器就知道如何来编译它。特性是属于编程语言层面的东西。比如2个相同的类,为了表示这2个类不完全相同或者有差异。这时候就要针对这两个类加一些特性。

[Serializable]                                   // 这是Attribute,打上该标记的类说明可以被序列化
class Order
{
   protected internal Single Price { get; set; } // 这是Property

   [Obsolete("此方法已过时,请改用xxx.")]           // 打上该标记说明此方法是过时的
   public Single GetPrice()
   {
      return default(Single);
   }
}

在看在XAML中:

Attribute 在XAML中的对于标签的属性特征,以下都是Window标签下的attribute

xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:AvaloniaMarkdown.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="AvaloniaMarkdown.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
xmlns:md="clr-namespace:Markdown.Avalonia;assembly=Markdown.Avalonia"
Icon="/Assets/avalonia-logo.ico"
Title="AvaloniaMarkdown"

Property 在后台代码中针对对象的属性特征,对应的后端类的对象Text,就是一个 property:

private string _text="hello";
public string Text
{
    get => _text;
    set => this.RaiseAndSetIfChanged(ref _text, value);
}
private string _filePath;

3.xmlns 名称空间

xmlns[:可选的映射前缀]="名称空间"

用于引用外来程序集

xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:AvaloniaMarkdown.ViewModels"

没有映射前缀的是默认名称空间,默认名称空间只能有一个。

通过xmlns,我们可以直接使用这些CLR名称空间中的类型

4.partial关键字

XAML文件对应的.xaml.cs文件中的类的声明使用了partial关键字,可以把一个类拆分在多处定义,只要各部分代码不冲突即可,由于partial机制,我们实现逻辑代码留在.cs文件中,把UI元素相关代码分离出去。

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

}

2.XAML语法

1.树形结构

<Window>
	<Grid>
		<Grid.ColumnDefinitions>
			<ColumnDefinition Width="10*"/>
			<ColumnDefinition Width="10*"/>
		</Grid.ColumnDefinitions>
		<Grid.RowDefinitions>
			<RowDefinition Height="1*"/>
			<RowDefinition Height="10*"/>
		</Grid.RowDefinitions>
		<Grid Grid.Row="0"
            Grid.Column="0" Grid.ColumnSpan="2">
			<Grid.ColumnDefinitions>
				<ColumnDefinition Width="1*"/>
				<ColumnDefinition Width="9*"/>
			</Grid.ColumnDefinitions>
			<StackPanel Grid.Column="0" >
				<Button>打开</Button>
				<Button>保存</Button>
				<Label/>
			</StackPanel>
		</Grid>
		<TextBox Grid.Row="1" Grid.Column="0"/>
		<md:MarkdownScrollViewer Grid.Row="1"
            Grid.Column="1"/>
	</Grid>  
</Window>

XAML UI 框架是树状结构,以对象为根节点,一层一层往下包含。我们经常需要在这棵树上进行按名称查找元素、获取父子节点等操作。WPF使用VisualTreeHelper、LogicalTreeHelper来操作树。

2.x:Name

x:Name的作用:

  1. 告诉XAML编译器,带有x:Name的标签需要声明一个引用变量,变量名就是x:Name的值
  2. 将XAML标签对应的对象的Name属性也设为x:Name的值,并注册到UI树上,方便查找

2.x:Key

在资源字典(Resource Dictionary)中使用,构成其中的元素。资源(Resource )非常重要,存放需要重复使用的内容。

	<Application.Resources>
		<Color x:Key="SystemAccentColor">rgb(155, 138, 255)</Color>
		<Color x:Key="SystemAccentColorDark1">rgb(155, 138, 255)</Color>
		<Color x:Key="SystemAltMediumLowColor">rgb(52, 53, 65)</Color>
		<Color x:Key="ApplicationPageBackgroundThemeBrush">rgb(52, 53, 65)</Color>
		<Color x:Key="ControlStrokeColorDefaultBrush">rgb(94, 95, 109)</Color>
	</Application.Resources>

3.控件

1.ContentControl 单一内容控件

只能单一元素充当其内容。

例如:Button、Label等(具体看书中列表)

2.HeaderdContentControl

除了用于显示主体内容的区域外,控件还具有一个显示标题(header)的区域

例如:GroupBox、TabItem

3.ItemsControl

  • 显示列表化的数据
  • 内容属性为Items或ItemsSource
  • 每种ItemsControl都对应有自己的条目容器(Item Container)

例如:ListBox、TreeView

4.Decorator

在UI 上起装饰效果,比如可以使用Border元素为一些组织在一起的内容加个边框

例如:Border、ViewBox

5.TextBlock和TextBox

最常用的文本控件

  • TextBlock 用于显示文本,不能编辑
  • TextBox 允许编辑内容

6.Shape

绘制图形使用的元素

  • Fill 属性设置填充
  • Stroke 属性设置边线

7.Panel

所有的UI布局元素都属于这一族

Panel元素控制布局

包括:Canvas、Grid、StackPanel等

4.布局

WPF的UI形成的树形结构,我们称之为可视化树(Visual Tree)

控件框架形成的树形结构,我们称之为逻辑树(Logic Tree)

五种大类

  • Grid 网格面板
  • DockPanel 停靠面板
  • StackPanel 栈面板
  • WrapPanel 环绕面板
  • Canvas 精准定位

下面复习下它们的使用方法:

1.Grid

网格形式布局

1.CloumnDefinitions

定义多少列

2.RowDefinitions

定义了多少行

	<Grid>
		<Grid.ColumnDefinitions>
			<ColumnDefinition Width="10*"/>
			<ColumnDefinition Width="10*"/>
		</Grid.ColumnDefinitions>
		<Grid.RowDefinitions>
			<RowDefinition Height="1*"/>
			<RowDefinition Height="10*"/>
		</Grid.RowDefinitions>
		<Grid Grid.Row="0"
            Grid.Column="0" Grid.ColumnSpan="2">
			<Grid.ColumnDefinitions>
				<ColumnDefinition Width="1*"/>
				<ColumnDefinition Width="9*"/>
			</Grid.ColumnDefinitions>
			<StackPanel Grid.Column="0" Orientation="Horizontal" HorizontalAlignment="Center">
				<Button Classes="small" Margin="0,0,20,0" Command="{Binding UploadCommand}">打开</Button>
				<Button Classes="small" Margin="0,0,20,0" Command="{Binding SaveCommand}">保存</Button>
				<Label Content="{Binding FilePath}" Margin="0,0,20,0"/>
			</StackPanel>
	</Grid>

3.Grid长宽常用设置值

  • 绝对值:double 数值后加单位后缀
  • 比例值:double数值后加一个星号(*)(如上例)
  • 自动值:Auto

2.StackPanel

StackPanel可以把内部的元素在纵向或横向上紧凑排列,形成栈式布局

适合场合:

  • 同类元素需要紧凑排列(列表或菜单)
  • 移除其中的元素后能够自动补缺的布局或者动画

1.属性

常用属性 数据类型 可选值 说明
Orientation Orientation Horizontal(水平排列)\Vertical(垂直排列) 决定内部元素是水平还是垂直排列,默认值(Vertical)
Background Brush 背景色(Red/Yellow等等)
HorizontalAlignment HorizontalAlignment Center(中心)/Left(靠左)/Right(靠右)/Stretch(拉伸以填充父元素) 决定内部元素在水平方向的对齐方式
VerticalAlignment VerticalAlignment Top(上方)/Center(中心)/Bottom(下方)/Stretch(拉伸以填充父元素) 决定内部元素在垂直方向的对齐方式

3.Canvas

画布,可以使用Left、Top、Right、 Bottom。内部元素通过离上下左右的距离控制元素在布局中的位置。

4.DockPanel

DockPanel会对每个子元素进行排序,并停靠在面板的一侧,多个停靠在同侧的元素则按顺序排序,。

<Grid>
    <DockPanel Width="Auto" Height="Auto">
        <Button DockPanel.Dock="Left" >1</Button>
        <Button DockPanel.Dock="Top">2</Button>
        <Button DockPanel.Dock="Right">3</Button>
        <Button DockPanel.Dock="Bottom">4</Button>
    </DockPanel>
</Grid>

5.WrapPanel

流式布局,根据Orientation属性来设置其水平或垂直布局方向

默认是水平排列

<WrapPanel>
    <Button />
    <Button />
    <Button />
    <Button />
    <Button />
    <Button />
</WrapPanel>

垂直排列

<WrapPanel Orientation="Vertical">
</WrapPanel>

5.Binding 绑定

数据交互核心属性,在字段定义的set语句中使用一个PropertyChanged事件,,当为Binding设置了数据源后,就会自动侦听PropertyChanged事件

WPF

using CommunityToolkit.Mvvm
    
private string _searchKeyword;
public string SearchKeyword
{
    get => _searchKeyword;
    set => SetProperty(ref _searchKeyword, value);
}

Avalonia

using ReactiveUI;

private string _filePath;

public string FilePath 
{ 
    get => _filePath;
    set => this.RaiseAndSetIfChanged(ref _filePath, value);
}

6.Dependency Property 依赖属性

依赖属性是一种本身没有可以没有值,能通过使用Binding从数据源获取值的属性。拥有依赖属性的对象称为“依赖对象”

特点包括:

  • 节省实例对内存的开销
  • 属性值可以通过Binding依赖在其他的对象上

7.Attached Property 附加属性

附加属性,被环境赋予的属性,作用是将属性与数据类型(宿主)解耦,让数据类型的设计更加灵活

	<Grid>
		<Grid.ColumnDefinitions>
			<ColumnDefinition Width="10*"/>
			<ColumnDefinition Width="10*"/>
		</Grid.ColumnDefinitions>
		<Grid.RowDefinitions>
			<RowDefinition Height="1*"/>
			<RowDefinition Height="10*"/>
		</Grid.RowDefinitions>
		<Grid Grid.Row="0"
            Grid.Column="0" Grid.ColumnSpan="2">
			<Grid.ColumnDefinitions>
				<ColumnDefinition Width="1*"/>
				<ColumnDefinition Width="9*"/>
			</Grid.ColumnDefinitions>
			<StackPanel Grid.Column="0" >
				<Button>打开</Button>
				<Button>保存</Button>
				<Label/>
			</StackPanel>
		</Grid>
		<TextBox Grid.Row="1" Grid.Column="0"/>
		<md:MarkdownScrollViewer Grid.Row="1"
            Grid.Column="1"/>
	</Grid> 

上面 TextBox 的Grid.Row,Grid.Column都是附加属性。

8.Route 和Event 路由事件

路由事件被激发后是沿着Visual Tree传递的,只有这样,“藏”在Templete里的控件才能把消息送出来。

9.Resource 资源

每个WPF的界面的元素都具有一个名为Resources的属性,这个属性继承自FrameWorkElement类,其类型为ResourceDictionary,用来存储资源。

	<Application.Resources>
		<ResourceDictionary>
			<ResourceDictionary.MergedDictionaries>
				<ResourceInclude Source="/Assets/Lang/en-US.axaml" />
			</ResourceDictionary.MergedDictionaries>
		</ResourceDictionary>

	</Application.Resources>

在使用资源时候分为静态资源(StaticResource)和动态资源(DynamicResource)

1.StaticResource

在程序载入内存时对资源一次性使用,之后就不再去访问这个资源了

 <TextBox Grid.Row="4"
			   Name="Editor3"
			   AcceptsReturn="True"
			   Text="{Binding Source={StaticResource VMLocator}, Path=EditorViewModel.Editor3Text,Mode=TwoWay}"
			   FontSize="{Binding Source={StaticResource VMLocator}, Path=EditorViewModel.EditorCommonFontSize}" />

2.StaticResource

程序运行过程中仍然会去访问资源

<Rectangle Name="PART_BottomRightCorner"
									   Fill="{DynamicResource DataGridScrollBarsSeparatorBackground}"
									   Grid.Column="2"
									   Grid.Row="2" />

10.Template 模板

1.ControlTemplate 控制器模板

<ControlTemplate>
					<Border Name="DataGridBorder"
							Background="{TemplateBinding Background}"
							BorderBrush="{TemplateBinding BorderBrush}"
							BorderThickness="{TemplateBinding BorderThickness}"
							CornerRadius="{TemplateBinding CornerRadius}">
						<Grid ColumnDefinitions="Auto,*,Auto" RowDefinitions="Auto,*,Auto,Auto">
							<DataGridColumnHeader Name="PART_TopLeftCornerHeader"
												  Theme="{StaticResource DataGridTopLeftColumnHeader}" />
							<DataGridColumnHeadersPresenter Name="PART_ColumnHeadersPresenter"
															Grid.Column="1"
															Grid.Row="0" Grid.ColumnSpan="2" />
							<Rectangle Name="PART_ColumnHeadersAndRowsSeparator"
									   Grid.Row="0" Grid.ColumnSpan="3" Grid.Column="0"
									   VerticalAlignment="Bottom"
									   Height="1"
									   Fill="{DynamicResource DataGridGridLinesBrush}" />

							<DataGridRowsPresenter Name="PART_RowsPresenter"
												   Grid.Row="1"
												   Grid.RowSpan="2"
												   Grid.ColumnSpan="3" Grid.Column="0">
								<DataGridRowsPresenter.GestureRecognizers>
									<ScrollGestureRecognizer CanHorizontallyScroll="True" CanVerticallyScroll="True" />
								</DataGridRowsPresenter.GestureRecognizers>
							</DataGridRowsPresenter>
							<Rectangle Name="PART_BottomRightCorner"
									   Fill="{DynamicResource DataGridScrollBarsSeparatorBackground}"
									   Grid.Column="2"
									   Grid.Row="2" />
							<Image Source="/Assets/maskGrad.png"
								   Grid.Row="1" Grid.RowSpan="2" Grid.Column="0" Grid.ColumnSpan="4"
								   VerticalAlignment="Stretch"
								   HorizontalAlignment="Right"
								   Width="60"
								   Stretch="Fill"
								   IsHitTestVisible="False"
								   ZIndex="1" />
							<ScrollBar Name="PART_VerticalScrollbar"
									   Orientation="Vertical"
									   Grid.Column="2"
									   Grid.Row="1"
									   Width="{DynamicResource ScrollBarSize}"
									   ZIndex="2" />
							
							<Grid Grid.Column="1"
								  Grid.Row="2"
								  ColumnDefinitions="Auto,*">
								<Rectangle Name="PART_FrozenColumnScrollBarSpacer" />
								<ScrollBar Name="PART_HorizontalScrollbar"
										   Grid.Column="1"
										   Orientation="Horizontal"
										   Height="{DynamicResource ScrollBarSize}" />
							</Grid>
							<Border Name="PART_DisabledVisualElement"
									Grid.ColumnSpan="3" Grid.Column="0"
									Grid.Row="0" Grid.RowSpan="4"
									IsHitTestVisible="False"
									HorizontalAlignment="Stretch"
									VerticalAlignment="Stretch"
									CornerRadius="2"
									Background="{DynamicResource DataGridDisabledVisualElementBackground}"
									IsVisible="{Binding !$parent[DataGrid].IsEnabled}" />
						</Grid>
					</Border>
				</ControlTemplate>

2.DataTemplate 数据模板

<DataTemplate>
    <TextBlock Text="{Binding Title}" />
</DataTemplate>

11.Style 风格

设计外观和行为动作

1.Setter 设置器

Setter 类的Property属性用来指明你想为目标的哪个属性赋值,Value属性则是你提供的属性值

<Style Selector="Grid Button">
    <Setter Property="BorderBrush" Value="rgb(94, 95, 109)" />
    <Setter Property="BorderThickness" Value="1" />
    <Setter Property="FontSize" Value="16" />
    <Setter Property="Padding" Value="10,0,10,2" />
    <Setter Property="Height" Value="32" />
    <Setter Property="CornerRadius" Value="6" />
    <Setter Property="Margin" Value="0" />
    <Setter Property="FontFamily" Value="avares://TmCGPTD/Assets/Lato-Regular.ttf#Lato" />
    <Setter Property="Transitions">
        <Transitions>
            <BrushTransition Property="Background" Duration="0:0:0.2" />
        </Transitions>
    </Setter>
</Style>

上面的例子是针对 Grid ButtonStyle,使用了若干个Setter 来设置 Grid 中的Button的一些属性,这样,在程序中, Grid 中的Button就会具有统一的风格。

2.Trigger 触发器

当条件满足时会触发一个行为。

<Grid>
    <TextBlock Text="raokun" Width="75" Height="20">
        <TextBlock.Style>
            <Style TargetType="TextBlock">
                <Style.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="Foreground" Value="blue" />
                    </Trigger>
                </Style.Triggers>
            </Style>
        </TextBlock.Style>
    </TextBlock>
</Grid>

上面的例子,是当鼠标移动在上面时,字体的颜色变成蓝色。文章来源地址https://www.toymoban.com/news/detail-514940.html

阅读如遇样式问题,请前往个人博客浏览: https://www.raokun.top
拥抱ChatGPT:https://ai.terramours.site
开源项目地址:https://github.com/firstsaofan/TerraMours

到了这里,关于WPF复习知识点记录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Pytorch基础知识点复习

    本篇博客是本人对pytorch使用的查漏补缺,参考资料来自 深入浅出PyTorch,本文主要以提问的方式对知识点进行回顾,小伙伴们不记得的知识点可以查一下前面的教程哦。   现在并行计算的策略是 不同的数据分布到不同的设备中,执行相同的任务(Data parallelism) 。   它的逻

    2024年01月20日
    浏览(42)
  • Web期末复习知识点

    下载Tomcat :前往Apache Tomcat官方网站(https://tomcat.apache.org)下载适合您操作系统的Tomcat版本。  安装Tomcat :解压下载的Tomcat压缩文件到您选择的目录。例如,将Tomcat解压到/opt/tomcat。 配置环境变量(可选) :如果需要在任何位置启动Tomcat,可以将Tomcat的bin目录添加到系统的

    2024年02月04日
    浏览(47)
  • 离散数学---期末复习知识点

    一、 数理逻辑   [ 复习知识点 ] 1、命题与联结词(否定¬、析取∨、合取∧、蕴涵→、等价↔),命题(非真既假的陈述句),复合命题(由简单命题通过联结词联结而成的命题) 2、命题公式与赋值(成真、成假),真值表,公式类型(重言、矛盾、可满足),公式的基本等值式

    2024年02月08日
    浏览(74)
  • java基础知识点复习①

    java是一门开源的面向对象的编程语言,具有面向对象的封装、继承、多态的特点。 封装:将类的某些信息隐藏起来,只提供特定的方法来访问或修改这些隐藏信息,从而防止直接操作类中的某些属性。是通过访问权限修饰符来实现封装的,public——protected——default——pri

    2023年04月22日
    浏览(52)
  • Java期末复习——知识点+题库

    简单、面向对象、平台无关、多线程、动态 Java 所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。 关于 Java 标识符,有以下几点需要注意: 所有的标识符都应该以字母(A-Z 或者 a-z),美元符($)、或者下划线(_)开始 首字符之后可以是字母(A-Z 或者

    2024年02月02日
    浏览(65)
  • Zookeeper 复习知识点(更新中)

    Zookeeper 是开源的,是一个基于观察者模式设计的分布式服务管理框架,负责存储和管理大家都关心的数据,然后接收观察者的注册,一旦这些数据发生变化,Zookeeper 负责通知已经注册的观察者。Zookeeper 相当于文件系统 + 通知机制。 1.1 Zookeeper 特点 集群架构 :Zookeeper 通常由

    2024年01月18日
    浏览(37)
  • Java集合基础知识点复习

    主要分为两类: 第一个是Collection 属于单列集合,第二个是Map 属于双列集合在Collection中有两个子接口List和Set。在我们平常开发的过程中用的比较多像list接口中的实现类ArrarList和LinkedList。 在Set接口中有实现类HashSet和TreeSet。 在map接口中有很多的实现类,平时比较常见的是

    2024年04月08日
    浏览(57)
  • 计算机网络期末复习(知识点)

    目录 第一章 概述 1.1计算机网络的概念 1.2计算机网络的组成 1.3计算机网络的功能 1.4计算机网络的性能指标 1.5计算机网络的体系结构 第二章 物理层 1.基本概念 2.常见的数字数据编码 3.传输介质 4.物理层中的设备 第三章 数据链路层 1.数据链路层的功能 2.组帧 3.差错控制 4.流

    2024年02月03日
    浏览(64)
  • Spark相关知识点(期末复习集锦)

    嗨喽,最近小伙伴们快要期末考试了吧,下面是我对《Spark零基础实战》的总结,希望能帮助到你们。 Spark,拥有hadoop MR所具有的优点,但不同于MR的是job中监测结果可以 保存在内存中 ,从而不再需要读写HDFS,因此spark能够更好的适用于数据挖掘与机器学习等需要迭代的m r的

    2024年02月02日
    浏览(52)
  • 图论期末复习知识点 卓新建

    图的定义、关联、相邻、重边、环、孤立点、简单图 同 顶点的度d(v), deg(v)、出度、入度、最大度D、最小度d、奇点、偶点、邻域、悬挂点、 悬挂边 独立集 偶图/二部图/二分图、多部图、完全偶图、完全图、正则图 度序列 、图序列(简单图的度序列) 握手定理 子图、极大子

    2024年02月03日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包