todo stage1

main
syneffort 2 years ago
parent 937fbc4bc0
commit ba58c0a803
  1. 2
      MySolution/ToDoApp/Context/ToDoContext.cs
  2. 81
      MySolution/ToDoApp/MainWindow.xaml
  3. 145
      MySolution/ToDoApp/MainWindow.xaml.cs
  4. 105
      MySolution/ToDoApp/Migrations/20231027075930_init.Designer.cs
  5. 84
      MySolution/ToDoApp/Migrations/20231027075930_init.cs
  6. 102
      MySolution/ToDoApp/Migrations/ToDoContextModelSnapshot.cs
  7. 8
      MySolution/ToDoApp/Model/Item.cs
  8. 6
      MySolution/ToDoApp/Model/User.cs
  9. BIN
      MySolution/ToDoApp/Resource/ToDo.png
  10. 22
      MySolution/ToDoApp/Service/DbService.cs
  11. 108
      MySolution/ToDoApp/Service/ItemService.cs
  12. 34
      MySolution/ToDoApp/Service/UserService.cs
  13. 14
      MySolution/ToDoApp/SubControl/PlaceholderTextBox.xaml
  14. 68
      MySolution/ToDoApp/SubControl/PlaceholderTextBox.xaml.cs
  15. 32
      MySolution/ToDoApp/SubControl/ToDoListItem.xaml
  16. 60
      MySolution/ToDoApp/SubControl/ToDoListItem.xaml.cs
  17. 54
      MySolution/ToDoApp/SubWindow/JoinWindow.xaml
  18. 165
      MySolution/ToDoApp/SubWindow/JoinWindow.xaml.cs
  19. 40
      MySolution/ToDoApp/SubWindow/LoginWindow.xaml
  20. 73
      MySolution/ToDoApp/SubWindow/LoginWindow.xaml.cs
  21. BIN
      MySolution/ToDoApp/ToDo.ico
  22. BIN
      MySolution/ToDoApp/ToDo.png
  23. 15
      MySolution/ToDoApp/ToDoApp.csproj
  24. BIN
      Reaources/ToDo.ico
  25. BIN
      Reaources/ToDo.png

@ -18,7 +18,5 @@ namespace ToDoApp.Context
optionsBuilder.UseMySQL(@"Server=peacecloud.synology.me;Port=3307;Database=Study;Uid=study;Pwd=Study1234!;");
base.OnConfiguring(optionsBuilder);
}
}
}

@ -3,10 +3,87 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ToDoApp"
xmlns:local="clr-namespace:ToDoApp" xmlns:subcontrol="clr-namespace:ToDoApp.SubControl"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
Title="To Do" Height="800" Width="1000" WindowStartupLocation="CenterScreen"
Icon="./Resource/ToDo.png">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="250"/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Margin="5" Background="WhiteSmoke">
<Grid.RowDefinitions>
<RowDefinition Height="70"/>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Vertical" Margin="15">
<TextBlock x:Name="tbName" Text="Name" HorizontalAlignment="Left"
FontSize="15" FontWeight="Bold"/>
<TextBlock x:Name="tbEmail" Text="mail@mail.com" HorizontalAlignment="Left"/>
</StackPanel>
<subcontrol:PlaceholderTextBox x:Name="tbxSearch" Grid.Row="1" VerticalAlignment="Center" TPlaceholder="검색" THeight="20"
KeyDown="tbxSearch_KeyDown"/>
<StackPanel Grid.Row="2" Orientation="Vertical">
<Button x:Name="btnToday" Content="☀ 오늘 할 일" Height="30" Margin="5" Background="Transparent" BorderThickness="0" HorizontalContentAlignment="Left"/>
<Button x:Name="btnPlaned" Content="📅 계획된 일정" Height="30" Margin="5" Background="Transparent" BorderThickness="0" HorizontalContentAlignment="Left"/>
<Button x:Name="btnFinished" Content="✅ 완료됨" Height="30" Margin="5" Background="Transparent" BorderThickness="0" HorizontalContentAlignment="Left"/>
<Label Background="Gray" Height="1"/>
<Button x:Name="btnToDo" Content="💡 To Do" Height="30" Margin="5" Background="Transparent" BorderThickness="0" HorizontalContentAlignment="Left"/>
</StackPanel>
</Grid>
<Grid Grid.Column="1" Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
<RowDefinition Height="40"/>
</Grid.RowDefinitions>
<TextBlock x:Name="tbTitle" Grid.Row="0" VerticalAlignment="Center" Text="Title"
FontSize="25" FontWeight="Bold"/>
<ListBox x:Name="lbxContent" Grid.Row="1" HorizontalContentAlignment="Left" BorderThickness="0" Margin="0 10 0 0"
SelectionChanged="lbxContent_SelectionChanged"/>
<subcontrol:PlaceholderTextBox x:Name="tbxNewItemName" Grid.Row="2" VerticalAlignment="Center" TPlaceholder="작업 추가" THeight="20"
KeyDown="tbxNewItem_KeyDown"/>
</Grid>
<Grid Grid.Column="2" Margin="5" Background="WhiteSmoke">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Vertical" Margin="5">
<subcontrol:PlaceholderTextBox x:Name="tbxItemName" VerticalAlignment="Center" TPlaceholder="검색" THeight="40"
TFontWeight="Bold" TFontSize="20"/>
<TextBlock x:Name="tbItemCreatedAt" Text="0000년 00월 00일 0요일 생성됨" Foreground="Gray" TextAlignment="Right"/>
<Button x:Name="btnItemToday" HorizontalContentAlignment="Left" Height="30" Margin="0 10 0 0" Content="나의 하루에 추가" Background="Transparent" BorderThickness="0"/>
<DatePicker x:Name="dpItemDueDate" Margin="0 5 0 0" Background="Transparent"/>
<subcontrol:PlaceholderTextBox x:Name="tbxItemDescription" Margin="0 5 0 0" TPlaceholder="메모" THeight="200" TVerticalAlignment="Top"/>
</StackPanel>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<Button x:Name="btnUpdate" Grid.Column="0" Content="업데이트" Background="Transparent" BorderThickness="0" Margin="3"
Click="btnUpdate_Click"/>
<Button x:Name="btnDelete" Grid.Column="1" Content="🗑" Background="Transparent" BorderThickness="0" Margin="3"
Click="btnDelete_Click"/>
</Grid>
</Grid>
</Grid>
</Window>

@ -1,4 +1,5 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -13,8 +14,10 @@ using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ToDoApp.Context;
using ToDoApp.Controller;
using ToDoApp.Model;
using ToDoApp.Service;
using ToDoApp.SubControl;
using ToDoApp.SubWindow;
namespace ToDoApp
{
@ -23,6 +26,9 @@ namespace ToDoApp
/// </summary>
public partial class MainWindow : Window
{
private User _user;
private Item _selectedItem;
public MainWindow()
{
InitializeComponent();
@ -32,13 +38,28 @@ namespace ToDoApp
MessageBox.Show("데이터베이스가 정상적이지 않아 프로그램을 종료합니다.");
Application.Current.Shutdown();
}
if (CheckLogin() != true)
{
Application.Current.Shutdown();
}
InitInstance();
}
private void InitInstance()
{
tbName.Text = _user.Name;
tbEmail.Text = _user.Email;
RefreshList();
}
private bool CheckDB()
{
try
{
ToDoController.Instance.EnsureCreated();
DbService.Instance.EnsureCreated();
return true;
}
catch (Exception ex)
@ -47,5 +68,123 @@ namespace ToDoApp
}
}
private bool? CheckLogin()
{
try
{
LoginWindow dlg = new LoginWindow();
bool? isOk = dlg.ShowDialog();
_user = dlg.User;
return isOk;
}
catch (Exception ex)
{
return false;
}
}
private void RefreshList()
{
List<Item> items = GetAllItems();
SetToDoList(items);
}
private List<Item> GetAllItems()
{
return ItemService.Instance.FindAllNotCompletedItems(_user.Id);
}
private void SetToDoList(List<Item> items)
{
List<ToDoListItem> list = new List<ToDoListItem>();
foreach (Item item in items)
{
list.Add(new ToDoListItem(item));
}
lbxContent.ItemsSource = list;
}
private void SetSelectedItem(Item item)
{
_selectedItem = item;
tbxItemName.Text = _selectedItem.Title;
tbItemCreatedAt.Text = _selectedItem.CreateDate.ToString("yyyy년 MM월 dd일 ddd 생성됨");
if (_selectedItem.DueDate != null)
dpItemDueDate.SelectedDate = _selectedItem.DueDate;
if (_selectedItem.Description != null)
tbxItemDescription.Text = _selectedItem.Description;
}
private void ClearSelectedItem()
{
_selectedItem = null;
tbxItemName.Text = "";
tbItemCreatedAt.Text = "";
dpItemDueDate.SelectedDate = null;
tbxItemDescription.Text = "";
}
private void tbxNewItemName_KeyDown(object sender, KeyEventArgs e)
{
}
private void tbxSearch_KeyDown(object sender, KeyEventArgs e)
{
}
private void btnUpdate_Click(object sender, RoutedEventArgs e)
{
}
private void btnDelete_Click(object sender, RoutedEventArgs e)
{
if (_selectedItem == null)
return;
ItemService.Instance.RemoveItem(_selectedItem.Id);
ClearSelectedItem();
RefreshList();
}
private void tbxNewItem_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key != Key.Enter)
return;
PlaceholderTextBox textBox = sender as PlaceholderTextBox;
if (textBox == null || string.IsNullOrEmpty(textBox.Text))
return;
Item newItem = new Item()
{
UserId = _user.Id,
Title = textBox.Text,
};
ItemService.Instance.CreateItem(newItem);
textBox.Text = "";
RefreshList();
}
private void lbxContent_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ToDoListItem toDoListItem = lbxContent.SelectedItem as ToDoListItem;
if (toDoListItem == null)
return;
SetSelectedItem(toDoListItem.Item);
}
}
}

@ -0,0 +1,105 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using ToDoApp.Context;
#nullable disable
namespace ToDoApp.Migrations
{
[DbContext(typeof(ToDoContext))]
[Migration("20231027075930_init")]
partial class init
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.13")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("ToDoApp.Model.Item", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("CreateDate")
.HasColumnType("datetime(6)");
b.Property<string>("Description")
.HasColumnType("longtext");
b.Property<DateTime?>("DueDate")
.HasColumnType("datetime(6)");
b.Property<bool?>("IsCompleted")
.HasColumnType("tinyint(1)");
b.Property<bool?>("IsToday")
.HasColumnType("tinyint(1)");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("UserId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("Items");
});
modelBuilder.Entity("ToDoApp.Model.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("CreateDate")
.HasColumnType("datetime(6)");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("varchar(255)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("Status")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("Users");
});
modelBuilder.Entity("ToDoApp.Model.Item", b =>
{
b.HasOne("ToDoApp.Model.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
#pragma warning restore 612, 618
}
}
}

@ -0,0 +1,84 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
using MySql.EntityFrameworkCore.Metadata;
#nullable disable
namespace ToDoApp.Migrations
{
/// <inheritdoc />
public partial class init : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterDatabase()
.Annotation("MySQL:Charset", "utf8mb4");
migrationBuilder.CreateTable(
name: "Users",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySQL:ValueGenerationStrategy", MySQLValueGenerationStrategy.IdentityColumn),
Name = table.Column<string>(type: "varchar(255)", nullable: false),
Password = table.Column<string>(type: "longtext", nullable: false),
Email = table.Column<string>(type: "longtext", nullable: false),
CreateDate = table.Column<DateTime>(type: "datetime(6)", nullable: false),
Status = table.Column<int>(type: "int", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Users", x => x.Id);
})
.Annotation("MySQL:Charset", "utf8mb4");
migrationBuilder.CreateTable(
name: "Items",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySQL:ValueGenerationStrategy", MySQLValueGenerationStrategy.IdentityColumn),
UserId = table.Column<int>(type: "int", nullable: false),
Title = table.Column<string>(type: "longtext", nullable: false),
Description = table.Column<string>(type: "longtext", nullable: true),
DueDate = table.Column<DateTime>(type: "datetime(6)", nullable: true),
IsToday = table.Column<bool>(type: "tinyint(1)", nullable: true),
IsCompleted = table.Column<bool>(type: "tinyint(1)", nullable: true),
CreateDate = table.Column<DateTime>(type: "datetime(6)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Items", x => x.Id);
table.ForeignKey(
name: "FK_Items_Users_UserId",
column: x => x.UserId,
principalTable: "Users",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySQL:Charset", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_Items_UserId",
table: "Items",
column: "UserId");
migrationBuilder.CreateIndex(
name: "IX_Users_Name",
table: "Users",
column: "Name",
unique: true);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Items");
migrationBuilder.DropTable(
name: "Users");
}
}
}

@ -0,0 +1,102 @@
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using ToDoApp.Context;
#nullable disable
namespace ToDoApp.Migrations
{
[DbContext(typeof(ToDoContext))]
partial class ToDoContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "7.0.13")
.HasAnnotation("Relational:MaxIdentifierLength", 64);
modelBuilder.Entity("ToDoApp.Model.Item", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("CreateDate")
.HasColumnType("datetime(6)");
b.Property<string>("Description")
.HasColumnType("longtext");
b.Property<DateTime?>("DueDate")
.HasColumnType("datetime(6)");
b.Property<bool?>("IsCompleted")
.HasColumnType("tinyint(1)");
b.Property<bool?>("IsToday")
.HasColumnType("tinyint(1)");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("UserId")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("Items");
});
modelBuilder.Entity("ToDoApp.Model.User", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("int");
b.Property<DateTime>("CreateDate")
.HasColumnType("datetime(6)");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("longtext");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("varchar(255)");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("longtext");
b.Property<int>("Status")
.HasColumnType("int");
b.HasKey("Id");
b.HasIndex("Name")
.IsUnique();
b.ToTable("Users");
});
modelBuilder.Entity("ToDoApp.Model.Item", b =>
{
b.HasOne("ToDoApp.Model.User", "User")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("User");
});
#pragma warning restore 612, 618
}
}
}

@ -17,11 +17,13 @@ namespace ToDoApp.Model
[Required]
public string Title { get; set; }
public string Description { get; set; }
public string? Description { get; set; }
public DateTime DueDate { get; set; }
public DateTime? DueDate { get; set; }
public bool IsCompleted { get; set; }
public bool? IsToday { get; set; }
public bool? IsCompleted { get; set; }
public DateTime CreateDate { get; set; }

@ -1,4 +1,5 @@
using System;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
@ -13,6 +14,7 @@ namespace ToDoApp.Model
Invalid
}
[Index(nameof(Name), IsUnique = true)]
public class User
{
public int Id { get; set; }
@ -24,7 +26,7 @@ namespace ToDoApp.Model
public string Password { get; set; }
[EmailAddress(ErrorMessage = "Invalid email format")]
public string Email { get; set; }
public string? Email { get; set; }
public DateTime CreateDate { get; set; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ToDoApp.Context;
namespace ToDoApp.Service
{
public class DbService
{
public static DbService Instance { get; set; } = new DbService();
public void EnsureCreated()
{
using (var context = new ToDoContext())
{
context.Database.EnsureCreated();
}
}
}
}

@ -0,0 +1,108 @@
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ToDoApp.Context;
using ToDoApp.Model;
using ToDoApp.Utility;
namespace ToDoApp.Service
{
public class ItemService
{
public static ItemService Instance { get; set; } = new ItemService();
public List<Item> FindAllItems(int userId)
{
using (var context = new ToDoContext())
{
return context.Items.Where(i => i.UserId == userId).ToList();
}
}
public List<Item> FindAllItems(User user)
{
using (var context = new ToDoContext())
{
return context.Items.Include(i => i.User).Where(i => i.User == user).ToList();
}
}
public List<Item> FindAllNotCompletedItems(int userId)
{
using (var context = new ToDoContext())
{
return context.Items.Include(i => i.User).Where(i => i.UserId == userId && i.IsCompleted != false).ToList();
}
}
public List<Item> FindAllNotCompletedItems(User user)
{
using (var context = new ToDoContext())
{
return context.Items.Include(i => i.User).Where(i => i.User == user && i.IsCompleted == false).ToList();
}
}
public Item? FindItem(int itemId)
{
using (var context = new ToDoContext())
{
return context.Items.FirstOrDefault(i => i.Id == itemId);
}
}
public Item? FindItem(Item item)
{
return FindItem(item.Id);
}
public void CreateItem(Item item)
{
using (var context = new ToDoContext())
{
item.CreateDate = DateTime.Now;
context.Items.Add(item);
context.SaveChanges();
}
}
public void UpdateItem(Item item)
{
using (var context = new ToDoContext())
{
Item? original = context.Items.Find(item.Id);
if (original == null)
return;
original.Title = item.Title;
original.Description = item.Description;
original.DueDate = item.DueDate;
original.IsToday = item.IsToday;
original.IsCompleted = item.IsCompleted;
context.SaveChanges();
}
}
public void RemoveItem(int itemId)
{
using (var context = new ToDoContext())
{
Item? item = context.Items.Find(itemId);
if (item == null)
return;
context.Remove(item);
context.SaveChanges();
}
}
public void RemoveItem(Item item)
{
RemoveItem(item.Id);
}
}
}

@ -7,25 +7,17 @@ using ToDoApp.Context;
using ToDoApp.Model;
using ToDoApp.Utility;
namespace ToDoApp.Controller
namespace ToDoApp.Service
{
public class ToDoController
public class UserService
{
public static ToDoController Instance { get; set; } = new ToDoController();
public static UserService Instance { get; set; } = new UserService();
public void EnsureCreated()
public User? FindUser(int userId)
{
using (var context = new ToDoContext())
{
context.Database.EnsureCreated();
}
}
public User? FindUser(int id)
{
using (var context = new ToDoContext())
{
return context.Users.Find(id);
return context.Users.Find(userId);
}
}
@ -37,7 +29,7 @@ namespace ToDoApp.Controller
}
}
public bool LoginCheckUser(string username, string password)
public bool CheckUserLogin(string username, string password)
{
User? user = FindUser(username);
if (user == null)
@ -50,17 +42,18 @@ namespace ToDoApp.Controller
{
using (var context = new ToDoContext())
{
user.Password = Utils.HashPassword(user.Password);
user.CreateDate = DateTime.Now;
context.Users.Add(user);
context.SaveChanges();
}
}
public void DisableUser(int id)
public void DisableUser(int userId)
{
using (var context = new ToDoContext())
{
User? user = context.Users.Find(id);
User? user = context.Users.Find(userId);
if (user == null)
return;
@ -82,11 +75,11 @@ namespace ToDoApp.Controller
}
}
public void RemoveUser(int id)
public void RemoveUser(int userId)
{
using (var context = new ToDoContext())
{
User? user = context.Users.Find(id);
User? user = context.Users.Find(userId);
if (user == null)
return;
@ -107,5 +100,10 @@ namespace ToDoApp.Controller
context.SaveChanges();
}
}
public void RemoveUser(User user)
{
RemoveUser(user.Id);
}
}
}

@ -0,0 +1,14 @@
<UserControl x:Class="ToDoApp.SubControl.PlaceholderTextBox"
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:local="clr-namespace:ToDoApp.SubControl"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="200">
<Grid>
<TextBox x:Name="tbxMain" Background="Transparent" Foreground="Gray" Text="{Binding TPlaceholder}" FontSize="{Binding TFontSize}" FontWeight="{Binding TFontWeight}" Height="{Binding THeight}"
GotFocus="tbxMain_GotFocus" LostFocus="tbxMain_LostFocus"/>
</Grid>
</UserControl>

@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
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;
namespace ToDoApp.SubControl
{
/// <summary>
/// PlaceholderTextBox.xaml에 대한 상호 작용 논리
/// </summary>
public partial class PlaceholderTextBox : UserControl
{
public string TPlaceholder { get; set; } = "";
public int TFontSize { get; set; } = 12;
public FontWeight TFontWeight { get; set; } = FontWeights.Normal;
public int THeight { get; set; } = 20;
public VerticalAlignment TVerticalAlignment { get; set; } = VerticalAlignment.Center;
public PlaceholderTextBox()
{
InitializeComponent();
this.DataContext = this;
}
public string Text
{
get { return tbxMain.Text; }
set { tbxMain.Text = value; }
}
private void tbxMain_GotFocus(object sender, RoutedEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox == null)
return;
if (textBox.Text != this.TPlaceholder)
return;
textBox.Text = "";
textBox.Foreground = Brushes.Black;
}
private void tbxMain_LostFocus(object sender, RoutedEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox == null)
return;
if (!string.IsNullOrEmpty(textBox.Text))
return;
textBox.Text = this.TPlaceholder;
textBox.Foreground = Brushes.Gray;
}
}
}

@ -0,0 +1,32 @@
<UserControl x:Class="ToDoApp.SubControl.ToDoListItem"
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:local="clr-namespace:ToDoApp.SubControl"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.ContextMenu>
<ContextMenu>
<MenuItem x:Name="miToday" Header="오늘 하루에 추가"
Click="miToday_Click"/>
<MenuItem x:Name="miFinish" Header="완료됨으로 표시"
Click="miFinish_Click"/>
<Separator/>
<MenuItem x:Name="miDelete" Header="작업 삭제" Foreground="OrangeRed"
Click="miDelete_Click"/>
</ContextMenu>
</Grid.ContextMenu>
<CheckBox x:Name="ckbFinish" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Checked="ckbFinish_Checked"/>
<TextBlock x:Name="tbItemName" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Text="Item Name"/>
</Grid>
</UserControl>

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
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 ToDoApp.Model;
namespace ToDoApp.SubControl
{
/// <summary>
/// ToDoListItem.xaml에 대한 상호 작용 논리
/// </summary>
public partial class ToDoListItem : UserControl
{
public Item Item { get; set; }
public ToDoListItem(Item item)
{
InitializeComponent();
this.Item = item;
InitInstance();
}
private void InitInstance()
{
tbItemName.Text = this.Item.Title;
ckbFinish.IsChecked = this.Item.IsToday == true ? true : false;
}
private void miToday_Click(object sender, RoutedEventArgs e)
{
}
private void miFinish_Click(object sender, RoutedEventArgs e)
{
}
private void miDelete_Click(object sender, RoutedEventArgs e)
{
}
private void ckbFinish_Checked(object sender, RoutedEventArgs e)
{
}
}
}

@ -0,0 +1,54 @@
<Window x:Class="ToDoApp.SubWindow.JoinWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ToDoApp.SubWindow"
mc:Ignorable="d"
Title="가입" Height="300" Width="300" ResizeMode="NoResize" WindowStyle="ToolWindow" WindowStartupLocation="CenterScreen"
Icon="../Resource/ToDo.png"
Loaded="Window_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="사용자" Width="80" TextAlignment="Center" VerticalAlignment="Center" Margin="5"/>
<TextBox x:Name="tbName" Width="150" VerticalAlignment="Center" Margin="5"
KeyDown="tb_KeyDown"/>
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="비밀번호" Width="80" TextAlignment="Center" VerticalAlignment="Center" Margin="5"/>
<PasswordBox x:Name="pbPassword" Width="150" VerticalAlignment="Center" Margin="5"
PasswordChanged="PasswordChanged"
KeyDown="tb_KeyDown"/>
</StackPanel>
<StackPanel Grid.Row="2" Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="비밀번호 확인" Width="80" TextAlignment="Center" VerticalAlignment="Center" Margin="5"/>
<PasswordBox x:Name="pbVerification" Width="150" VerticalAlignment="Center" Margin="5"
PasswordChanged="PasswordChanged"
KeyDown="tb_KeyDown"/>
</StackPanel>
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="이메일" Width="80" TextAlignment="Center" VerticalAlignment="Center" Margin="5"/>
<TextBox x:Name="tbEmail" Width="150" VerticalAlignment="Center" Margin="5"
TextChanged="tbEmail_TextChanged"
KeyDown="tb_KeyDown"/>
</StackPanel>
<TextBlock x:Name="tbMessage" Grid.Row="4" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Red" Visibility="Collapsed"/>
<Button x:Name="btnJoin" Grid.Row="5" Width="150" HorizontalAlignment="Center" VerticalAlignment="Center"
Content="가입"
Click="btnJoin_Click"/>
</Grid>
</Window>

@ -0,0 +1,165 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Mail;
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.Shapes;
using System.Xml.Linq;
using ToDoApp.Model;
using ToDoApp.Service;
namespace ToDoApp.SubWindow
{
/// <summary>
/// JoinWindow.xaml에 대한 상호 작용 논리
/// </summary>
public partial class JoinWindow : Window
{
public JoinWindow()
{
InitializeComponent();
}
private bool VerifyInfo()
{
if (!CheckName(tbName.Text))
return false;
if (!CheckPassword(pbPassword.Password, pbVerification.Password))
return false;
if (!CheckEmail(tbEmail.Text))
return false;
return true;
}
private bool CheckName(string name)
{
if (string.IsNullOrEmpty(name))
{
tbMessage.Text = "사용자 이름을 입력하세요.";
tbMessage.Visibility = Visibility.Visible;
return false;
}
User? user = UserService.Instance.FindUser(name);
if (user != null)
{
tbMessage.Text = "사용할 수 없는 이름입니다.";
tbMessage.Visibility = Visibility.Visible;
return false;
}
else
{
tbMessage.Visibility = Visibility.Collapsed;
return true;
}
}
private bool CheckPassword(string password, string verification)
{
if (string.IsNullOrEmpty(password) || string.IsNullOrEmpty(verification))
{
tbMessage.Text = "비밀번호를 입력하세요.";
tbMessage.Visibility = Visibility.Visible;
return false;
}
if (password != verification)
{
tbMessage.Text = "비밀번호가 일치하지 않습니다.";
tbMessage.Visibility = Visibility.Visible;
return false;
}
else
{
tbMessage.Visibility = Visibility.Collapsed;
return true;
}
}
private bool CheckEmail(string email)
{
if (string.IsNullOrEmpty(email))
return true;
try
{
MailAddress addr = new MailAddress(email);
if (addr.Address != email)
{
tbMessage.Text = "이메일 형식이 올바르지 않습니다.";
tbMessage.Visibility = Visibility.Visible;
return false;
}
else
{
tbMessage.Visibility = Visibility.Collapsed;
return true;
}
}
catch
{
tbMessage.Text = "이메일 형식이 올바르지 않습니다.";
tbMessage.Visibility = Visibility.Visible;
return false;
}
}
private void btnJoin_Click(object sender, RoutedEventArgs e)
{
if (!VerifyInfo())
{
MessageBox.Show("가입할 수 없습니다.");
return;
}
User user = new User()
{
Name = tbName.Text,
Email = tbEmail.Text,
Password = pbPassword.Password,
CreateDate = DateTime.Now,
Status = UserStatus.Valid
};
UserService.Instance.CreateUser(user);
MessageBox.Show("가입되었습니다.");
this.Close();
}
private void PasswordChanged(object sender, RoutedEventArgs e)
{
CheckPassword(pbPassword.Password, pbVerification.Password);
}
private void tbEmail_TextChanged(object sender, TextChangedEventArgs e)
{
CheckEmail(tbEmail.Text);
}
private void tb_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key != Key.Enter)
return;
btnJoin_Click(this, null);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
tbName.Focus();
}
}
}

@ -0,0 +1,40 @@
<Window x:Class="ToDoApp.SubWindow.LoginWindow"
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ToDoApp.SubWindow"
mc:Ignorable="d"
Title="로그인" Height="180" Width="300" ResizeMode="NoResize" WindowStyle="ToolWindow" WindowStartupLocation="CenterScreen"
Icon="../Resource/ToDo.png"
Loaded="Window_Loaded">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="사용자" Width="80" TextAlignment="Center" VerticalAlignment="Center" Margin="5"/>
<TextBox x:Name="tbName" Width="150" VerticalAlignment="Center" Margin="5"
KeyDown="tb_KeyDown"/>
</StackPanel>
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center">
<TextBlock Text="비밀번호" Width="80" TextAlignment="Center" VerticalAlignment="Center" Margin="5"/>
<PasswordBox Width="150" x:Name="pbPassword" VerticalAlignment="Center" Margin="5"
KeyDown="tb_KeyDown"/>
</StackPanel>
<Button x:Name="btnLogin" Grid.Row="2" Width="150" HorizontalAlignment="Center" VerticalAlignment="Center"
Content="로그인"
Click="btnLogin_Click"/>
<Button x:Name="btnJoin" Grid.Row="3" Width="150" HorizontalAlignment="Center" VerticalAlignment="Center"
Content="가입"
Click="btnJoin_Click"/>
</Grid>
</Window>

@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
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.Shapes;
using ToDoApp.Model;
using ToDoApp.Service;
namespace ToDoApp.SubWindow
{
/// <summary>
/// LoginWindow.xaml에 대한 상호 작용 논리
/// </summary>
public partial class LoginWindow : Window
{
public User User { get; set; }
public LoginWindow()
{
InitializeComponent();
}
private bool CheckLogin(string name, string password)
{
if (!UserService.Instance.CheckUserLogin(name, password))
return false;
else
return true;
}
private void btnLogin_Click(object sender, RoutedEventArgs e)
{
if (!CheckLogin(tbName.Text, pbPassword.Password))
{
MessageBox.Show("로그인 정보가 올바르지 않습니다.");
}
else
{
this.User = UserService.Instance.FindUser(tbName.Text);
this.DialogResult = true;
this.Close();
}
}
private void btnJoin_Click(object sender, RoutedEventArgs e)
{
JoinWindow dlg = new JoinWindow();
dlg.ShowDialog();
}
private void tb_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key != Key.Enter)
return;
btnLogin_Click(this, null);
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
tbName.Focus();
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

@ -5,8 +5,17 @@
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWPF>true</UseWPF>
<ApplicationIcon>ToDo.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<None Remove="Resource\ToDo.png" />
</ItemGroup>
<ItemGroup>
<Content Include="ToDo.ico" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.13" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="7.0.13">
@ -20,4 +29,10 @@
<PackageReference Include="MySql.EntityFrameworkCore" Version="7.0.5" />
</ItemGroup>
<ItemGroup>
<Resource Include="Resource\ToDo.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Resource>
</ItemGroup>
</Project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Loading…
Cancel
Save