RestAPI
1) Views/Shared/_Layout.cshtml 수정
2) Home/Index.cshtml 수정
RestAPI를 WPF에서 사용하기
1) WPF 애플리케이션으로 프로젝트 생성
2) 누겟 패키지 관리
- MahApps.Metro 설치 및 적용
https://mahapps.com/docs/guides/quick-start3) MainWindow.xaml 디자인
<mah:MetroWindow x:Class="TodoItemApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mah="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:TodoItemApp" mc:Ignorable="d" Title="TodoList" Height="450" Width="800" Loaded="MetroWindow_Loaded"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="3*"/> <ColumnDefinition Width="2*"/> </Grid.ColumnDefinitions> <DataGrid Grid.Column="0" x:Name="GrdTodoItems" Margin="10" Background="Gainsboro"></DataGrid> <Grid Grid.Column="1" Margin="20"> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> <RowDefinition/> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <TextBox Grid.Row="0" x:Name="TxtId" mah:TextBoxHelper.AutoWatermark="True" mah:TextBoxHelper.Watermark="Id" FontSize="14" Margin="5"/> <TextBox Grid.Row="1" x:Name="TxtTitle" mah:TextBoxHelper.AutoWatermark="True" mah:TextBoxHelper.Watermark="Title" FontSize="14" Margin="5"/> <mah:DateTimePicker Grid.Row="2" x:Name="DtpTodoDate" mah:TextBoxHelper.AutoWatermark="True" mah:TextBoxHelper.Watermark="TodoDate" FontSize="14" Margin="5"/> <ComboBox Grid.Row="3" x:Name="CboIsComplete" FontSize="14" Margin="5" mah:TextBoxHelper.AutoWatermark="True" mah:TextBoxHelper.Watermark="IsComplete"/> <StackPanel Orientation="Horizontal" Grid.Row="4"> <Button x:Name="BtnInsert" Content="Insert" FontSize="14" Width="90" Margin="1,10"/> <Button x:Name="BtnUpdate" Content="Update" FontSize="14" Width="90" Margin="1,10"/> <Button x:Name="BtnDelete" Content="Delete" FontSize="14" Width="90" Margin="1,10"/> </StackPanel> </Grid> </Grid> </mah:MetroWindow>
Day87
1) 누겟 패키지 관리
- Microsoft.AspNet.WebApi.Client 설치
2) Models/TodoItem , TodoItemsCollection 클래스 추가
- TodoItem.cs
using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Media; namespace TodoItemApp.Models { public class TodoItem { [Key] public int Id { get; set; } [Column(TypeName = "Varchar(100)")] public string? Title { get; set; } public string TodoDate { get; set; } public int IsComplete { get; set; } } }
- TodoItemsCollection.cs
using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Collections.Specialized; namespace TodoItemApp.Models { public class TodoItemsCollection : ObservableCollection<TodoItem> { public void CopyForm(IEnumerable<TodoItem> todoItems) { this.Items.Clear();//초기화 foreach (TodoItem item in todoItems) { this.Items.Add(item);//데이터 추가 } //데이터 변경을 알림 this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } } }
3) MainWindow.xaml.cs 수정
using MahApps.Metro.Controls; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using TodoItemApp.Models; using System.Net.Http.Headers; using MahApps.Metro.Controls.Dialogs; using System.Diagnostics; namespace TodoItemApp { public class DivCode { public string Key { get; set; } public string Value { get; set; } } /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : MetroWindow { private List<DivCode> divCodes= new List<DivCode>(); HttpClient client = new HttpClient(); TodoItemsCollection todoItems = new TodoItemsCollection(); public MainWindow() { InitializeComponent(); } private async void MetroWindow_Loaded(object sender, RoutedEventArgs e) { divCodes.Add(new DivCode { Key = "True", Value = "1" }); divCodes.Add(new DivCode { Key = "False", Value = "0" }); CboIsComplete.ItemsSource=divCodes; CboIsComplete.DisplayMemberPath = "Key"; //콤보박스에 True/False 추가 //yyyy-MM--dd HH:mm:ss DtpTodoDate.Culture = new System.Globalization.CultureInfo("ko-KR"); //RestAPI 기본 URI 호출 client.BaseAddress = new Uri("https://localhost:7188/");//RestAPI 서버 기본 URL //헤더 설정 client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); GetData();//데이터 로드 메서드 호출 } private async void GetData() { //데이터그리드 ItemsSource에 todoItems 바인딩 GrdTodoItems.ItemsSource = todoItems; //Api 호출 핵심 try { HttpResponseMessage? response = await client.GetAsync("api/TodoItems"); response.EnsureSuccessStatusCode(); var items = await response.Content.ReadAsAsync<IEnumerable<TodoItem>>(); todoItems.CopyForm(items); } catch (Newtonsoft.Json.JsonException jEx) { await (this.ShowMessageAsync("error", jEx.Message, MessageDialogStyle.Affirmative, new MetroDialogSettings() { AnimateShow = true, AnimateHide = true })); } catch (HttpRequestException ex) { await (this.ShowMessageAsync("error", ex.Message, MessageDialogStyle.Affirmative, new MetroDialogSettings() { AnimateShow = true, AnimateHide = true })); } } private async void BtnInsert_Click(object sender, RoutedEventArgs e) { try { var todoItem = new TodoItem() { Id = 0, Title = TxtTitle.Text, TodoDate = ((DateTime)DtpTodoDate.SelectedDateTime).ToString("yyyy-MM-dd HH:mm:ss"), IsComplete = Int32.Parse((CboIsComplete.SelectedItem as DivCode).Value) }; var response = await client.PostAsJsonAsync("api/TodoItems", todoItem); response.EnsureSuccessStatusCode(); GetData(); TxtId.Text = TxtTitle.Text = string.Empty; CboIsComplete.SelectedIndex = -1; } catch (Newtonsoft.Json.JsonException jEx) { await (this.ShowMessageAsync("error", jEx.Message, MessageDialogStyle.Affirmative, new MetroDialogSettings() { AnimateShow = true, AnimateHide = true })); } catch (HttpRequestException ex) { await (this.ShowMessageAsync("error", ex.Message, MessageDialogStyle.Affirmative, new MetroDialogSettings() { AnimateShow = true, AnimateHide = true })); } } private async void BtnUpdate_Click(object sender, RoutedEventArgs e) { try { var todoItem = new TodoItem() { Id = Int32.Parse(TxtId.Text), Title = TxtTitle.Text, TodoDate = ((DateTime)DtpTodoDate.SelectedDateTime).ToString("yyyy-MM-dd HH:mm:ss"), IsComplete = Int32.Parse((CboIsComplete.SelectedItem as DivCode).Value) }; //Update할때는 Put var response = await client.PutAsJsonAsync($"api/TodoItems/{todoItem.Id}", todoItem); response.EnsureSuccessStatusCode(); GetData(); TxtId.Text = TxtTitle.Text = string.Empty; CboIsComplete.SelectedIndex = -1; } catch (Newtonsoft.Json.JsonException jEx) { await(this.ShowMessageAsync("error", jEx.Message, MessageDialogStyle.Affirmative, new MetroDialogSettings() { AnimateShow = true, AnimateHide = true })); } catch (HttpRequestException ex) { await(this.ShowMessageAsync("error", ex.Message, MessageDialogStyle.Affirmative, new MetroDialogSettings() { AnimateShow = true, AnimateHide = true })); } } private async void BtnDelete_Click(object sender, RoutedEventArgs e) { try { var Id = Int32.Parse(TxtId.Text); //Update할때는 Put var response = await client.DeleteAsync($"api/TodoItems/{Id}"); response.EnsureSuccessStatusCode(); GetData(); TxtId.Text = TxtTitle.Text = string.Empty; CboIsComplete.SelectedIndex = -1; } catch (Newtonsoft.Json.JsonException jEx) { await(this.ShowMessageAsync("error", jEx.Message, MessageDialogStyle.Affirmative, new MetroDialogSettings() { AnimateShow = true, AnimateHide = true })); } catch (HttpRequestException ex) { await(this.ShowMessageAsync("error", ex.Message, MessageDialogStyle.Affirmative, new MetroDialogSettings() { AnimateShow = true, AnimateHide = true })); } } private async void GrdTodoItems_SelectionChanged(object sender, SelectionChangedEventArgs e) { try { var Id = ((TodoItem)GrdTodoItems.SelectedItem).Id; HttpResponseMessage? response = await client.GetAsync($"api/TodoItems/{Id}"); response.EnsureSuccessStatusCode(); var item = await response.Content.ReadAsAsync<TodoItem>(); TxtId.Text = item.Id.ToString(); TxtTitle.Text = item.Title; DtpTodoDate.SelectedDateTime = DateTime.Parse(item.TodoDate); //1인 경우에는 0번을 인덱스를 할당 즉 True이면 콤보박스의 0번째(True)를 할당 , 그 외는 1번(False) CboIsComplete.SelectedIndex = item.IsComplete == 1 ? 0 : 1; } catch (Newtonsoft.Json.JsonException jEx) { await(this.ShowMessageAsync("error", jEx.Message, MessageDialogStyle.Affirmative, new MetroDialogSettings() { AnimateShow = true, AnimateHide = true })); } catch (HttpRequestException ex) { await(this.ShowMessageAsync("error", ex.Message, MessageDialogStyle.Affirmative, new MetroDialogSettings() { AnimateShow = true, AnimateHide = true })); } catch(Exception ex) { //아래 비동기 메시지 주석은 화면에 출력하지 않기 위해 Debug.WriteLine으로 뺀것 //await(this.ShowMessageAsync("error", ex.Message, MessageDialogStyle.Affirmative, new MetroDialogSettings() //{ AnimateShow = true, AnimateHide = true })); Debug.WriteLine($"이외 예외 {ex.Message}"); } } } }
실행화면