Wpf 使用 Prism 实战开发Day19

server/2024/9/24 22:56:05/

待办事项功能页面完善以及优化

概要:

由于待办事项功能页,数据已正常渲染出来了。但页面新增,查询,修改,删除等功能还未实现。本章节来实现页面的请求后台实现CURD(增删改查)


一.待办事项查询搜索删除增加等功能

根据渲染出来的待办事项,点击对应的待办事项时,查找出该条数据,显展示在编辑窗口中。

同时在搜索框中输入的参数或选择的待办事项状态,按下Enter按键时,触发查询。

1.首先把待办事项页修改成支持编辑的功能,也就是增加触发器。需要引入微软行为类 behaviors

ToDoView.xaml 前端页引入命名空间

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

 修改 Grid,支持编辑功能

<!--自定义内容区域-->
<Grid Width="220" MinHeight="180" MaxHeight="250" Margin="8" ><!--行为触发器--><i:Interaction.Triggers><!--鼠标左击事件--><i:EventTrigger EventName="MouseLeftButtonUp"><!--设置命令--><i:InvokeCommandAction CommandParameter="{Binding}"Command="{Binding DataContext.SelectedCommand ,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ItemsControl}}"/></i:EventTrigger></i:Interaction.Triggers>
</Grid>
  1. EventTrigger 通过EventName 锁定当前事件名称
  2. RelativeSource 指定绑定的属性
  3. Mode 设置查找模式
  4. AncestorType 设置绑定的类型
  5. DataContext 设置绑定命令
  6. CommandParameter 设置当前绑定命令传递到后台的参数

2.待办事项对应的后台处理逻辑类 (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>/// 右侧编辑窗口是否展开/// </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>/// 编辑选中/新增对象/// </summary>public ToDoDto CurrentDto{get { return currentDto; }set { currentDto = value; RaisePropertyChanged(); }}private async void Selected(ToDoDto obj){try{UpdateLoading(true);//进行数据查询var todoResult = await toDoService.GetFirstOfDefaultAsync(obj.Id);if (todoResult.Status){//把拿到的结果,赋给一个当前选中的ToDoDtoCurrentDto = todoResult.Result;IsRightDrawerOpen = true;//打开窗口}}catch (Exception ex){await Console.Out.WriteLineAsync(ex.Message);}finally{UpdateLoading(false);}}}
}

数据查出来后,前端也需要绑定对应的数据模型,才能显示


3.搜索框输入文本,按下Enter 按键时触发查询

首先,需要在搜索框绑定一个属性,用来接收用户输入的参数。那么对应后台逻辑处理类  ToDoViewModel 需定义这么一个属性。然后前台需要绑定该属性。并且设置绑定的模式Mode为(双向绑定)TwoWay,并且设置(更新的数据源)UpdateSourceTrigger为PropertyChanged(一旦发生变化,马上通知更新),

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

接着,给输入框绑定一个回车(Enter)事件。同时绑定一个(ExecuteCommand)指令,以及(CommandParameter)传递给后台的处理的参数。

<!--设置绑定模式和更新数据源类型-->
<TextBox Text="{Binding Search,Mode=OneWay,UpdateSourceTrigger=PropertyChanged}"><!--搜索框绑定回车事件--><TextBox.InputBindings><!--通过Key 绑定--><KeyBinding Key="Enter"  Command="{Binding ExecuteCommand}" CommandParameter="查询"/></TextBox.InputBindings>
</TextBox>

4.处理逻辑类 (ToDoViewModel)添加一个通用(ExecuteCommand)绑定指令,根据(CommandParameter)传递不同的参数处理不同的逻辑。例如:

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>/// 根据不同的参数,处理不同的逻辑/// </summary>/// <param name="obj"></param>private void Execute(string obj){switch (obj){case "新增":Add();break;case "查询":GetDataAsync();break;case "保存":Save();break;}}}
}

5.待办事项功能页,根据待办不同的状态,显示不同的颜色

在ToDoView.xaml 渲染背景颜色Border 中,增加一个触发器来处理,例如:

 <!--整个框圆角--><Border CornerRadius="3" Grid.RowSpan="2" ><!--增加触发器,根据绑定的状态不同,显示不同的颜色--><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>

后台ToDoViewModel 逻辑实现

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>/// 创建数据的动态集合/// </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){//在当前数据集合中,找到当前已经删除掉的数据,并移除掉var model= ToDoDtos.FirstOrDefault(t => t.Id.Equals(dto.Id));if(model != null) ToDoDtos.Remove(model);}}}
}

7.当查找不到数据时,希望显示一个默认的图片。例如暂无数据。。

ToDoView.xaml 前端页面修改,先添加一张图片。然后,如何判断是否有无数据。是通过添加转换器,拿到ToDoDtos 数据集合统计总数是否为0来显示或隐藏当前图片。随便找一张图片放在Image文件夹中

 <!--当查不到数据时,要显示的图片。添加转换器来控制,要不要显示这个图片-->
<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="哇哦,暂无数据"/>
</StackPanel>

添加转换器 IntToVisibilityConveter,需继承自 IValueConverter。

namespace MyToDo.Common.Converters
{/// <summary>/// 转换器/// </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();}}
}

转换器编写完成后,然后添加到 ToDoView.xaml 前端当中进行使用。

首先引入转换器命名空间

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

然后,还需要在当前ToDoView.xaml 用户控件的资源文件中,进行声明。

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

8.根据下拉列表选择的状态值查询 

同搜索框查询处理方式一样,然后下拉列表 ComboBox 也需要绑定一个属性。那么首先要定义这个属性,然后在ToDoView.xaml 中的选择框中,绑定这个 SelectIndex 属性

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

后台 ToDoViewModel 逻辑中,需要去定义这个 SelectIndex 属性。由于基类没有根据该条件的查询,所以我们可以自定义自己的查询接口和参数,从而避免修改到基类共用类的方法函数。

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>/// 创建数据的动态集合/// </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>/// 下拉列表状态值/// </summary>public int SelectIndex{get { return selectIndex; }set { selectIndex = value; RaisePropertyChanged(); }}/// <summary>/// 获取数据/// </summary>async void GetDataAsync(){UpdateLoading(true); //发布消息,设置加载中的窗口//前端界面 0全部,1 待办,2 已完成;数据库实际值,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); //发布消息,关闭加载中的窗口}//重写导航加载数据的方法public override void OnNavigatedTo(NavigationContext navigationContext){base.OnNavigatedTo(navigationContext);GetDataAsync();}}
}

自定义查询接口和参数实现,例如:当前根据下拉列表状态查询,由于基类方法不适用。需要新增一个自定义的查询接口和参数

 步骤1.MyToDo.Shared 项目中,定义一个 ToDoParameter 类,继承自QueryParameter 类
  public class ToDoParameter: QueryParameter{public int? Status { get; set; }}

步骤2.在MyToDo 项目Service 文件中,增加自定义的查询接口,并传入定义的参数类
namespace MyToDo.Service
{public interface IToDoService:IBaseService<ToDoDto>{Task<ApiResponse<PagedList<ToDoDto>>> GetAllFilterAsync(ToDoParameter parameter);}
}

步骤3.ToDoService 中去实现自定义的接口,查询条件就加上自定义根据状态来查
namespace MyToDo.Service
{public class ToDoService : BaseService<ToDoDto>, IToDoService{private readonly HttpRestClient client;/// <summary>/// 构造中,直接传控制器名称进去。因为在Web Api项目中,待办事项控制器的名称,就是叫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);}}
}

步骤4.接着,修改MyToDo.Api 项目,首先IToDoService 新增一个 GetAllFilter 接口
namespace MyToDo.Api.Service
{public interface IToDoService: IBaseService<ToDoDto>{Task<ApiResponse> GetAllFilterAsync(ToDoParameter query);}
}

步骤5.接着,在MyToDo.Api 项目 去ToDoService层实现 GetAllFilterAsync 接口
 public async Task<ApiResponse> GetAllFilterAsync(ToDoParameter query){try{var todos = await work.GetRepository<ToDo>()//根据标题查,如果传过来的Search 为空,直接过。否则就匹配标题。.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) //根据创建时间进行排序);return new ApiResponse(true, todos); //返回true,并返回所有数据}catch (Exception ex){return new ApiResponse(ex.Message);}}

步骤6.然后还要在MyToDo.Api 项目中,修改ToDoController 控制器,添加GetAllFilter 接口方法,并传入自定义的参数。
[HttpGet]
public async Task<ApiResponse> GetAllFilter([FromQuery] ToDoParameter query) => await service.GetAllFilterAsync(query);

步骤7.最后,在 MyToDo 项目中的 ToDoViewModel 逻辑处理层去使用它
  /// <summary>/// 获取数据/// </summary>async void GetDataAsync(){UpdateLoading(true); //发布消息,设置加载中的窗口//前端界面 0全部,1 待办,2 已完成;数据库实际值,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); //发布消息,关闭加载中的窗口}


二.完整源码

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}"><!--设计右边弹出层--><md:DrawerHost.RightDrawerContent><!--定义弹出层的内容区域--><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="状态:"  Padding="0,0,10,0" VerticalAlignment="Center"/><ComboBox SelectedIndex="{Binding CurrentDto.Status}"> <!--通过绑定索引来找到对应的状态--><ComboBoxItem>待办</ComboBoxItem><ComboBoxItem>已完成</ComboBoxItem></ComboBox></StackPanel><TextBox Text="{Binding CurrentDto.Title}" md:HintAssist.Hint="请输入待办概要" Margin="20,0" DockPanel.Dock="Top"/><TextBox Text="{Binding CurrentDto.Content}" md:HintAssist.Hint="请输入待办内容" 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"><!--设置绑定模式和更新数据源类型--><TextBox Text="{Binding Search,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Width="250" VerticalAlignment="Center" md:HintAssist.Hint="查找待办事项..." 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="新增" /><!--当查不到数据时,要显示的图片。添加转换器来控制,要不要显示这个图片--><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="哇哦,暂无数据"/></StackPanel><ScrollViewer Grid.Row="1"><ItemsControl  HorizontalAlignment="Center" ItemsSource="{Binding ToDoDtos}"><ItemsControl.ItemsPanel><ItemsPanelTemplate><WrapPanel /></ItemsPanelTemplate></ItemsControl.ItemsPanel><!--自定义内容模板--><ItemsControl.ItemTemplate><DataTemplate><md:TransitioningContent OpeningEffect="{md:TransitionEffect Kind=ExpandIn}"><!--自定义内容区域--><Grid Width="220" MinHeight="180" MaxHeight="250" Margin="8" ><!--行为触发器--><i:Interaction.Triggers><!--鼠标左击事件--><i:EventTrigger EventName="MouseLeftButtonUp"><!--设置命令--><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><!--整个框圆角--><Border CornerRadius="3" Grid.RowSpan="2" ><!--增加触发器,根据绑定的状态不同,显示不同的颜色--><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 类构造中传入了 IOC容器,所以当前类继承的时候,需要把对应的参数传通过Base传过去就不会报错了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>/// 右侧编辑窗口是否展开/// </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>/// 创建数据的动态集合/// </summary>public ObservableCollection<ToDoDto> ToDoDtos{get { return toDoDtos; }set { toDoDtos = value;RaisePropertyChanged(); }}private ToDoDto currentDto;/// <summary>/// 编辑选中/新增对象/// </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>/// 下拉列表状态值/// </summary>public int? SelectIndex {get { return selectIndex; }set { selectIndex = value; RaisePropertyChanged(); }}/// <summary>/// 获取数据/// </summary>async void GetDataAsync(){UpdateLoading(true); //发布消息,设置加载中的窗口//前端界面 0全部,1 待办,2 已完成;数据库实际值,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); //发布消息,关闭加载中的窗口}/// <summary>/// 添加待办/// </summary>/// <exception cref="NotImplementedException"></exception>private void Add(){CurrentDto = new ToDoDto();//添加时,初始化一个新对象IsRightDrawerOpen = true;}private async void Save(){//判断数据是否为空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) //更新成功{//查找到当前界面更新的那个条数据,把显示的内容进行更新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; //关闭编辑窗口}}else{var addResult = await toDoService.AddAsync(CurrentDto);if (addResult.Status){if(addResult.Result != null){ToDoDtos.Add(addResult.Result); //把数据添加到界面的集合中IsRightDrawerOpen = false; //关闭新增窗口} }}}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){//在当前数据集合中,找到当前已经删除掉的数据,并移除掉var model= ToDoDtos.FirstOrDefault(t => t.Id.Equals(dto.Id));if(model != null) ToDoDtos.Remove(model);}}/// <summary>/// 根据不同的参数,处理不同的逻辑/// </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);//进行数据查询var todoResult = await toDoService.GetFirstOfDefaultAsync(obj.Id);if (todoResult.Status){//把拿到的结果,赋给一个当前选中的ToDoDtoCurrentDto = todoResult.Result;IsRightDrawerOpen = true;//打开窗口}}catch (Exception ex){await Console.Out.WriteLineAsync(ex.Message);}finally{UpdateLoading(false);}}//重写导航加载数据的方法public override void OnNavigatedTo(NavigationContext navigationContext){base.OnNavigatedTo(navigationContext);GetDataAsync();}}
}

整个项目结构 ,其他有小改动的接口都在错误排查里面体现了。贴源码太多了。


三.当前章节所有出现的错误排查

1.查询报错,是Dto 引用不对,应该引用的是MyToDo.Shared

如果运行点击查询报错,一定要检查,所有的接口使用的Dto是不是MyToDo.Shared 里面的Dto,而不是引用MyToDo下面Models 文件夹中的Dto。或者说,直接把 MyToDo 下面的Models 文件夹中的Dto 类型删除掉。重新引用接口报错的Dto 类就可以了。

例如:ToDoService 接口处理,重新引用Dto。同其他的报错的ViewMode类 一样处理,重新引用一下Dto就可以了。

2.待办事项接口查询一直无数据返回

  • 检查待办事项接口,获取仓储时,传的实体是否是ToDo(待办事项实体)

  • 检查待办事项请求的Method 类型是否设置正确

3.搜索框输入关键词查询,一直无数据返回

修改待办事项查询接口,根据标题关键词查询,是使用 Contains(包含)而不是Equals(等于)

4.新增总是返回 status 400报不错,导致没办新增或更新成功

将原来添加请求参数 request.AddParameter 替换成 request.AddJsonBody。主要参考官网例子 。可能大概是请求传参数处理的有问题或其他原因,暂时不管了。

5.实际数据库已更新成功,但代码执行总是报错

在 ToDoController 中,修改更新逻辑,更新成功后把Todo实体返回出去。这样在序列化的时候才能不报错。如果直接返回一个字符串:例如:更新成功。会导致序列化出错,从而影响到前端界面显示。

6.添加成功的待办,无法再次编辑

由于原来新增成功后,返回的实体是传递过来的 model实体,ID属性值为空,导致该问题。只需要把添加成功的新实体返回即可。

7.待办事项删除报错 

把通用删除接口返回 ApiResponse修改成 ApiResponse<TEntity> 泛型类

同时在MyToDo.Api ToDoService 中,修改删除 DeleteAsync接口逻辑,把删除的实体返回出去即可。


http://www.ppmy.cn/server/8243.html

相关文章

CentOS显示mac地址错误|虚拟机克隆|CentOS静态ip

文章目录 怎么复制虚拟机&#xff1f;修改虚拟机静态ip遇到的错误解决 怎么复制虚拟机&#xff1f; 方法一&#xff1a; 方法二&#xff1a; 1.以前创建好的虚拟机所在文件夹复制一份&#xff0c;改名字 2.在虚拟机中打开 后缀为.vmx文件 3.启动虚拟机 修改虚拟机静态ip …

C++:多态

目录 概念&#xff1a; 多态产生的条件&#xff1a; 虚函数的重写&#xff1a; 虚函数&#xff1a;即被virtual修饰的类成员函数称为虚函数 虚函数重写的两个例外&#xff1a; 协变(基类与派生类虚函数返回值类型不同) 析构函数 而为什么没有调用到子类呢&#xff1f; …

Java最短路径问题知识点(含面试大厂题和源码)

最短路径问题是图论中的一个经典问题&#xff0c;它寻找图中两点之间的最短路径。这个问题在现实世界中有广泛的应用&#xff0c;比如导航系统中的路线规划、网络中的信息传输等。解决最短路径问题有多种算法&#xff0c;其中最著名的包括&#xff1a; 贝尔曼-福特算法&#xf…

C#:直接调用 OpenFileDialog

C# 直接调用 OpenFileDialog&#xff0c;打开文件夹&#xff0c;选择视频文件&#xff0c;并播放。 编写 openvideo.cs 如下 // open a video file using System; using System.Diagnostics; using System.Windows.Forms;public class OpenVideoFile {[STAThread]public st…

arm64-v8a、armeabi-v7a、x86、x86_64

当我们去GitHub下载应用的时候是不是经常很懵逼&#xff0c;就像下图一样&#xff0c;粗看一下如此多安装包到底要选择下载哪个且每种安装包到底有哪差别&#xff1f;毕竟因为自己一无所知&#xff0c;有时便随意下载一个后&#xff0c;安装时却报『此版本与你的系统不兼容』的…

走进敦煌说谷雨 | 谷雨万物新,推开那扇门

谷雨&#xff0c;是春季的最后一个节气&#xff0c; 也铺垫着“热烈”夏天的到来。 让我们来到敦煌&#xff0c;遍寻上下五千年&#xff0c; 了解谷雨在文物里的故事和习俗。 雨生百谷 且把春留驻 谷雨取自“雨生百谷”之意。谷雨&#xff0c;意味着寒潮天气基本结束。这时…

2024.4.19作业

1.总结二进制信号量和计数型信号量的区别&#xff0c;以及他们的使用场景。 二进制信号量只有0和1两个状态&#xff0c;如果信号被一个线程接收&#xff0c;那别的线程就无法接收此信号 计数型信号可以累计&#xff0c;可以被多个线程接收 2.使用计数型信号量完成生产者和消费…

数据结构-前缀树

前缀树 前缀树定义 前缀树&#xff08;Trie树&#xff09;&#xff0c;又称字典树、单词查找树或键树&#xff0c;是一种专门设计用于高效存储和检索字符串集合中词项的树形数据结构。其核心特性在于能够快速实现字符串的前缀匹配&#xff0c;极大减少了无谓的字符比较&#xf…