待辦事項(xiàng)功能頁面完善以及優(yōu)化
概要:
由于待辦事項(xiàng)功能頁,數(shù)據(jù)已正常渲染出來了。但頁面新增,查詢,修改,刪除等功能還未實(shí)現(xiàn)。本章節(jié)來實(shí)現(xiàn)頁面的請(qǐng)求后臺(tái)實(shí)現(xiàn)CURD(增刪改查)
一.待辦事項(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>
- EventTrigger 通過EventName 鎖定當(dāng)前事件名稱
- RelativeSource 指定綁定的屬性
- Mode 設(shè)置查找模式
- AncestorType 設(shè)置綁定的類型
- DataContext 設(shè)置綁定命令
- 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ù)模型,才能顯示
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; }
}
步驟2.在MyToDo 項(xiàng)目Service 文件中,增加自定義的查詢接口,并傳入定義的參數(shù)類
namespace MyToDo.Service
{
public interface IToDoService:IBaseService<ToDoDto>
{
Task<ApiResponse<PagedList<ToDoDto>>> GetAllFilterAsync(ToDoParameter parameter);
}
}
步驟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);
}
}
}
步驟4.接著,修改MyToDo.Api 項(xiàng)目,首先IToDoService 新增一個(gè) GetAllFilter 接口
namespace MyToDo.Api.Service
{
public interface IToDoService: IBaseService<ToDoDto>
{
Task<ApiResponse> GetAllFilterAsync(ToDoParameter query);
}
}
步驟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);
}
}
步驟6.然后還要在MyToDo.Api 項(xiàng)目中,修改ToDoController 控制器,添加GetAllFilter 接口方法,并傳入自定義的參數(shù)。
[HttpGet]
public async Task<ApiResponse> GetAllFilter([FromQuery] ToDoParameter query) => await service.GetAllFilterAsync(query);
步驟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)閉加載中的窗口
}
二.完整源碼
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)了。貼源碼太多了。
三.當(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 類就可以了。
例如:ToDoService 接口處理,重新引用Dto。同其他的報(bào)錯(cuò)的ViewMode類 一樣處理,重新引用一下Dto就可以了。
2.待辦事項(xiàng)接口查詢一直無數(shù)據(jù)返回
- 檢查待辦事項(xiàng)接口,獲取倉儲(chǔ)時(shí),傳的實(shí)體是否是ToDo(待辦事項(xiàng)實(shí)體)
- 檢查待辦事項(xiàng)請(qǐng)求的Method 類型是否設(shè)置正確
3.搜索框輸入關(guān)鍵詞查詢,一直無數(shù)據(jù)返回
修改待辦事項(xiàng)查詢接口,根據(jù)標(biāo)題關(guān)鍵詞查詢,是使用?Contains(包含)而不是Equals(等于)
4.新增總是返回 status?400報(bào)不錯(cuò),導(dǎo)致沒辦新增或更新成功
將原來添加請(qǐng)求參數(shù)?
request.AddParameter替換成?request.AddJsonBody。主要參考官網(wǎng)例子???赡艽蟾攀钦?qǐng)求傳參數(shù)處理的有問題或其他原因,暫時(shí)不管了。
5.實(shí)際數(shù)據(jù)庫已更新成功,但代碼執(zhí)行總是報(bào)錯(cuò)
在 ToDoController 中,修改更新邏輯,更新成功后把Todo實(shí)體返回出去。這樣在序列化的時(shí)候才能不報(bào)錯(cuò)。如果直接返回一個(gè)字符串:例如:更新成功。會(huì)導(dǎo)致序列化出錯(cuò),從而影響到前端界面顯示。
6.添加成功的待辦,無法再次編輯
由于原來新增成功后,返回的實(shí)體是傳遞過來的 model實(shí)體,ID屬性值為空,導(dǎo)致該問題。只需要把添加成功的新實(shí)體返回即可。
7.待辦事項(xiàng)刪除報(bào)錯(cuò)?
把通用刪除接口返回?ApiResponse修改成?ApiResponse<TEntity> 泛型類
同時(shí)在MyToDo.Api ToDoService 中,修改刪除 DeleteAsync接口邏輯,把刪除的實(shí)體返回出去即可。文章來源:http://www.zghlxwxcb.cn/news/detail-855984.html
文章來源地址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)!