待办事项功能页面完善以及优化
概要:
由于待办事项功能页,数据已正常渲染出来了。但页面新增,查询,修改,删除等功能还未实现。本章节来实现页面的请求后台实现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>
- EventTrigger 通过EventName 锁定当前事件名称
- RelativeSource 指定绑定的属性
- Mode 设置查找模式
- AncestorType 设置绑定的类型
- DataContext 设置绑定命令
- 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)
{
//把拿到的结果,赋给一个当前选中的ToDoDto
CurrentDto = 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)
{
//把拿到的结果,赋给一个当前选中的ToDoDto
CurrentDto = 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接口逻辑,把删除的实体返回出去即可。