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

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19

這篇具有很好參考價(jià)值的文章主要介紹了Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

待辦事項(xiàng)功能頁面完善以及優(yōu)化

概要:

由于待辦事項(xiàng)功能頁,數(shù)據(jù)已正常渲染出來了。但頁面新增,查詢,修改,刪除等功能還未實(shí)現(xiàn)。本章節(jié)來實(shí)現(xiàn)頁面的請(qǐng)求后臺(tái)實(shí)現(xiàn)CURD(增刪改查)

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#


一.待辦事項(xiàng)查詢搜索刪除增加等功能

根據(jù)渲染出來的待辦事項(xiàng),點(diǎn)擊對(duì)應(yīng)的待辦事項(xiàng)時(shí),查找出該條數(shù)據(jù),顯展示在編輯窗口中。

同時(shí)在搜索框中輸入的參數(shù)或選擇的待辦事項(xiàng)狀態(tài),按下Enter按鍵時(shí),觸發(fā)查詢。

1.首先把待辦事項(xiàng)頁修改成支持編輯的功能,也就是增加觸發(fā)器。需要引入微軟行為類?behaviors

ToDoView.xaml 前端頁引入命名空間

xmlns:i="http://schemas.microsoft.com/xaml/behaviors"

?修改 Grid,支持編輯功能

<!--自定義內(nèi)容區(qū)域-->
<Grid Width="220" MinHeight="180" MaxHeight="250" Margin="8" >
    <!--行為觸發(fā)器-->
    <i:Interaction.Triggers>
             <!--鼠標(biāo)左擊事件-->
            <i:EventTrigger EventName="MouseLeftButtonUp">
                <!--設(shè)置命令-->
                <i:InvokeCommandAction 
                    CommandParameter="{Binding}"
                    Command="{Binding DataContext.SelectedCommand ,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ItemsControl}}"/>
            </i:EventTrigger>
    </i:Interaction.Triggers>
</Grid>
  1. EventTrigger 通過EventName 鎖定當(dāng)前事件名稱
  2. RelativeSource 指定綁定的屬性
  3. Mode 設(shè)置查找模式
  4. AncestorType 設(shè)置綁定的類型
  5. DataContext 設(shè)置綁定命令
  6. CommandParameter 設(shè)置當(dāng)前綁定命令傳遞到后臺(tái)的參數(shù)

2.待辦事項(xiàng)對(duì)應(yīng)的后臺(tái)處理邏輯類 (ToDoViewModel)

namespace MyToDo.ViewModels
{
   public class ToDoViewModel: NavigationViewModel
    {
        public ToDoViewModel(IToDoService toDoService, IContainerProvider provider):base(provider)
        {
            ToDoDtos = new ObservableCollection<ToDoDto>();
            SelectedCommand = new DelegateCommand<ToDoDto>(Selected);
            this.toDoService = toDoService;
        }

        private bool isRightDrawerOpen;
        /// <summary>
        /// 右側(cè)編輯窗口是否展開
        /// </summary>
        public bool IsRightDrawerOpen
        {
            get { return isRightDrawerOpen; }
            set { isRightDrawerOpen = value; RaisePropertyChanged(); }
        }


        public DelegateCommand<ToDoDto> SelectedCommand { get; private set; }
        private readonly IToDoService toDoService;


        private ToDoDto currentDto;
        /// <summary>
        /// 編輯選中/新增對(duì)象
        /// </summary>
        public ToDoDto CurrentDto
        {
            get { return currentDto; }
            set { currentDto = value; RaisePropertyChanged(); }
        }
        private async void Selected(ToDoDto obj)
        {
            try
            {
                UpdateLoading(true);
                //進(jìn)行數(shù)據(jù)查詢
                var todoResult = await toDoService.GetFirstOfDefaultAsync(obj.Id);
                if (todoResult.Status)
                {
                    //把拿到的結(jié)果,賦給一個(gè)當(dāng)前選中的ToDoDto
                    CurrentDto = todoResult.Result;
                    IsRightDrawerOpen = true;//打開窗口
                }
            }
            catch (Exception ex)
            {
                await Console.Out.WriteLineAsync(ex.Message);
            }
            finally
            {
                UpdateLoading(false);
            }
          
        }
    }
}

數(shù)據(jù)查出來后,前端也需要綁定對(duì)應(yīng)的數(shù)據(jù)模型,才能顯示

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#


3.搜索框輸入文本,按下Enter 按鍵時(shí)觸發(fā)查詢

首先,需要在搜索框綁定一個(gè)屬性,用來接收用戶輸入的參數(shù)。那么對(duì)應(yīng)后臺(tái)邏輯處理類??ToDoViewModel 需定義這么一個(gè)屬性。然后前臺(tái)需要綁定該屬性。并且設(shè)置綁定的模式Mode為(雙向綁定)TwoWay,并且設(shè)置(更新的數(shù)據(jù)源)UpdateSourceTrigger為PropertyChanged(一旦發(fā)生變化,馬上通知更新),

<TextBox Text="{Binding Search,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />

接著,給輸入框綁定一個(gè)回車(Enter)事件。同時(shí)綁定一個(gè)(ExecuteCommand)指令,以及(CommandParameter)傳遞給后臺(tái)的處理的參數(shù)。

<!--設(shè)置綁定模式和更新數(shù)據(jù)源類型-->
<TextBox Text="{Binding Search,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}">
    <!--搜索框綁定回車事件-->
    <TextBox.InputBindings>
        <!--通過Key 綁定-->
        <KeyBinding Key="Enter"  Command="{Binding ExecuteCommand}" CommandParameter="查詢"/>
    </TextBox.InputBindings>
</TextBox>

4.處理邏輯類 (ToDoViewModel)添加一個(gè)通用(ExecuteCommand)綁定指令,根據(jù)(CommandParameter)傳遞不同的參數(shù)處理不同的邏輯。例如:

namespace MyToDo.ViewModels
{
   public class ToDoViewModel: NavigationViewModel
    {
        public ToDoViewModel(IContainerProvider provider):base(provider)
        {
            ExecuteCommand = new DelegateCommand<string>(Execute);
        }
        public DelegateCommand<string> ExecuteCommand{ get; private set; }
        private string search;
        /// <summary>
        /// 用戶輸入的搜索條件
        /// </summary>
        public string Search
        {
            get { return search; }
            set { search = value; }
        }
        /// <summary>
        /// 根據(jù)不同的參數(shù),處理不同的邏輯
        /// </summary>
        /// <param name="obj"></param>
        private void Execute(string obj)
        {
            switch (obj)
            {
                case "新增":
                    Add();
                    break;
                case "查詢":
                    GetDataAsync();
                    break;
                case "保存":
                    Save();
                    break;
            }
        }
    }
}

5.待辦事項(xiàng)功能頁,根據(jù)待辦不同的狀態(tài),顯示不同的顏色

在ToDoView.xaml 渲染背景顏色Border 中,增加一個(gè)觸發(fā)器來處理,例如:

 <!--整個(gè)框圓角-->
     <Border CornerRadius="3" Grid.RowSpan="2" >
         <!--增加觸發(fā)器,根據(jù)綁定的狀態(tài)不同,顯示不同的顏色-->
         <Border.Style>
             <Style TargetType="Border">
                 <Style.Triggers>
                     <DataTrigger Binding="{Binding Status}" Value="0">
                         <Setter Property="Background" Value="#3CB371"/>
                     </DataTrigger>
                     <DataTrigger Binding="{Binding Status}" Value="1">
                         <Setter Property="Background" Value="#1E90EF"/>
                     </DataTrigger>
                 </Style.Triggers>
             </Style>
         </Border.Style>
     </Border>

?6.右鍵刪除功能

ToDoView.xaml 前端頁面修改,增加綁定指定

 <!--右上角按鈕-->
 <md:PopupBox HorizontalAlignment="Right" Panel.ZIndex="1">
         <Button Content="刪除"  CommandParameter="{Binding}"
          Command="{Binding DataContext.DeleteCommand ,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ItemsControl}}"/>
 </md:PopupBox>

后臺(tái)ToDoViewModel 邏輯實(shí)現(xiàn)

namespace MyToDo.ViewModels
{
   public class ToDoViewModel: NavigationViewModel
    {
        public ToDoViewModel(IToDoService toDoService, IContainerProvider provider):base(provider)
        {
            ToDoDtos = new ObservableCollection<ToDoDto>();
            DeleteCommand = new DelegateCommand<ToDoDto>(Delete);
            this.toDoService = toDoService;
        }
        public DelegateCommand<ToDoDto> DeleteCommand { get; private set; }
        private ObservableCollection<ToDoDto> toDoDtos;
        private readonly IToDoService toDoService;

        /// <summary>
        /// 創(chuàng)建數(shù)據(jù)的動(dòng)態(tài)集合
        /// </summary>
        public ObservableCollection<ToDoDto> ToDoDtos
        {
            get { return toDoDtos; }
            set { toDoDtos = value;RaisePropertyChanged(); }
        }

        private async void Delete(ToDoDto dto)
        {
           var deleteResult=await toDoService.DeleteAsync(dto.Id);
            if (deleteResult.Status)
            {
                //在當(dāng)前數(shù)據(jù)集合中,找到當(dāng)前已經(jīng)刪除掉的數(shù)據(jù),并移除掉
               var model= ToDoDtos.FirstOrDefault(t => t.Id.Equals(dto.Id));
                if(model != null) ToDoDtos.Remove(model);
            }
        }
    }
}

7.當(dāng)查找不到數(shù)據(jù)時(shí),希望顯示一個(gè)默認(rèn)的圖片。例如暫無數(shù)據(jù)。。

ToDoView.xaml 前端頁面修改,先添加一張圖片。然后,如何判斷是否有無數(shù)據(jù)。是通過添加轉(zhuǎn)換器,拿到ToDoDtos 數(shù)據(jù)集合統(tǒng)計(jì)總數(shù)是否為0來顯示或隱藏當(dāng)前圖片。隨便找一張圖片放在Image文件夾中

 <!--當(dāng)查不到數(shù)據(jù)時(shí),要顯示的圖片。添加轉(zhuǎn)換器來控制,要不要顯示這個(gè)圖片-->
<StackPanel Grid.Row="1" VerticalAlignment="Center" Visibility="{Binding ToDoDtos.Count,Converter={StaticResource IntToVisibility}}">
    <Image Source="/Images/NoData.png" Width="620" Height="220"/>
    <TextBlock Margin="0,10" FontSize="18" HorizontalAlignment="Center" Text="哇哦,暫無數(shù)據(jù)"/>
</StackPanel>

添加轉(zhuǎn)換器?IntToVisibilityConveter,需繼承自?IValueConverter。

namespace MyToDo.Common.Converters
{
    /// <summary>
    /// 轉(zhuǎn)換器
    /// </summary>
    public class IntToVisibilityConveter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if(value!=null && int.TryParse(value.ToString(), out int result))
            {
                if(result ==0) return Visibility.Visible; //如果等于0,則讓圖片顯示
            }
            //否則,隱藏圖片
            return Visibility.Hidden;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

轉(zhuǎn)換器編寫完成后,然后添加到?ToDoView.xaml 前端當(dāng)中進(jìn)行使用。

首先引入轉(zhuǎn)換器命名空間

 xmlns:cv="clr-namespace:MyToDo.Common.Converters"

然后,還需要在當(dāng)前ToDoView.xaml 用戶控件的資源文件中,進(jìn)行聲明。

   <UserControl.Resources>
       <cv:IntToVisibilityConveter x:Key="IntToVisibility"/>
   </UserControl.Resources>

8.根據(jù)下拉列表選擇的狀態(tài)值查詢?

同搜索框查詢處理方式一樣,然后下拉列表 ComboBox 也需要綁定一個(gè)屬性。那么首先要定義這個(gè)屬性,然后在ToDoView.xaml 中的選擇框中,綁定這個(gè)?SelectIndex 屬性

<ComboBox SelectedIndex="{Binding SelectIndex}">
    <ComboBoxItem>全部</ComboBoxItem>
    <ComboBoxItem>待辦</ComboBoxItem>
    <ComboBoxItem>已完成</ComboBoxItem>
</ComboBox>

后臺(tái)?ToDoViewModel 邏輯中,需要去定義這個(gè) SelectIndex 屬性。由于基類沒有根據(jù)該條件的查詢,所以我們可以自定義自己的查詢接口和參數(shù),從而避免修改到基類共用類的方法函數(shù)。

namespace MyToDo.ViewModels
{
   public class ToDoViewModel: NavigationViewModel
    {
        public ToDoViewModel(IToDoService toDoService, IContainerProvider provider):base(provider)
        {
            ToDoDtos = new ObservableCollection<ToDoDto>();
            this.toDoService = toDoService;
        }

        private ObservableCollection<ToDoDto> toDoDtos;
        private readonly IToDoService toDoService;

        /// <summary>
        /// 創(chuàng)建數(shù)據(jù)的動(dòng)態(tài)集合
        /// </summary>
        public ObservableCollection<ToDoDto> ToDoDtos
        {
            get { return toDoDtos; }
            set { toDoDtos = value;RaisePropertyChanged(); }
        }
      
        private string search;
        /// <summary>
        /// 用戶輸入的搜索條件
        /// </summary>
        public string Search
        {
            get { return search; }
            set { search = value; RaisePropertyChanged(); }
        }
        private int selectIndex=0;
        /// <summary>
        /// 下拉列表狀態(tài)值
        /// </summary>
        public int SelectIndex
        {
            get { return selectIndex; }
            set { selectIndex = value; RaisePropertyChanged(); }
        }



        /// <summary>
        /// 獲取數(shù)據(jù)
        /// </summary>
        async void GetDataAsync()
        {
            UpdateLoading(true); //發(fā)布消息,設(shè)置加載中的窗口
            //前端界面 0全部,1 待辦,2 已完成;數(shù)據(jù)庫實(shí)際值,0待辦,1已完成
            int? stastus=  SelectIndex == 0 ? null : SelectIndex == 2 ? 1 : 0;
            //添加查詢條件
            var todoResult=await toDoService.GetAllFilterAsync(new Shared.Parameters.ToDoParameter()
            {
                PageIndex = 0,
                PageSize = 100,
                Search = Search, //傳入搜索框查詢條件
                Status=selectIndex //下拉框值
            });
            if (todoResult.Status)
            {
                toDoDtos.Clear();
                foreach (var item in todoResult.Result.Items)
                {
                    toDoDtos.Add(item);
                }
            }
            UpdateLoading(false); //發(fā)布消息,關(guān)閉加載中的窗口
        }

        //重寫導(dǎo)航加載數(shù)據(jù)的方法
        public override void OnNavigatedTo(NavigationContext navigationContext)
        {
            base.OnNavigatedTo(navigationContext);
            GetDataAsync();
        }
    }
}

自定義查詢接口和參數(shù)實(shí)現(xiàn),例如:當(dāng)前根據(jù)下拉列表狀態(tài)查詢,由于基類方法不適用。需要新增一個(gè)自定義的查詢接口和參數(shù)

?步驟1.MyToDo.Shared 項(xiàng)目中,定義一個(gè)?ToDoParameter 類,繼承自QueryParameter 類
  public class ToDoParameter: QueryParameter
  {
      public int? Status { get; set; }
  }

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#

步驟2.在MyToDo 項(xiàng)目Service 文件中,增加自定義的查詢接口,并傳入定義的參數(shù)類
namespace MyToDo.Service
{
    public interface IToDoService:IBaseService<ToDoDto>
    {
        Task<ApiResponse<PagedList<ToDoDto>>> GetAllFilterAsync(ToDoParameter parameter);
    }
}

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#

步驟3.ToDoService 中去實(shí)現(xiàn)自定義的接口,查詢條件就加上自定義根據(jù)狀態(tài)來查
namespace MyToDo.Service
{
    public class ToDoService : BaseService<ToDoDto>, IToDoService
    {
        private readonly HttpRestClient client;

        /// <summary>
        /// 構(gòu)造中,直接傳控制器名稱進(jìn)去。因?yàn)樵赪eb Api項(xiàng)目中,待辦事項(xiàng)控制器的名稱,就是叫ToDo
        /// </summary>
        /// <param name="client"></param>
        /// <param name="serverName"></param>
        public ToDoService(HttpRestClient client, string serverName= "ToDo") : base(client, serverName)
        {
            this.client = client;
        }

        public async Task<ApiResponse<PagedList<ToDoDto>>> GetAllFilterAsync(ToDoParameter parameter)
        {
            var request = new BaseRequest()
            {
                Method = Method.Get,
                Route = $"api/ToDo/GetAllFilter?pageIndex={parameter.PageIndex}" +
                $"&pageSize={parameter.PageSize}&Search={parameter.Search}&Status={parameter.Status}"
            };
            return await client.ExecuteAsync<PagedList<ToDoDto>>(request);
        }
    }
}

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#

步驟4.接著,修改MyToDo.Api 項(xiàng)目,首先IToDoService 新增一個(gè) GetAllFilter 接口
namespace MyToDo.Api.Service
{
    public interface IToDoService: IBaseService<ToDoDto>
    {
        Task<ApiResponse> GetAllFilterAsync(ToDoParameter query);
    }
}

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#

步驟5.接著,在MyToDo.Api 項(xiàng)目 去ToDoService層實(shí)現(xiàn)?GetAllFilterAsync 接口
 public async Task<ApiResponse> GetAllFilterAsync(ToDoParameter query)
 {
     try
     {
         var todos = await work.GetRepository<ToDo>()
              //根據(jù)標(biāo)題查,如果傳過來的Search 為空,直接過。否則就匹配標(biāo)題。
              .GetPagedListAsync(predicate: x => (string.IsNullOrWhiteSpace(query.Search) ? true : x.Title.Contains(query.Search))
                && (query.Status==null ? true : x.Status.Equals(query.Status)),
               pageIndex: query.PageIndex,
               pageSize: query.PageSize,
               orderBy: source => source.OrderByDescending(t => t.CreateDate) //根據(jù)創(chuàng)建時(shí)間進(jìn)行排序
               );
         return new ApiResponse(true, todos); //返回true,并返回所有數(shù)據(jù)
     }
     catch (Exception ex)
     {
         return new ApiResponse(ex.Message);
     }
 }

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#

步驟6.然后還要在MyToDo.Api 項(xiàng)目中,修改ToDoController 控制器,添加GetAllFilter 接口方法,并傳入自定義的參數(shù)。
[HttpGet]
public async Task<ApiResponse> GetAllFilter([FromQuery] ToDoParameter query) => await service.GetAllFilterAsync(query);

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#

步驟7.最后,在 MyToDo 項(xiàng)目中的?ToDoViewModel 邏輯處理層去使用它
  /// <summary>
  /// 獲取數(shù)據(jù)
  /// </summary>
  async void GetDataAsync()
  {
      UpdateLoading(true); //發(fā)布消息,設(shè)置加載中的窗口
  //前端界面 0全部,1 待辦,2 已完成;數(shù)據(jù)庫實(shí)際值,0待辦,1已完成
   int? stastus=  SelectIndex == 0 ? null : SelectIndex == 2 ? 1 : 0;
      //添加查詢條件
      var todoResult=await toDoService.GetAllFilterAsync(new Shared.Parameters.ToDoParameter()
      {
          PageIndex = 0,
          PageSize = 100,
          Search = Search, //傳入搜索框查詢條件
          Status=selectIndex //下拉框值
      });
      if (todoResult.Status)
      {
          toDoDtos.Clear();
          foreach (var item in todoResult.Result.Items)
          {
              toDoDtos.Add(item);
          }
      }
      UpdateLoading(false); //發(fā)布消息,關(guān)閉加載中的窗口
  }

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#


二.完整源碼

ToDoView.xaml?

<UserControl x:Class="MyToDo.Views.ToDoView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
             xmlns:local="clr-namespace:MyToDo.Views"
             xmlns:cv="clr-namespace:MyToDo.Common.Converters"
             mc:Ignorable="d" 
             xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Resources>
        <cv:IntToVisibilityConveter x:Key="IntToVisibility"/>
    </UserControl.Resources>
    <md:DialogHost>
        <md:DrawerHost IsRightDrawerOpen="{Binding IsRightDrawerOpen}">
            <!--設(shè)計(jì)右邊彈出層-->
            <md:DrawerHost.RightDrawerContent>
                <!--定義彈出層的內(nèi)容區(qū)域-->
                <DockPanel Width="300" LastChildFill="False">
                    <TextBlock Text="添加待辦" Padding="20,10" FontSize="20" FontWeight="Bold"  DockPanel.Dock="Top"/>
                    <StackPanel Orientation="Horizontal" Margin="20" DockPanel.Dock="Top">
                        <TextBlock Text="狀態(tài):"  Padding="0,0,10,0" VerticalAlignment="Center"/>
                        <ComboBox SelectedIndex="{Binding CurrentDto.Status}"> <!--通過綁定索引來找到對(duì)應(yīng)的狀態(tài)-->
                            <ComboBoxItem>待辦</ComboBoxItem>
                            <ComboBoxItem>已完成</ComboBoxItem>
                        </ComboBox>
                    </StackPanel>
                    <TextBox Text="{Binding CurrentDto.Title}" md:HintAssist.Hint="請(qǐng)輸入待辦概要" Margin="20,0" DockPanel.Dock="Top"/>
                    <TextBox Text="{Binding CurrentDto.Content}" md:HintAssist.Hint="請(qǐng)輸入待辦內(nèi)容" Margin="20" MinHeight="100" DockPanel.Dock="Top"/>
                    <Button Command="{Binding ExecuteCommand}" CommandParameter="保存" Content="添加到待辦"  DockPanel.Dock="Top" Margin="20,0" />
                </DockPanel>
            </md:DrawerHost.RightDrawerContent>

            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="auto"/>
                    <RowDefinition/>
                </Grid.RowDefinitions>

                <StackPanel Margin="15,0,0,0" Orientation="Horizontal">
                    <!--設(shè)置綁定模式和更新數(shù)據(jù)源類型-->
                    <TextBox Text="{Binding Search,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Width="250" VerticalAlignment="Center" md:HintAssist.Hint="查找待辦事項(xiàng)..." md:TextFieldAssist.HasClearButton="True">
                        <!--搜索框綁定回車事件-->
                        <TextBox.InputBindings>
                            <!--通過Key 綁定-->
                            <KeyBinding Key="Enter"  Command="{Binding ExecuteCommand}" CommandParameter="查詢"/>
                        </TextBox.InputBindings>
                    </TextBox>
                    <TextBlock Text="篩選:" Margin="10.0" VerticalAlignment="Center"/>
                    <ComboBox SelectedIndex="{Binding SelectIndex}">
                        <ComboBoxItem>全部</ComboBoxItem>
                        <ComboBoxItem>待辦</ComboBoxItem>
                        <ComboBoxItem>已完成</ComboBoxItem>
                    </ComboBox>
                </StackPanel>
                <Button HorizontalAlignment="Right" Content="+ 添加待辦" Margin="10,5" Command="{Binding ExecuteCommand}" CommandParameter="新增" />
                 <!--當(dāng)查不到數(shù)據(jù)時(shí),要顯示的圖片。添加轉(zhuǎn)換器來控制,要不要顯示這個(gè)圖片-->
                <StackPanel Grid.Row="1" VerticalAlignment="Center" Visibility="{Binding ToDoDtos.Count,Converter={StaticResource IntToVisibility}}">
                    <Image Source="/Images/NoData.png" Width="620" Height="220"/>
                    <TextBlock Margin="0,10" FontSize="18" HorizontalAlignment="Center" Text="哇哦,暫無數(shù)據(jù)"/>
                </StackPanel>
                <ScrollViewer Grid.Row="1">
                    <ItemsControl  HorizontalAlignment="Center" ItemsSource="{Binding ToDoDtos}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <WrapPanel />
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        <!--自定義內(nèi)容模板-->
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <md:TransitioningContent OpeningEffect="{md:TransitionEffect Kind=ExpandIn}">
                                <!--自定義內(nèi)容區(qū)域-->
                                <Grid Width="220" MinHeight="180" MaxHeight="250" Margin="8" >
                                    <!--行為觸發(fā)器-->
                                    <i:Interaction.Triggers>
                                             <!--鼠標(biāo)左擊事件-->
                                            <i:EventTrigger EventName="MouseLeftButtonUp">
                                                <!--設(shè)置命令-->
                                                <i:InvokeCommandAction 
                                                    CommandParameter="{Binding}"
                                                    Command="{Binding DataContext.SelectedCommand ,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ItemsControl}}"/>
                                            </i:EventTrigger>
                                    </i:Interaction.Triggers>
                                    <!--定義2行-->
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="auto"/>
                                        <RowDefinition />
                                    </Grid.RowDefinitions>
                                    <!--右上角按鈕-->
                                    <md:PopupBox HorizontalAlignment="Right" Panel.ZIndex="1">
                                            <Button Content="刪除"  CommandParameter="{Binding}"
                                             Command="{Binding DataContext.DeleteCommand ,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ItemsControl}}"/>
                                    </md:PopupBox>

                                    <!--整個(gè)框圓角-->
                                        <Border CornerRadius="3" Grid.RowSpan="2" >
                                            <!--增加觸發(fā)器,根據(jù)綁定的狀態(tài)不同,顯示不同的顏色-->
                                            <Border.Style>
                                                <Style TargetType="Border">
                                                    <Style.Triggers>
                                                        <DataTrigger Binding="{Binding Status}" Value="0">
                                                            <Setter Property="Background" Value="#3CB371"/>
                                                        </DataTrigger>
                                                        <DataTrigger Binding="{Binding Status}" Value="1">
                                                            <Setter Property="Background" Value="#1E90EF"/>
                                                        </DataTrigger>
                                                    </Style.Triggers>
                                                </Style>
                                            </Border.Style>
                                        </Border>

                                        <TextBlock  Text="{Binding Title}" Padding="10,5" FontWeight="Bold"/>
                                    <TextBlock Text="{Binding Content}" Padding="10,5" Grid.Row="1"/>
                                    <!--白色背景底色控件-->
                                    <Canvas Grid.RowSpan="2" ClipToBounds="True">
                                        <Border Canvas.Top="10" CornerRadius="100" Canvas.Right="-50" Width="120" Height="120" Background="#ffffff" Opacity="0.1"/>
                                        <Border Canvas.Top="80" CornerRadius="100" Canvas.Right="-30" Width="120" Height="120" Background="#ffffff" Opacity="0.1"/>
                                    </Canvas>
                                </Grid>
                                </md:TransitioningContent>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </ScrollViewer>
                
            </Grid>

        </md:DrawerHost>
        
    </md:DialogHost>
   
</UserControl>

ToDoViewModel.cs

namespace MyToDo.ViewModels
{
   public class ToDoViewModel: NavigationViewModel
    {
        //由于NavigationViewModel 類構(gòu)造中傳入了 IOC容器,所以當(dāng)前類繼承的時(shí)候,需要把對(duì)應(yīng)的參數(shù)傳通過Base傳過去就不會(huì)報(bào)錯(cuò)了
        public ToDoViewModel(IToDoService toDoService, IContainerProvider provider):base(provider)
        {
            ToDoDtos = new ObservableCollection<ToDoDto>();
            ExecuteCommand = new DelegateCommand<string>(Execute);
            SelectedCommand = new DelegateCommand<ToDoDto>(Selected);
            DeleteCommand = new DelegateCommand<ToDoDto>(Delete);
            this.toDoService = toDoService;
        }

        private bool isRightDrawerOpen;
        /// <summary>
        /// 右側(cè)編輯窗口是否展開
        /// </summary>
        public bool IsRightDrawerOpen
        {
            get { return isRightDrawerOpen; }
            set { isRightDrawerOpen = value; RaisePropertyChanged(); }
        }


        public DelegateCommand<string> ExecuteCommand{ get; private set; }
        public DelegateCommand<ToDoDto> SelectedCommand { get; private set; }
        public DelegateCommand<ToDoDto> DeleteCommand { get; private set; }
        private ObservableCollection<ToDoDto> toDoDtos;
        private readonly IToDoService toDoService;

        /// <summary>
        /// 創(chuàng)建數(shù)據(jù)的動(dòng)態(tài)集合
        /// </summary>
        public ObservableCollection<ToDoDto> ToDoDtos
        {
            get { return toDoDtos; }
            set { toDoDtos = value;RaisePropertyChanged(); }
        }
        private ToDoDto currentDto;
        /// <summary>
        /// 編輯選中/新增對(duì)象
        /// </summary>
        public ToDoDto CurrentDto
        {
            get { return currentDto; }
            set { currentDto = value; RaisePropertyChanged(); }
        }

        private string search;
        /// <summary>
        /// 用戶輸入的搜索條件
        /// </summary>
        public string Search
        {
            get { return search; }
            set { search = value; RaisePropertyChanged(); }
        }
        private int? selectIndex = 0;
        /// <summary>
        /// 下拉列表狀態(tài)值
        /// </summary>
        public int? SelectIndex 
        {
            get { return selectIndex; }
            set { selectIndex = value; RaisePropertyChanged(); }
        }



        /// <summary>
        /// 獲取數(shù)據(jù)
        /// </summary>
        async void GetDataAsync()
        {
            UpdateLoading(true); //發(fā)布消息,設(shè)置加載中的窗口
            //前端界面 0全部,1 待辦,2 已完成;數(shù)據(jù)庫實(shí)際值,0待辦,1已完成
             int? stastus=  SelectIndex == 0 ? null : SelectIndex == 2 ? 1 : 0;
            //添加查詢條件
            var todoResult=await toDoService.GetAllFilterAsync(new Shared.Parameters.ToDoParameter()
            {
                PageIndex = 0,
                PageSize = 100,
                Search = Search, //傳入搜索框查詢條件
                Status= stastus //下拉框值
            });
            if (todoResult.Status)
            {
                toDoDtos.Clear();
                foreach (var item in todoResult.Result.Items)
                {
                    toDoDtos.Add(item);
                }
            }
            UpdateLoading(false); //發(fā)布消息,關(guān)閉加載中的窗口
        }
        /// <summary>
        /// 添加待辦
        /// </summary>
        /// <exception cref="NotImplementedException"></exception>
        private void Add()
        {
            CurrentDto = new ToDoDto();//添加時(shí),初始化一個(gè)新對(duì)象
            IsRightDrawerOpen = true;
        }
        private async void Save()
        {
            //判斷數(shù)據(jù)是否為空
            if (string.IsNullOrWhiteSpace(CurrentDto.Title) || string.IsNullOrWhiteSpace(CurrentDto.Content)) return;
            UpdateLoading(true);
            try
            {
                if (CurrentDto.Id > 0) //Id 大于0,表示編輯。否則新增
                {
                    var updateResult = await toDoService.UpdateAsync(CurrentDto);
                    if (updateResult.Status) //更新成功
                    {
                        //查找到當(dāng)前界面更新的那個(gè)條數(shù)據(jù),把顯示的內(nèi)容進(jìn)行更新
                        var todo = ToDoDtos.FirstOrDefault(t => t.Id == CurrentDto.Id);
                        if (todo != null)
                        {
                            todo.Title = CurrentDto.Title;
                            todo.Content = CurrentDto.Content;
                            todo.Status = CurrentDto.Status;
                        }
                        IsRightDrawerOpen = false; //關(guān)閉編輯窗口
                    }
                }
                else
                {
      
                    var addResult = await toDoService.AddAsync(CurrentDto);
                    if (addResult.Status)
                    {
                        if(addResult.Result != null)
                        {
                            ToDoDtos.Add(addResult.Result); //把數(shù)據(jù)添加到界面的集合中
                            IsRightDrawerOpen = false; //關(guān)閉新增窗口
                        } 
                    }
                }
            }
            catch (Exception ex)
            {
                await Console.Out.WriteLineAsync(ex.Message);
            }
            finally
            {
                UpdateLoading(false);
            }
        }

        private async void Delete(ToDoDto dto)
        {
           var deleteResult=await toDoService.DeleteAsync(dto.Id);
            if (deleteResult.Status)
            {
                //在當(dāng)前數(shù)據(jù)集合中,找到當(dāng)前已經(jīng)刪除掉的數(shù)據(jù),并移除掉
               var model= ToDoDtos.FirstOrDefault(t => t.Id.Equals(dto.Id));
                if(model != null) ToDoDtos.Remove(model);
            }
        }
        /// <summary>
        /// 根據(jù)不同的參數(shù),處理不同的邏輯
        /// </summary>
        /// <param name="obj"></param>
        private void Execute(string obj)
        {
            switch (obj)
            {
                case "新增":
                    Add();
                    break;
                case "查詢":
                    GetDataAsync();
                    break;
                case "保存":
                    Save();
                    break;
            }
        }
        private async void Selected(ToDoDto obj)
        {
            try
            {
                UpdateLoading(true);
             
                //進(jìn)行數(shù)據(jù)查詢
                var todoResult = await toDoService.GetFirstOfDefaultAsync(obj.Id);
                if (todoResult.Status)
                {
                    //把拿到的結(jié)果,賦給一個(gè)當(dāng)前選中的ToDoDto
                    CurrentDto = todoResult.Result;
                    IsRightDrawerOpen = true;//打開窗口
                }
            }
            catch (Exception ex)
            {
                await Console.Out.WriteLineAsync(ex.Message);
            }
            finally
            {
                UpdateLoading(false);
            }
          
        }

        //重寫導(dǎo)航加載數(shù)據(jù)的方法
        public override void OnNavigatedTo(NavigationContext navigationContext)
        {
            base.OnNavigatedTo(navigationContext);
            GetDataAsync();
        }
    }
}

整個(gè)項(xiàng)目結(jié)構(gòu) ,其他有小改動(dòng)的接口都在錯(cuò)誤排查里面體現(xiàn)了。貼源碼太多了。

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#


三.當(dāng)前章節(jié)所有出現(xiàn)的錯(cuò)誤排查

1.查詢報(bào)錯(cuò),是Dto 引用不對(duì),應(yīng)該引用的是MyToDo.Shared

如果運(yùn)行點(diǎn)擊查詢報(bào)錯(cuò),一定要檢查,所有的接口使用的Dto是不是MyToDo.Shared 里面的Dto,而不是引用MyToDo下面Models 文件夾中的Dto?;蛘哒f,直接把 MyToDo 下面的Models 文件夾中的Dto 類型刪除掉。重新引用接口報(bào)錯(cuò)的Dto 類就可以了。

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#

例如:ToDoService 接口處理,重新引用Dto。同其他的報(bào)錯(cuò)的ViewMode類 一樣處理,重新引用一下Dto就可以了。

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#

2.待辦事項(xiàng)接口查詢一直無數(shù)據(jù)返回

  • 檢查待辦事項(xiàng)接口,獲取倉儲(chǔ)時(shí),傳的實(shí)體是否是ToDo(待辦事項(xiàng)實(shí)體)

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#

  • 檢查待辦事項(xiàng)請(qǐng)求的Method 類型是否設(shè)置正確

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#

3.搜索框輸入關(guān)鍵詞查詢,一直無數(shù)據(jù)返回

修改待辦事項(xiàng)查詢接口,根據(jù)標(biāo)題關(guān)鍵詞查詢,是使用?Contains(包含)而不是Equals(等于)

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#

4.新增總是返回 status?400報(bào)不錯(cuò),導(dǎo)致沒辦新增或更新成功

將原來添加請(qǐng)求參數(shù)?request.AddParameter 替換成?request.AddJsonBody。主要參考官網(wǎng)例子???赡艽蟾攀钦?qǐng)求傳參數(shù)處理的有問題或其他原因,暫時(shí)不管了。

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#

5.實(shí)際數(shù)據(jù)庫已更新成功,但代碼執(zhí)行總是報(bào)錯(cuò)

在 ToDoController 中,修改更新邏輯,更新成功后把Todo實(shí)體返回出去。這樣在序列化的時(shí)候才能不報(bào)錯(cuò)。如果直接返回一個(gè)字符串:例如:更新成功。會(huì)導(dǎo)致序列化出錯(cuò),從而影響到前端界面顯示。

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#

6.添加成功的待辦,無法再次編輯

由于原來新增成功后,返回的實(shí)體是傳遞過來的 model實(shí)體,ID屬性值為空,導(dǎo)致該問題。只需要把添加成功的新實(shí)體返回即可。

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#

7.待辦事項(xiàng)刪除報(bào)錯(cuò)?

把通用刪除接口返回?ApiResponse修改成?ApiResponse<TEntity> 泛型類

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#

同時(shí)在MyToDo.Api ToDoService 中,修改刪除 DeleteAsync接口邏輯,把刪除的實(shí)體返回出去即可。

Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19,WPF入門,wpf,c#文章來源地址http://www.zghlxwxcb.cn/news/detail-855984.html

到了這里,關(guān)于Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day19的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?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)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

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

相關(guān)文章

  • Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day03

    Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day03

    效果圖: ? 創(chuàng)建 Models ,放置實(shí)體類。 實(shí)體類需要繼承自 Prism 框架的? BindableBase ,目的是讓實(shí)體類支持?jǐn)?shù)據(jù)的動(dòng)態(tài)變更! ?例如: 系統(tǒng)導(dǎo)航菜單實(shí)體類 創(chuàng)建View文件夾? 放置前端顯示頁面 。例如:創(chuàng)建首頁: MainView.xaml 創(chuàng)建ViewModel 文件夾,放置前端邏輯處理類。意思是:有前端

    2024年02月08日
    瀏覽(22)
  • Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day13

    Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day13

    在上一節(jié)? ToDoController 控制器,或 IToDoService 服務(wù)接口中,方法的傳參都是直接傳的實(shí)體類。但在實(shí)際開發(fā)過程中,這樣是不允許的。標(biāo)準(zhǔn)且規(guī)范的做法是,定義一個(gè)數(shù)據(jù)傳輸層,即Dto層。 1. 創(chuàng)建 BaseDto 基類,用于存放共用屬性。 2. 創(chuàng)建待辦事項(xiàng) Dto類,并繼承自 BaseDto 基類

    2024年01月20日
    瀏覽(42)
  • Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day10

    Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day10

    1-9章節(jié)已經(jīng)把基本功能都做好了,但頁面的數(shù)據(jù)是后臺(tái)模擬生成的靜態(tài)數(shù)據(jù)。接下來所有章節(jié)就是實(shí)現(xiàn),頁面的所有數(shù)據(jù)都是從數(shù)據(jù)庫中獲取,并且實(shí)現(xiàn)頁面數(shù)據(jù)的持久化以及增刪改查。 使用Sqlite 做為數(shù)據(jù)庫? 1.打開 MyToDo.Api項(xiàng)目,右鍵=》選擇 管理NuGet 程序包?,進(jìn)行下載安

    2024年01月25日
    瀏覽(21)
  • Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day11

    Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day11

    ?倉儲(chǔ)(rep):倉儲(chǔ)接口定義了對(duì)實(shí)體類訪問數(shù)據(jù)庫及操作的方法。它統(tǒng)一管理數(shù)據(jù)訪問的邏輯,并與業(yè)務(wù)邏輯層進(jìn)行解耦。 簡單的理解就是對(duì)訪問數(shù)據(jù)庫的一層接口封裝。 工作單元(uow):用來保證我們處理業(yè)務(wù)邏輯的,穩(wěn)定性,完整性。防止在業(yè)務(wù)操作過程中,涉及對(duì)數(shù)據(jù)

    2024年02月02日
    瀏覽(31)
  • Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day08

    Wpf 使用 Prism 實(shí)戰(zhàn)開發(fā)Day08

    1.效果圖 MemoView.xaml 頁面代碼 ? ? ?1. 在? ItemsControl 中,添加滾動(dòng)條? ScrollViewer ?這樣使用 ScrollViewer 把內(nèi)容區(qū)域包裹起來,就能讓內(nèi)容區(qū)域支持滾動(dòng)了 ? ? ?? 2 . 添加滾動(dòng)條后的效果圖如下:? 使用md 中的一個(gè)自帶動(dòng)畫 md:TransitioningContent 來實(shí)現(xiàn)該功能? 需要設(shè)置一個(gè)屬性,

    2024年02月03日
    瀏覽(20)
  • WPF超好用的框架Prism入門使用,上位機(jī)趕緊學(xué)起來!

    WPF框架Prism是一種用于開發(fā)模塊化、可重用和可測(cè)試的WPF應(yīng)用程序的框架。它提供了一種簡單而強(qiáng)大的方式來管理復(fù)雜應(yīng)用程序的代碼和構(gòu)建高度可擴(kuò)展的應(yīng)用程序。 如果您想使用Prism框架來開發(fā)WPF應(yīng)用程序,需要學(xué)習(xí)以下幾個(gè)方面: MVVM模式 :Prism基于MVVM模式,因此需要了

    2024年02月01日
    瀏覽(44)
  • WPF開發(fā)學(xué)生信息管理系統(tǒng)【W(wǎng)PF+Prism+MAH+WebApi】(四)

    WPF開發(fā)學(xué)生信息管理系統(tǒng)【W(wǎng)PF+Prism+MAH+WebApi】(四)

    最近通過WPF開發(fā)項(xiàng)目,為了對(duì)WPF知識(shí)點(diǎn)進(jìn)行總結(jié),所以利用業(yè)余時(shí)間,開發(fā)一個(gè)學(xué)生信息管理系統(tǒng)【Student Information Management System】。前三篇文章進(jìn)行了框架搭建和模塊劃分,后臺(tái)WebApi接口編寫,以及課程管理模塊開發(fā),本文在前三篇基礎(chǔ)之上,繼續(xù)深入開發(fā)學(xué)生信息管理系統(tǒng)

    2024年02月04日
    瀏覽(33)
  • WPF開發(fā)之Prism詳解【內(nèi)附源碼】

    WPF開發(fā)之Prism詳解【內(nèi)附源碼】

    在實(shí)際應(yīng)用開發(fā)中,隨著項(xiàng)目業(yè)務(wù)逐漸復(fù)雜,耦合度會(huì)越來越高,維護(hù)成本也會(huì)直線上升,所以解耦也變得越來越重要。Prism框架為WPF開發(fā)中解耦提供了非常便捷的應(yīng)用。今天主要以一個(gè)簡單的小例子,簡述WPF開發(fā)中Prism框架的簡單應(yīng)用,如有不足之處,還請(qǐng)指正。 Prism是一個(gè)

    2023年04月16日
    瀏覽(30)
  • WPF Prism的簡單使用

    新建 WPF 項(xiàng)目,我是基于 .net 5.0-windows 創(chuàng)建的。 引入 Prism.DryIoc(8.1.97) 的 Nuget 包。 App.xaml 中引入命名空間。 將 App.xaml 中 Application 標(biāo)簽更改成 prism:PrismApplication 并去除 StartUri 屬性,將 App.xaml.cs 中 Application 更改成 PrismApplication 。 實(shí)現(xiàn) PrismApplication (實(shí)際上是 PrismApplicationBas

    2023年04月14日
    瀏覽(17)
  • WPF框架Prism的使用 二

    這是第二篇關(guān)于Prism-WPF的介紹,第一篇中我們簡單介紹了Prism,然后講述了如何搭建一個(gè)MVVM的簡單頁面程序。其實(shí)我寫的文章就是把github上面的官方例子摘出來自己跑了一遍,然后加上了一些自己的理解,簡單給大家分享一下。 下面放上傳送門: 第一篇的鏈接 官方提供的示

    2024年04月10日
    瀏覽(26)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包