国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用

這篇具有很好參考價(jià)值的文章主要介紹了WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

為何模塊化

模塊化是一種分治思想,不僅可以分離復(fù)雜的業(yè)務(wù)邏輯,還可以進(jìn)行不同任務(wù)的分工。模塊與模塊之間相互獨(dú)立,從而構(gòu)建一種松耦合的應(yīng)用程序,便于開發(fā)和維護(hù)。

開發(fā)技術(shù)

.NET 6 + WPF + Prism (v8.0.0.1909) + HandyControl (v3.4.0)

知識準(zhǔn)備

什么是MVVM

Model-View-ViewModel?是一種軟件架構(gòu)設(shè)計(jì),它是一種簡化用戶界面的事件驅(qū)動(dòng)編程方式。Model:數(shù)據(jù)模型,用來存儲(chǔ)數(shù)據(jù)。 View:視圖界面,用來展示UI界面和響應(yīng)用戶交互。ViewModel:連接View和Model的中間件,起到了橋梁的作用。

什么是Prism

Prism?是一套桌面開發(fā)框架,用于在WPF和Xamarin Forms中構(gòu)建松耦合、可維護(hù)、可以測試的XAML應(yīng)用程序。Prism提供了一組設(shè)計(jì)模式的實(shí)現(xiàn),這些模式有助于編寫結(jié)構(gòu)良好且可維護(hù)的XAML應(yīng)用程序,包括MVVM、依賴注入、命令、事件聚合器等。

什么是HandyControl

HandyControl?是一套WPF控件庫,它幾乎重寫了所有原生樣式,同時(shí)包含80余款自定義控件。

搭建項(xiàng)目

假設(shè)現(xiàn)在有一套叫Lapis的業(yè)務(wù)系統(tǒng),包含A和B兩塊業(yè)務(wù)。業(yè)務(wù)A含有<頁面1>和<頁面2>,業(yè)務(wù)B含有<頁面3>。界面設(shè)計(jì)如下:

WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用

下面我們就按照上述要求,來搭建一套MVVM + 模塊化的桌面應(yīng)用程序。

首先,新建一個(gè)名為Lapis.WpfDemo的解決方案,分別創(chuàng)建以下四個(gè)不同項(xiàng)目:其中Lapis.Shell是WPF應(yīng)用程序,其余是WPF類庫。如圖所示:

WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用

Lapis.Share:?是一個(gè)共享庫,用來定義抽象基類和一些公共方法,供上層調(diào)用。它引用了Prism.Wpf、Prism.Core和HandyControl第三方Nuget包。BaseViewModel?是一個(gè)視圖模型基類,繼承自?BindableBase,分別定義了EventAggregator、RegionManager、LoadCommand?屬性。代碼如下:

WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用
 1     /// <summary>
 2     /// 視圖模型基類
 3     /// </summary>
 4     public abstract class BaseViewModel : BindableBase
 5     {
 6         private DelegateCommand _loadCommand;
 7         protected IEventAggregator EventAggregator { get; } //事件聚合器
 8         protected IRegionManager RegionManager { get; } // 區(qū)域管理器
 9         public DelegateCommand LoadCommand => _loadCommand ??= new(OnLoad); //界面加載命令
10 
11         public BaseViewModel()
12         {
13             RegionManager = ContainerLocator.Current.Resolve<IRegionManager>();
14             EventAggregator = ContainerLocator.Current.Resolve<IEventAggregator>();
15         }
16 
17         /// <summary>
18         /// 界面加載時(shí),由Loaded事件觸發(fā)
19         /// </summary>
20         protected virtual void OnLoad()
21         {
22         }
23 
24         /// <summary>
25         /// 根據(jù)區(qū)域名稱查找視圖
26         /// </summary>
27         /// <param name="regionName">區(qū)域名稱</param>
28         protected TView TryFindView<TView>(string regionName) where TView : class
29         {
30             return RegionManager.Regions[regionName].Views
31                      .Where(v => v.GetType() == typeof(TView))
32                      .FirstOrDefault() as TView;
33         }
34     }
BaseViewModel.cs

Lapis.ModuleA?和?Lapis.ModuleB:?對應(yīng)前端業(yè)務(wù)模塊A和B,? 模塊A包含?PageOne?和?PageTwo?兩個(gè)視圖及視圖模型,模塊B只含?PageThree?一個(gè)視圖及視圖模型。按照Prism框架規(guī)定,視圖模型最好以?視圖名稱 + ViewModel?來命名。如圖所示:

WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用

?其中,ModuleA?和?ModuleB?表示模塊類,用于初始化模塊和注冊類型。ModuleA?代碼如下:

 1  [Module(ModuleName = "ModuleA", OnDemand = true)]
 2     public class ModuleA : IModule
 3     {
 4         public void OnInitialized(IContainerProvider containerProvider)
 5         {
 6             var regionManager = containerProvider.Resolve<IRegionManager>();
 7             regionManager.RegisterViewWithRegion(ModuleARegionNames.RegionOne, typeof(PageOne)); // 將頁面一注冊到區(qū)域一
 8             regionManager.RegisterViewWithRegion(ModuleARegionNames.RegionTwo, typeof(PageTwo)); // 將頁面二注冊到區(qū)域二
 9         }
10 
11         public void RegisterTypes(IContainerRegistry containerRegistry)
12         {
13         }
14     }

第7和第8行代碼:分別將?PageOne?和?PageTwo?注冊到?RegionOne?和?RegionTwo。為了方便,區(qū)域名稱用字符串常量表示。

Lapis.Shell:?是一個(gè)啟動(dòng)模塊,負(fù)責(zé)啟動(dòng)/初始化應(yīng)用程序(加載模塊和資源),它包含App啟動(dòng)類、主窗口、側(cè)邊菜單和Tab頁內(nèi)容視圖及對應(yīng)的視圖模型等。其中?PageSelectedEvent?是一個(gè)頁面選中事件,用于 ViewModel 之間傳遞消息,起到解耦作用。如圖所示:

WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用

MainWindow?此處作為啟動(dòng)窗口/主窗口。為了讓?MainWindow?代碼保持簡潔,我們只把它當(dāng)作布局頁面來使用。代碼片段如下:

 1     <Grid>
 2         <Grid.ColumnDefinitions>
 3             <ColumnDefinition Width="auto" />
 4             <ColumnDefinition />
 5         </Grid.ColumnDefinitions>
 6         <!--  側(cè)邊菜單欄內(nèi)容  -->
 7         <ContentControl Name="sideMenuContentControl" Width="200px" Margin="5" />
 8         <!--  Tab頁主內(nèi)容  -->
 9         <ContentControl Name="tabPagesContentControl" Grid.Column="1" Margin="0,5,5,5" />
10     </Grid>

第7和第9行代碼:sideMenuContentControl?和?tabPagesContentControl?是兩個(gè)內(nèi)容控件,用來呈現(xiàn)左側(cè)菜單和Tab頁面視圖??吹竭@里,大家一定會(huì)問:ContentControl?是通過什么來關(guān)聯(lián)視圖的?沒錯(cuò),就是上面提到的Region,我們可以在MainWindow.cs中進(jìn)行區(qū)域設(shè)置,代碼如下:

1     public partial class MainWindow : Window
2     {
3         public MainWindow()
4         {
5             InitializeComponent();
6             RegionManager.SetRegionName(this.sideMenuContentControl, ShellRegionNames.SideMenuContentRegion);
7             RegionManager.SetRegionName(this.tabPagesContentControl, ShellRegionNames.TabPagesContentRegion);
8         }
9     }

然后,同樣在?ShellModule?類里對?SideMenuContent?和?TabPagesContent?視圖進(jìn)行區(qū)域注冊,這樣主窗口就能顯示左側(cè)菜單和Tab頁面了。代碼如下:

WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用
 1     [Module(ModuleName = "ShellModule", OnDemand = true)]
 2     public class ShellModule : IModule
 3     {
 4         public void OnInitialized(IContainerProvider containerProvider)
 5         {
 6             var regionManager = containerProvider.Resolve<IRegionManager>();
 7             regionManager.RegisterViewWithRegion(ShellRegionNames.SideMenuContentRegion, typeof(SideMenuContent)); // 注冊側(cè)邊菜單內(nèi)容視圖
 8             regionManager.RegisterViewWithRegion(ShellRegionNames.TabPagesContentRegion, typeof(TabPagesContent)); // 注冊Tab頁面內(nèi)容視圖
 9         }
10 
11         public void RegisterTypes(IContainerRegistry containerRegistry)
12         {
13         }
14     }
ShellModule.cs

App?是WPF應(yīng)用啟動(dòng)入口,由于使用了第三方Prism框架和HandyControl控件庫,我們需要對?App.xaml?和?App.xaml.cs?兩個(gè)文件做一些修改。代碼如下:

WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用
 1 <unity:PrismApplication
 2     x:Class="Lapis.Shell.App"
 3     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 4     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 5     xmlns:local="clr-namespace:Lapis.Shell"
 6     xmlns:unity="http://prismlibrary.com/">
 7     <Application.Resources>
 8         <ResourceDictionary>
 9             <ResourceDictionary.MergedDictionaries>
10                 <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml" />
11                 <ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml" />
12             </ResourceDictionary.MergedDictionaries>
13         </ResourceDictionary>
14     </Application.Resources>
15 </unity:PrismApplication>
App.xaml
WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用
 1     public partial class App : PrismApplication
 2     {
 3         protected override void ConfigureModuleCatalog(IModuleCatalog moduleCatalog)
 4         {
 5             base.ConfigureModuleCatalog(moduleCatalog);
 6             //
 7             moduleCatalog.AddModule<ShellModule>();      //添加宿主模塊
 8             moduleCatalog.AddModule<ModuleA.ModuleA>();  //添加業(yè)務(wù)模塊A
 9             moduleCatalog.AddModule<ModuleB.ModuleB>();  //添加業(yè)務(wù)模塊B
10         }
11 
12         protected override Window CreateShell()
13         {
14             return Container.Resolve<MainWindow>(); //返回主窗體
15         }
16 
17         protected override void RegisterTypes(IContainerRegistry containerRegistry)
18         {
19         }
20     }
App.xaml.cs

接下來,要做的就是左側(cè)菜單和Tab頁面之間的交互動(dòng)作。不同于傳統(tǒng)Winform的事件驅(qū)動(dòng)機(jī)制,我們使用MVVM模式將視圖和UI邏輯分離。因此一般情況下,所有的界面邏輯都應(yīng)該在?ViewModel?里完成。SideMenuContentViewModel?通過事件聚合器發(fā)布頁面選中事件,TabPagesContentViewModel?則通過訂閱該事件來進(jìn)行頁面切換,代碼如下:

WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用
 1     /// <summary>
 2     /// 側(cè)邊菜單內(nèi)容視圖模型
 3     /// </summary>
 4     public class SideMenuContentViewModel : BaseViewModel
 5     {
 6         private DelegateCommand<string> _menuSelectedCommand;
 7 
 8         private List<PageInfo> _pages = new()
 9         {
10             new PageInfo { Id = "1" ,RegionName = "RegionOne", DisplayName = "子菜單1" },
11             new PageInfo { Id = "2", RegionName = "RegionTwo", DisplayName = "子菜單2" },
12             new PageInfo { Id = "3", RegionName = "RegionThree", DisplayName = "子菜單3" },
13         };
14 
15         public DelegateCommand<string> MenuSelectedCommand => _menuSelectedCommand ??= new DelegateCommand<string>(ExecuteMenuSelectedCommand);
16 
17         private void ExecuteMenuSelectedCommand(string id)
18         {
19             var info = _pages.Find(x => x.Id == id);
20             if (info != null)
21             {
22                 EventAggregator.GetEvent<PageSelectedEvent>().Publish(info);
23             }
24         }
25     }
SideMenuContentViewModel.cs
WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用
 1     /// <summary>
 2     /// Tab頁面內(nèi)容視圖模型
 3     /// </summary>
 4     public class TabPagesContentViewModel : BaseViewModel
 5     {
 6         private TabControl _tabControl;
 7 
 8         protected override void OnLoad()
 9         {
10             _tabControl = TryFindView<TabPagesContent>(ShellRegionNames.TabPagesContentRegion)?.FindName("tabControl") as TabControl;
11 
12             EventAggregator.GetEvent<PageSelectedEvent>().Subscribe(OnPageSelected);
13         }
14 
15         /// <summary>
16         /// 頁面選中事件處理
17         /// </summary>
18         /// <param name="page"></param>
19         private void OnPageSelected(PageInfo page)
20         {
21             try
22             {
23                 var existItem = FindItem(_tabControl, page.RegionName);
24                 if (existItem != null)
25                 {
26                     existItem.IsSelected = true;
27                 }
28                 else
29                 {
30                     // 創(chuàng)建頁面區(qū)域控件
31                     var pageContentControl = new ContentControl();
32                     pageContentControl.SetRegionName(page.RegionName);
33 
34                     var item = new TabItem
35                     {
36                         Name = page.RegionName,     // 區(qū)域名稱,如:RegionOne、RegionTwo
37                         Header = page.DisplayName,  // 頁面名稱
38                         IsSelected = true,
39                         Content = pageContentControl
40                     };
41 
42                     _tabControl.Items.Add(item);
43                 }
44             }
45             catch { }
46         }
47 
48         private TabItem FindItem(TabControl tc, string name)
49         {
50             foreach (TabItem item in tc.Items)
51             {
52                 if (item.Name == name)
53                 {
54                     return item;
55                 }
56             }
57             return null;
58         }
59     }
TabPagesContentViewModel.cs

整個(gè)UI交互過程,如圖所示:

?

WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用

?

至此,整個(gè)桌面前端應(yīng)用就基本完成了。界面如圖所示:

WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用

參考資料

歡迎使用HandyControl | HandyOrg

Introduction to Prism | Prism (prismlibrary.com)

.NET Core 3 WPF MVVM框架 Prism系列文章索引 - RyzenAdorer - 博客園 (cnblogs.com)文章來源地址http://www.zghlxwxcb.cn/news/detail-648471.html

到了這里,關(guān)于WPF如何構(gòu)建MVVM+模塊化的桌面應(yīng)用的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 大型Android項(xiàng)目架構(gòu):基于組件化+模塊化+Kotlin+協(xié)程+Flow+Retrofit+Jetpack+MVVM架構(gòu)實(shí)現(xiàn)WanAndroid客戶端

    大型Android項(xiàng)目架構(gòu):基于組件化+模塊化+Kotlin+協(xié)程+Flow+Retrofit+Jetpack+MVVM架構(gòu)實(shí)現(xiàn)WanAndroid客戶端

    前言:茍有恒,何必三更眠五更起;最無益,莫過一日曝十日寒。 之前一直想寫個(gè) WanAndroid 項(xiàng)目來鞏固自己對 Kotlin+Jetpack+協(xié)程 等知識的學(xué)習(xí),但是一直沒有時(shí)間。這里重新行動(dòng)起來,從項(xiàng)目搭建到完成前前后后用了兩個(gè)月時(shí)間,平常時(shí)間比較少,基本上都是只能利用零碎的

    2024年02月09日
    瀏覽(27)
  • Rust之構(gòu)建命令行程序(三):重構(gòu)改進(jìn)模塊化和錯(cuò)誤處理

    Rust之構(gòu)建命令行程序(三):重構(gòu)改進(jìn)模塊化和錯(cuò)誤處理

    Windows 10 Rust 1.74.1 ? VS Code 1.85.1 這次創(chuàng)建了新的工程minigrep. 為了改進(jìn)我們的程序,我們將修復(fù)與程序結(jié)構(gòu)及其處理潛在錯(cuò)誤的方式有關(guān)的四個(gè)問題。首先,我們的 main 函數(shù)現(xiàn)在執(zhí)行兩項(xiàng)任務(wù):解析參數(shù)和讀取文件。隨著我們程序的增長, main 處理的獨(dú)立任務(wù)的數(shù)量也會(huì)增加。隨

    2024年01月18日
    瀏覽(106)
  • 一個(gè)基于.NET Core構(gòu)建的簡單、跨平臺(tái)、模塊化的商城系統(tǒng)

    一個(gè)基于.NET Core構(gòu)建的簡單、跨平臺(tái)、模塊化的商城系統(tǒng)

    今天大姚給大家分享一個(gè)基于.NET Core構(gòu)建的簡單、跨平臺(tái)、模塊化、完全開源免費(fèi)(MIT License)的商城系統(tǒng):Module Shop。 商品:分類、品牌、單位、選項(xiàng)(銷售屬性)、屬性、屬性模板、屬性組。 銷售:訂單、物流。 內(nèi)容:首頁配置、評論、回復(fù)。 配置:國家、用戶、倉庫

    2024年03月27日
    瀏覽(1131)
  • LabVIEW應(yīng)用開發(fā)——VI模塊化

    LabVIEW應(yīng)用開發(fā)——VI模塊化

    ? ? ? ? 我們在寫C語言的時(shí)候,一些模塊化的功能或者多次調(diào)用的功能,我們一般會(huì)用一個(gè)函數(shù)封裝起來,方便使用并且讓代碼看起來更加的簡潔。這種函數(shù)一般都會(huì)包含這幾個(gè)概念, 輸入?yún)?shù) 、 輸出參數(shù) 和 返回值 。而LabVIEW的VI就可以當(dāng)作是一個(gè)函數(shù), 輸入?yún)?shù) 就是

    2024年02月07日
    瀏覽(28)
  • TIMC 驅(qū)動(dòng)的模塊化區(qū)塊鏈 Axiomesh:致力于構(gòu)建「Mass Commercial Adoption」新范式

    TIMC 驅(qū)動(dòng)的模塊化區(qū)塊鏈 Axiomesh:致力于構(gòu)建「Mass Commercial Adoption」新范式

    撰文:JIN,Techub News 在區(qū)塊鏈技術(shù)的演進(jìn)歷程中,我們正見證歷史性的轉(zhuǎn)折點(diǎn):「Mass?Adoption」即區(qū)塊鏈的大規(guī)模普及,指的是區(qū)塊鏈技術(shù)從封閉的小范圍應(yīng)用擴(kuò)展到廣泛的行業(yè)和市場的過程。它是區(qū)塊鏈技術(shù)跨越早期采用者的界限,滲透到普通消費(fèi)者生活的每個(gè)角落,成為

    2024年03月24日
    瀏覽(27)
  • Java模塊化應(yīng)用實(shí)踐之精簡JRE(內(nèi)含開源)

    Java9及以后的版本引入了模塊化特性,但是直到今天JDK21都發(fā)布了,依然沒有被大量使用起來,那么這個(gè)特性就真的沒啥意義了嗎? 別忘了,Java本身可是把模塊化做到了極致的,所以可以利用這個(gè)特性對JRE本身進(jìn)行定制化或者精簡化。 由于平時(shí)偶爾會(huì)開發(fā)一些Java的客戶端應(yīng)

    2024年02月07日
    瀏覽(22)
  • Flask 高級應(yīng)用:使用藍(lán)圖模塊化應(yīng)用和 JWT 實(shí)現(xiàn)安全認(rèn)證

    本文將探討 Flask 的兩個(gè)高級特性:藍(lán)圖(Blueprints)和 JSON Web Token(JWT)認(rèn)證。藍(lán)圖讓我們可以將應(yīng)用模塊化,以便更好地組織代碼;而 JWT 認(rèn)證是現(xiàn)代 Web 應(yīng)用中常見的一種安全機(jī)制。 在大型應(yīng)用中,一個(gè)單獨(dú)的 Python 文件可能無法容納所有的路由和視圖函數(shù)。這時(shí),F(xiàn)lask 的

    2024年02月13日
    瀏覽(31)
  • Flask中的Blueprints:模塊化和組織大型Web應(yīng)用【第142篇—Web應(yīng)用】

    Flask中的Blueprints:模塊化和組織大型Web應(yīng)用【第142篇—Web應(yīng)用】

    前些天發(fā)現(xiàn)了一個(gè)巨牛的人工智能學(xué)習(xí)網(wǎng)站,通俗易懂,風(fēng)趣幽默,忍不住分享一下給大家?!军c(diǎn)擊進(jìn)入巨牛的人工智能學(xué)習(xí)網(wǎng)站】。 在構(gòu)建大型Web應(yīng)用時(shí),良好的組織結(jié)構(gòu)和模塊化是至關(guān)重要的。Flask提供了Blueprints(藍(lán)圖)這一功能,可以幫助我們更有效地組織應(yīng)用程序的

    2024年04月15日
    瀏覽(28)
  • 從單體架構(gòu)向微服務(wù)遷移:模塊化單體是如何幫助的

    從單體架構(gòu)向微服務(wù)遷移:模塊化單體是如何幫助的

    你開始構(gòu)建一個(gè)漂亮的單體系統(tǒng)。也許是一個(gè)模塊化的單體系統(tǒng)。 隨著時(shí)間的推移,系統(tǒng)不斷增長,需求也在不斷變化。漸漸地,系統(tǒng)開始出現(xiàn)裂痕。 這可能是出于組織原因,需要在團(tuán)隊(duì)之間分配工作。也可能是由于擴(kuò)展性問題和性能瓶頸。 你開始評估可能的解決方案,以

    2024年01月16日
    瀏覽(20)
  • 如何在Vue中進(jìn)行單元測試?什么是Vue的模塊化開發(fā)?

    在Vue中進(jìn)行單元測試可以提高代碼的可維護(hù)性和可讀性,同時(shí)也能夠幫助開發(fā)者更快地找到代碼中的問題和潛在的錯(cuò)誤。下面是一些在Vue中進(jìn)行單元測試的步驟: 安裝單元測試工具 首先需要安裝一個(gè)單元測試工具,例如Jest或Mocha。可以使用npm或yarn進(jìn)行安裝。 創(chuàng)建測試文件

    2024年02月12日
    瀏覽(25)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包