[build] 토이 프로젝트 작업 변경
1. .gitignore 파일이 추가되어, 컴파일된 바이너리, 로그, 임시 파일 등이 Git 추적에서 제외되었습니다. 2. WPF의 MVVM 패턴을 따르는 여러 뷰(LoginWindow.xaml, MainWindow.xaml, RegistMemberWindow.xaml), 뷰 모델(LoginWindowViewModel.cs, MainWindowViewModel.cs, RegistMemberWindowViewModel.cs), 그리고 모델(Member.cs)이 추가되었습니다. 3. 리소스 및 스타일 정의를 포함한 XAML 리소스 파일(DefaultTheme.xaml, LightTheme.xaml, Buttons.xaml 등)이 추가되어 UI의 모양과 느낌을 커스터마이즈할 수 있게 되었습니다. 4. 애플리케이션 설정(AppSettings.cs)과 관련된 설정 파일과 로그인 정보(LoginInfo.cs)를 처리하는 코드가 추가되었습니다. 5. 이미지 리소스(bg_login.jpeg, btn_search_001.png, ico_pw.png, ico_user.png)가 추가되어 UI에 사용됩니다. 6. 유틸리티 및 서비스(ResourceExplorer.cs, ViewModelLocator.cs 등)를 처리하는 여러 보조 클래스들이 추가되었습니다.
This commit is contained in:
498
.gitignore
vendored
Normal file
498
.gitignore
vendored
Normal file
@@ -0,0 +1,498 @@
|
|||||||
|
# ---> C++
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Fortran module files
|
||||||
|
*.mod
|
||||||
|
*.smod
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# ---> Node
|
||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Snowpack dependency directory (https://snowpack.dev/)
|
||||||
|
web_modules/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional stylelint cache
|
||||||
|
.stylelintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
.cache
|
||||||
|
.parcel-cache
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
.next
|
||||||
|
out
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# vuepress v2.x temp and cache directory
|
||||||
|
.temp
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# Docusaurus cache and generated files
|
||||||
|
.docusaurus
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
|
# yarn v2
|
||||||
|
.yarn/cache
|
||||||
|
.yarn/unplugged
|
||||||
|
.yarn/build-state.yml
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.pnp.*
|
||||||
|
|
||||||
|
# ---> Java
|
||||||
|
# Compiled class file
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Log file
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# BlueJ files
|
||||||
|
*.ctxt
|
||||||
|
|
||||||
|
# Mobile Tools for Java (J2ME)
|
||||||
|
.mtj.tmp/
|
||||||
|
|
||||||
|
# Package Files #
|
||||||
|
*.jar
|
||||||
|
*.war
|
||||||
|
*.nar
|
||||||
|
*.ear
|
||||||
|
*.zip
|
||||||
|
*.tar.gz
|
||||||
|
*.rar
|
||||||
|
|
||||||
|
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
||||||
|
hs_err_pid*
|
||||||
|
replay_pid*
|
||||||
|
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Oo]bjL/
|
||||||
|
[Ll]og/
|
||||||
|
|
||||||
|
# Visual Studio 2015 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUNIT
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
**/Properties/launchSettings.json
|
||||||
|
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_i.h
|
||||||
|
*_h.h
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.pch
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tlb
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
*.tlog
|
||||||
|
*.metagen
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# JustCode is a .NET coding add-in
|
||||||
|
.JustCode
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/packages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/packages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/packages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Typescript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
.idea/
|
||||||
|
*.sln.iml
|
||||||
|
|
||||||
|
# CodeRush
|
||||||
|
.cr/
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
20
src/WPFEduSolution/WPFBeginner/App.xaml
Normal file
20
src/WPFEduSolution/WPFBeginner/App.xaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<Application x:Class="WPFBeginner.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:service="clr-namespace:WPFBeginner.Services"
|
||||||
|
xmlns:conv="clr-namespace:WPFBeginner.Converters"
|
||||||
|
StartupUri="/Views/MainWindow.xaml">
|
||||||
|
<Application.Resources>
|
||||||
|
<ResourceDictionary>
|
||||||
|
<service:ViewModelLocator x:Key="ViewModelLocator"/>
|
||||||
|
<conv:InverseBoolConverter x:Key="InverseBoolConverter"/>
|
||||||
|
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/Themes/Styles/Buttons.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/Themes/Colors/DefaultTheme.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/Themes/Cultures/ko-KR.xaml" />
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/Resources/Images/DrawingImages.xaml" />
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</Application.Resources>
|
||||||
|
</Application>
|
||||||
109
src/WPFEduSolution/WPFBeginner/App.xaml.cs
Normal file
109
src/WPFEduSolution/WPFBeginner/App.xaml.cs
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Windows;
|
||||||
|
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using WPFBeginner.Configurations;
|
||||||
|
using WPFBeginner.Exceptions;
|
||||||
|
using WPFBeginner.Services;
|
||||||
|
using WPFBeginner.ViewModels;
|
||||||
|
using WPFBeginner.Views;
|
||||||
|
|
||||||
|
namespace WPFBeginner
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for App.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
private readonly static Dictionary<string, ResourceDictionary> _languages = new Dictionary<string, ResourceDictionary>();
|
||||||
|
private static ResourceDictionary _currentLanguage;
|
||||||
|
|
||||||
|
private readonly static Dictionary<string, ResourceDictionary> _themes = new Dictionary<string, ResourceDictionary>();
|
||||||
|
private static ResourceDictionary _currentTheme;
|
||||||
|
|
||||||
|
public static AppSettings Config { get; private set; }
|
||||||
|
|
||||||
|
//[STAThread]
|
||||||
|
//static void Main()
|
||||||
|
//{
|
||||||
|
//try
|
||||||
|
//{
|
||||||
|
// var application = new App();
|
||||||
|
// application.InitializeComponent(); // For resouce load.
|
||||||
|
// application.Run();
|
||||||
|
//}
|
||||||
|
//catch (AlreadyExcutedAppException ex)
|
||||||
|
//{
|
||||||
|
// MessageBox.Show("이미 실행중입니다. 종료 후, 다시 실행해주세요");
|
||||||
|
//}
|
||||||
|
//catch (LoginFailedException ex)
|
||||||
|
//{
|
||||||
|
// // Do not anything;
|
||||||
|
//}
|
||||||
|
//catch (Exception ex)
|
||||||
|
//{
|
||||||
|
// // log
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
|
||||||
|
protected override void OnStartup(StartupEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnStartup(e);
|
||||||
|
|
||||||
|
//Login();
|
||||||
|
InitializeService();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeService()
|
||||||
|
{
|
||||||
|
Config = JsonSerializer.Deserialize<AppSettings>(File.ReadAllText("appsettings.json"));
|
||||||
|
|
||||||
|
_languages.Add("ko-KR", ResourceExplorer.GetLanguageResourceDic("ko-KR"));
|
||||||
|
_languages.Add("en-US", ResourceExplorer.GetLanguageResourceDic("en-US"));
|
||||||
|
SetLanguage(Config.Language);
|
||||||
|
|
||||||
|
_themes.Add("DefaultTheme", ResourceExplorer.GetThemeResourceDic("DefaultTheme"));
|
||||||
|
_themes.Add("LightTheme", ResourceExplorer.GetThemeResourceDic("LightTheme"));
|
||||||
|
SetTheme(Config.Theme);
|
||||||
|
|
||||||
|
Config.LanguageChanged += (s, e) => SetLanguage(e.New);
|
||||||
|
Config.ThemeChanged += (s, e) => SetTheme(e.New);
|
||||||
|
|
||||||
|
Ioc.Default.ConfigureServices(
|
||||||
|
new ServiceCollection()
|
||||||
|
.AddSingleton(new MainWindowViewModel())
|
||||||
|
.BuildServiceProvider());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetTheme(string code)
|
||||||
|
{
|
||||||
|
if (_currentTheme != null)
|
||||||
|
Resources.MergedDictionaries.Remove(_currentTheme);
|
||||||
|
|
||||||
|
_currentTheme = ResourceExplorer.GetThemeResourceDic(code);
|
||||||
|
Resources.MergedDictionaries.Add(_currentTheme);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetLanguage(string code)
|
||||||
|
{
|
||||||
|
if (_currentLanguage != null)
|
||||||
|
Resources.MergedDictionaries.Remove( _currentLanguage );
|
||||||
|
|
||||||
|
_currentLanguage = ResourceExplorer.GetLanguageResourceDic(code);
|
||||||
|
Resources.MergedDictionaries.Add(_currentLanguage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Login()
|
||||||
|
{
|
||||||
|
var login = new LoginWindow();
|
||||||
|
var isSuccess = login.ShowDialog();
|
||||||
|
|
||||||
|
if (isSuccess != true)
|
||||||
|
throw new LoginFailedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
10
src/WPFEduSolution/WPFBeginner/AssemblyInfo.cs
Normal file
10
src/WPFEduSolution/WPFBeginner/AssemblyInfo.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
[assembly: ThemeInfo(
|
||||||
|
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// or application resource dictionaries)
|
||||||
|
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// app, or any theme specific resource dictionaries)
|
||||||
|
)]
|
||||||
277
src/WPFEduSolution/WPFBeginner/Behaviors/WindowBehavior.cs
Normal file
277
src/WPFEduSolution/WPFBeginner/Behaviors/WindowBehavior.cs
Normal file
@@ -0,0 +1,277 @@
|
|||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Windows.Interop;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace WPFBeginner.Behaviors
|
||||||
|
{
|
||||||
|
public class WindowBehavior
|
||||||
|
{
|
||||||
|
#region Win32 imports
|
||||||
|
|
||||||
|
private const int GWL_STYLE = -16;
|
||||||
|
private const int WS_SYSMENU = 0x80000;
|
||||||
|
private const int WS_MAXIMIZEBOX = 0x80000;
|
||||||
|
private const int WS_MINIMIZEBOX = 0x80000;
|
||||||
|
|
||||||
|
[DllImport("user32.dll", SetLastError = true)]
|
||||||
|
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private static readonly Type OwnerType = typeof(WindowBehavior);
|
||||||
|
|
||||||
|
#region HideCloseButton (attached property)
|
||||||
|
|
||||||
|
private static readonly RoutedEventHandler HideCloseButtonWhenLoadedDelegate = (sender, args) => {
|
||||||
|
if (sender is Window == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var w = (Window)sender;
|
||||||
|
HideCloseButton(w);
|
||||||
|
w.Loaded -= HideCloseButtonWhenLoadedDelegate;
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly RoutedEventHandler ShowCloseButtonWhenLoadedDelegate = (sender, args) => {
|
||||||
|
if (sender is Window == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var w = (Window)sender;
|
||||||
|
ShowCloseButton(w);
|
||||||
|
w.Loaded -= ShowCloseButtonWhenLoadedDelegate;
|
||||||
|
};
|
||||||
|
|
||||||
|
public static readonly DependencyProperty HideCloseButtonProperty =
|
||||||
|
DependencyProperty.RegisterAttached("HideCloseButton", typeof(bool), OwnerType,
|
||||||
|
new FrameworkPropertyMetadata(false, new PropertyChangedCallback(HideCloseButtonChangedCallback)));
|
||||||
|
|
||||||
|
[AttachedPropertyBrowsableForType(typeof(Window))]
|
||||||
|
public static bool GetHideCloseButton(Window obj) => (bool)obj.GetValue(HideCloseButtonProperty);
|
||||||
|
|
||||||
|
[AttachedPropertyBrowsableForType(typeof(Window))]
|
||||||
|
public static void SetHideCloseButton(Window obj, bool value) => obj.SetValue(HideCloseButtonProperty, value);
|
||||||
|
|
||||||
|
private static void HideCloseButtonChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var window = d as Window;
|
||||||
|
if (window == null) return;
|
||||||
|
|
||||||
|
var hideCloseButton = (bool)e.NewValue;
|
||||||
|
if (hideCloseButton && !GetIsHiddenCloseButton(window))
|
||||||
|
{
|
||||||
|
if (!window.IsLoaded)
|
||||||
|
window.Loaded += HideCloseButtonWhenLoadedDelegate;
|
||||||
|
else
|
||||||
|
HideCloseButton(window);
|
||||||
|
|
||||||
|
SetIsHiddenCloseButton(window, true);
|
||||||
|
}
|
||||||
|
else if (!hideCloseButton && GetIsHiddenCloseButton(window))
|
||||||
|
{
|
||||||
|
if (!window.IsLoaded)
|
||||||
|
window.Loaded -= ShowCloseButtonWhenLoadedDelegate;
|
||||||
|
else
|
||||||
|
ShowCloseButton(window);
|
||||||
|
|
||||||
|
SetIsHiddenCloseButton(window, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static void HideCloseButton(Window w)
|
||||||
|
{
|
||||||
|
var hwnd = new WindowInteropHelper(w).Handle;
|
||||||
|
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_SYSMENU);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ShowCloseButton(Window w)
|
||||||
|
{
|
||||||
|
var hwnd = new WindowInteropHelper(w).Handle;
|
||||||
|
SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_SYSMENU);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IsHiddenCloseButton (readonly attached property)
|
||||||
|
|
||||||
|
private static readonly DependencyPropertyKey IsHiddenCloseButtonKey =
|
||||||
|
DependencyProperty.RegisterAttachedReadOnly( "IsHiddenCloseButton", typeof(bool), OwnerType, new FrameworkPropertyMetadata(false));
|
||||||
|
|
||||||
|
public static readonly DependencyProperty IsHiddenCloseButtonProperty = IsHiddenCloseButtonKey.DependencyProperty;
|
||||||
|
|
||||||
|
[AttachedPropertyBrowsableForType(typeof(Window))]
|
||||||
|
public static bool GetIsHiddenCloseButton(Window obj) => (bool)obj.GetValue(IsHiddenCloseButtonProperty);
|
||||||
|
|
||||||
|
private static void SetIsHiddenCloseButton(Window obj, bool value) => obj.SetValue(IsHiddenCloseButtonKey, value);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
//#region HideMinimizeButton
|
||||||
|
|
||||||
|
//private static readonly RoutedEventHandler HideMinimizeButtonWhenLoadedDelegate = (sender, args) => {
|
||||||
|
// if (sender is Window == false)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// var w = (Window)sender;
|
||||||
|
// HideMinimizeButton(w);
|
||||||
|
// w.Loaded -= HideMinimizeButtonWhenLoadedDelegate;
|
||||||
|
//};
|
||||||
|
|
||||||
|
//private static readonly RoutedEventHandler ShowMinimizeButtonWhenLoadedDelegate = (sender, args) => {
|
||||||
|
// if (sender is Window == false)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// var w = (Window)sender;
|
||||||
|
// ShowMinimizeButton(w);
|
||||||
|
// w.Loaded -= ShowMinimizeButtonWhenLoadedDelegate;
|
||||||
|
//};
|
||||||
|
|
||||||
|
//public static readonly DependencyProperty HideMinimizeButtonProperty =
|
||||||
|
// DependencyProperty.RegisterAttached("HideMinimizeButton", typeof(bool), OwnerType,
|
||||||
|
// new FrameworkPropertyMetadata(false, new PropertyChangedCallback(HideMinimizeButtonChangedCallback)));
|
||||||
|
|
||||||
|
//[AttachedPropertyBrowsableForType(typeof(Window))]
|
||||||
|
//public static bool GetHideMinimizeButton(Window obj) => (bool)obj.GetValue(HideCloseButtonProperty);
|
||||||
|
|
||||||
|
//[AttachedPropertyBrowsableForType(typeof(Window))]
|
||||||
|
//public static void SetHideMinimizeButton(Window obj, bool value) => obj.SetValue(HideCloseButtonProperty, value);
|
||||||
|
|
||||||
|
//private static void HideMinimizeButtonChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
//{
|
||||||
|
// var window = d as Window;
|
||||||
|
// if (window == null) return;
|
||||||
|
|
||||||
|
// var hideCloseButton = (bool)e.NewValue;
|
||||||
|
// if (hideCloseButton && !GetIsHiddenMinimizeButton(window))
|
||||||
|
// {
|
||||||
|
// if (!window.IsLoaded)
|
||||||
|
// window.Loaded += HideMinimizeButtonWhenLoadedDelegate;
|
||||||
|
// else
|
||||||
|
// HideMinimizeButton(window);
|
||||||
|
|
||||||
|
// SetIsHiddenMinimizeButton(window, true);
|
||||||
|
// }
|
||||||
|
// else if (!hideCloseButton && GetIsHiddenMinimizeButton(window))
|
||||||
|
// {
|
||||||
|
// if (!window.IsLoaded)
|
||||||
|
// window.Loaded -= ShowMinimizeButtonWhenLoadedDelegate;
|
||||||
|
// else
|
||||||
|
// ShowMinimizeButton(window);
|
||||||
|
|
||||||
|
// SetIsHiddenMinimizeButton(window, false);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//private static void HideMinimizeButton(Window w)
|
||||||
|
//{
|
||||||
|
// var hwnd = new WindowInteropHelper(w).Handle;
|
||||||
|
// SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_MINIMIZEBOX);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//private static void ShowMinimizeButton(Window w)
|
||||||
|
//{
|
||||||
|
// var hwnd = new WindowInteropHelper(w).Handle;
|
||||||
|
// SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_MINIMIZEBOX);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region IsHiddenMinimizeButton (readonly attached property)
|
||||||
|
//private static readonly DependencyPropertyKey IsHiddenMinimizeButtonKey =
|
||||||
|
// DependencyProperty.RegisterAttachedReadOnly("IsHiddenMinimizeButton", typeof(bool), OwnerType, new FrameworkPropertyMetadata(false));
|
||||||
|
|
||||||
|
//public static readonly DependencyProperty IsHiddenMinimizeButtonProperty = IsHiddenMinimizeButtonKey.DependencyProperty;
|
||||||
|
|
||||||
|
//[AttachedPropertyBrowsableForType(typeof(Window))]
|
||||||
|
//public static bool GetIsHiddenMinimizeButton(Window obj) => (bool)obj.GetValue(IsHiddenMinimizeButtonProperty);
|
||||||
|
|
||||||
|
//private static void SetIsHiddenMinimizeButton(Window obj, bool value) => obj.SetValue(IsHiddenMinimizeButtonProperty, value);
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region HideMaximizeButton
|
||||||
|
|
||||||
|
//private static readonly RoutedEventHandler HideMaximizeButtonWhenLoadedDelegate = (sender, args) => {
|
||||||
|
// if (sender is Window == false)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// var w = (Window)sender;
|
||||||
|
// HideMaximizeButton(w);
|
||||||
|
// w.Loaded -= HideMaximizeButtonWhenLoadedDelegate;
|
||||||
|
//};
|
||||||
|
|
||||||
|
//private static readonly RoutedEventHandler ShowMaximizeButtonWhenLoadedDelegate = (sender, args) => {
|
||||||
|
// if (sender is Window == false)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// var w = (Window)sender;
|
||||||
|
// ShowMaximizeButton(w);
|
||||||
|
// w.Loaded -= ShowMaximizeButtonWhenLoadedDelegate;
|
||||||
|
//};
|
||||||
|
|
||||||
|
//public static readonly DependencyProperty HideMaximizeButtonProperty =
|
||||||
|
// DependencyProperty.RegisterAttached("HideMaximizeButton", typeof(bool), OwnerType,
|
||||||
|
// new FrameworkPropertyMetadata(false, new PropertyChangedCallback(HideMaximizeButtonChangedCallback)));
|
||||||
|
|
||||||
|
//[AttachedPropertyBrowsableForType(typeof(Window))]
|
||||||
|
//public static bool GetHideMaximizeButton(Window obj) => (bool)obj.GetValue(HideCloseButtonProperty);
|
||||||
|
|
||||||
|
//[AttachedPropertyBrowsableForType(typeof(Window))]
|
||||||
|
//public static void SetHideMaximizeButton(Window obj, bool value) => obj.SetValue(HideCloseButtonProperty, value);
|
||||||
|
|
||||||
|
//private static void HideMaximizeButtonChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
//{
|
||||||
|
// var window = d as Window;
|
||||||
|
// if (window == null) return;
|
||||||
|
|
||||||
|
// var hideCloseButton = (bool)e.NewValue;
|
||||||
|
// if (hideCloseButton && !GetIsHiddenMaximizeButton(window))
|
||||||
|
// {
|
||||||
|
// if (!window.IsLoaded)
|
||||||
|
// window.Loaded += HideMaximizeButtonWhenLoadedDelegate;
|
||||||
|
// else
|
||||||
|
// HideMaximizeButton(window);
|
||||||
|
|
||||||
|
// SetIsHiddenMaximizeButton(window, true);
|
||||||
|
// }
|
||||||
|
// else if (!hideCloseButton && GetIsHiddenMaximizeButton(window))
|
||||||
|
// {
|
||||||
|
// if (!window.IsLoaded)
|
||||||
|
// window.Loaded -= ShowMaximizeButtonWhenLoadedDelegate;
|
||||||
|
// else
|
||||||
|
// ShowMaximizeButton(window);
|
||||||
|
|
||||||
|
// SetIsHiddenMaximizeButton(window, false);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//private static void HideMaximizeButton(Window w)
|
||||||
|
//{
|
||||||
|
// var hwnd = new WindowInteropHelper(w).Handle;
|
||||||
|
// SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) & ~WS_MINIMIZEBOX);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//private static void ShowMaximizeButton(Window w)
|
||||||
|
//{
|
||||||
|
// var hwnd = new WindowInteropHelper(w).Handle;
|
||||||
|
// SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_MINIMIZEBOX);
|
||||||
|
//}
|
||||||
|
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region IsHiddenMaximizeButton (readonly attached property)
|
||||||
|
//private static readonly DependencyPropertyKey IsHiddenMaximizeButtonKey =
|
||||||
|
// DependencyProperty.RegisterAttachedReadOnly("IsHiddenMaximizeButton", typeof(bool), OwnerType, new FrameworkPropertyMetadata(false));
|
||||||
|
|
||||||
|
//public static readonly DependencyProperty IsHiddenMaximizeButtonProperty = IsHiddenMaximizeButtonKey.DependencyProperty;
|
||||||
|
|
||||||
|
//[AttachedPropertyBrowsableForType(typeof(Window))]
|
||||||
|
//public static bool GetIsHiddenMaximizeButton(Window obj) => (bool)obj.GetValue(IsHiddenMaximizeButtonProperty);
|
||||||
|
|
||||||
|
//private static void SetIsHiddenMaximizeButton(Window obj, bool value) => obj.SetValue(IsHiddenMaximizeButtonProperty, value);
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
75
src/WPFEduSolution/WPFBeginner/Configurations/AppSettings.cs
Normal file
75
src/WPFEduSolution/WPFBeginner/Configurations/AppSettings.cs
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using WPFBeginner.Models;
|
||||||
|
|
||||||
|
namespace WPFBeginner.Configurations
|
||||||
|
{
|
||||||
|
public class AppSettings
|
||||||
|
{
|
||||||
|
public EventHandler<StringChangedEventArg> LanguageChanged;
|
||||||
|
public EventHandler<StringChangedEventArg> ThemeChanged;
|
||||||
|
|
||||||
|
[JsonPropertyName("Login")]
|
||||||
|
public LoginInfo Login { get; set;}
|
||||||
|
|
||||||
|
private string language;
|
||||||
|
[JsonPropertyName("Language")]
|
||||||
|
public string Language
|
||||||
|
{
|
||||||
|
get => language;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var eventArg = new StringChangedEventArg()
|
||||||
|
{
|
||||||
|
Old = language,
|
||||||
|
New = value
|
||||||
|
};
|
||||||
|
|
||||||
|
language = value;
|
||||||
|
|
||||||
|
if (eventArg.NotChanged)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LanguageChanged?.Invoke(null, eventArg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string theme;
|
||||||
|
[JsonPropertyName("Theme")]
|
||||||
|
public string Theme
|
||||||
|
{
|
||||||
|
get => theme;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
var eventArg = new StringChangedEventArg()
|
||||||
|
{
|
||||||
|
Old = language,
|
||||||
|
New = value
|
||||||
|
};
|
||||||
|
|
||||||
|
theme = value;
|
||||||
|
|
||||||
|
if (eventArg.NotChanged)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ThemeChanged?.Invoke(null, eventArg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonPropertyName("DefaultMembers")]
|
||||||
|
public List<Member> Members { get; set;}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class StringChangedEventArg : EventArgs
|
||||||
|
{
|
||||||
|
public string Old { get; set; }
|
||||||
|
public string New { get; set; }
|
||||||
|
|
||||||
|
public bool NotChanged => Old?.Equals(New, StringComparison.OrdinalIgnoreCase) ?? true;
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/WPFEduSolution/WPFBeginner/Configurations/LoginInfo.cs
Normal file
12
src/WPFEduSolution/WPFBeginner/Configurations/LoginInfo.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using System.Text.Json.Serialization;
|
||||||
|
|
||||||
|
namespace WPFBeginner.Configurations
|
||||||
|
{
|
||||||
|
public class LoginInfo
|
||||||
|
{
|
||||||
|
[JsonPropertyName("User")]
|
||||||
|
public string User { get; set; }
|
||||||
|
|
||||||
|
public string Password { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
<UserControl x:Class="WPFBeginner.Controls.MemberInputPanel"
|
||||||
|
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:WPFBeginner.Controls"
|
||||||
|
mc:Ignorable="d" Name="root"
|
||||||
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
|
|
||||||
|
<UserControl.Resources>
|
||||||
|
<Style x:Key="LabelTitle" TargetType="Label">
|
||||||
|
<Setter Property="FontSize" Value="12"/>
|
||||||
|
<Setter Property="FontFamily" Value="Yu Gothic UI"/>
|
||||||
|
<Setter Property="FontWeight" Value="Bold"/>
|
||||||
|
<Setter Property="Padding" Value="10 0"/>
|
||||||
|
<Setter Property="HorizontalAlignment" Value="Right"/>
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource Colors.TextBox.Foreground}"/>
|
||||||
|
</Style>
|
||||||
|
<Style x:Key="InputBox" TargetType="TextBox">
|
||||||
|
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||||
|
<Setter Property="VerticalContentAlignment" Value="Center"/>
|
||||||
|
<Setter Property="Padding" Value="5 0"/>
|
||||||
|
<Setter Property="Height" Value="25"/>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource Colors.TextBox.Foreground}"/>
|
||||||
|
<Setter Property="Background" Value="{DynamicResource Colors.TextBox.Background}"/>
|
||||||
|
<Setter Property="BorderBrush" Value="#FF424242"/>
|
||||||
|
</Style>
|
||||||
|
</UserControl.Resources>
|
||||||
|
<Grid >
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Label Grid.Row="0" Style="{StaticResource LabelTitle}" Content="{StaticResource Cultures.MainWindow.Label.Name}"/>
|
||||||
|
<Label Grid.Row="1" Style="{StaticResource LabelTitle}" Content="{StaticResource Cultures.MainWindow.Label.Call}" />
|
||||||
|
<Label Grid.Row="2" Style="{StaticResource LabelTitle}" Content="{StaticResource Cultures.MainWindow.Label.No}"/>
|
||||||
|
<Label Grid.Row="3" Style="{StaticResource LabelTitle}" Content="{StaticResource Cultures.MainWindow.Label.Mail}"/>
|
||||||
|
|
||||||
|
<TextBox Grid.Row="0" Grid.Column="1" Style="{StaticResource InputBox}" Text="{Binding ElementName=root, Path=MemberName}"/>
|
||||||
|
<TextBox Grid.Row="1" Grid.Column="1" Style="{StaticResource InputBox}" Text="{Binding ElementName=root, Path=Call}"/>
|
||||||
|
<TextBox Grid.Row="2" Grid.Column="1" Style="{StaticResource InputBox}" Text="{Binding ElementName=root, Path=EmployeeNo}"/>
|
||||||
|
<TextBox Grid.Row="3" Grid.Column="1" Style="{StaticResource InputBox}" Text="{Binding ElementName=root, Path=Email}"/>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
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 WPFBeginner.Controls
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// MemberInputPanel.xaml에 대한 상호 작용 논리
|
||||||
|
/// </summary>
|
||||||
|
public partial class MemberInputPanel : UserControl
|
||||||
|
{
|
||||||
|
public static readonly DependencyProperty MemberNameProperty =
|
||||||
|
DependencyProperty.Register(nameof(MemberName), typeof(string), typeof(MemberInputPanel), new FrameworkPropertyMetadata(){BindsTwoWayByDefault = true});
|
||||||
|
|
||||||
|
public string MemberName
|
||||||
|
{
|
||||||
|
get => (string)GetValue(MemberNameProperty);
|
||||||
|
set => SetValue(MemberNameProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty EmployeeNoProperty =
|
||||||
|
DependencyProperty.Register(nameof(EmployeeNo), typeof(string), typeof(MemberInputPanel), new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true });
|
||||||
|
|
||||||
|
public string EmployeeNo
|
||||||
|
{
|
||||||
|
get => (string)GetValue(EmployeeNoProperty);
|
||||||
|
set => SetValue(EmployeeNoProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty CallProperty =
|
||||||
|
DependencyProperty.Register(nameof(Call), typeof(string), typeof(MemberInputPanel), new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true });
|
||||||
|
|
||||||
|
public string Call
|
||||||
|
{
|
||||||
|
get => (string)GetValue(CallProperty);
|
||||||
|
set => SetValue(CallProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly DependencyProperty EmailProperty =
|
||||||
|
DependencyProperty.Register(nameof(Email), typeof(string), typeof(MemberInputPanel), new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true });
|
||||||
|
|
||||||
|
public string Email
|
||||||
|
{
|
||||||
|
get => (string)GetValue(EmailProperty);
|
||||||
|
set => SetValue(EmailProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemberInputPanel()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
src/WPFEduSolution/WPFBeginner/Converters/BaseConverter.cs
Normal file
19
src/WPFEduSolution/WPFBeginner/Converters/BaseConverter.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Markup;
|
||||||
|
|
||||||
|
namespace WPFBeginner.Converters
|
||||||
|
{
|
||||||
|
public abstract class BaseConverter : MarkupExtension
|
||||||
|
{
|
||||||
|
protected BaseConverter() { }
|
||||||
|
|
||||||
|
public override object ProvideValue(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using System.Windows.Data;
|
||||||
|
|
||||||
|
namespace WPFBeginner.Converters
|
||||||
|
{
|
||||||
|
[ValueConversion(typeof(bool), typeof(bool))]
|
||||||
|
public class InverseBoolConverter : BaseConverter, IValueConverter
|
||||||
|
{
|
||||||
|
public InverseBoolConverter() { }
|
||||||
|
|
||||||
|
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||||
|
{
|
||||||
|
return !(bool)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
|
||||||
|
{
|
||||||
|
return !(bool)value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WPFBeginner.Exceptions
|
||||||
|
{
|
||||||
|
internal class AlreadyExcutedAppException : Exception
|
||||||
|
{
|
||||||
|
public AlreadyExcutedAppException() : base()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WPFBeginner.Exceptions
|
||||||
|
{
|
||||||
|
internal class LoginFailedException : Exception
|
||||||
|
{
|
||||||
|
public LoginFailedException() : base()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/WPFEduSolution/WPFBeginner/Models/Member.cs
Normal file
32
src/WPFEduSolution/WPFBeginner/Models/Member.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel.DataAnnotations;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace WPFBeginner.Models
|
||||||
|
{
|
||||||
|
public class Member
|
||||||
|
{
|
||||||
|
[JsonPropertyName("Name")]
|
||||||
|
public string Name { get; set; }
|
||||||
|
[JsonPropertyName("Call")]
|
||||||
|
public string Call { get; set; }
|
||||||
|
[JsonPropertyName("EMail")]
|
||||||
|
public string EMail { get; set; }
|
||||||
|
[JsonPropertyName("No")]
|
||||||
|
public string EmployeeNo { get; set; }
|
||||||
|
|
||||||
|
public static Member Create(string name, string call, string email, string employeeNo)
|
||||||
|
{
|
||||||
|
return new Member()
|
||||||
|
{
|
||||||
|
Name = name,
|
||||||
|
Call = call,
|
||||||
|
EMail = email,
|
||||||
|
EmployeeNo = employeeNo };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
|
<DrawingImage x:Key="Images.OptionsMenu.Setting.Normal">
|
||||||
|
<DrawingImage.Drawing>
|
||||||
|
<DrawingGroup ClipGeometry="M0,0 V24 H24 V0 H0 Z">
|
||||||
|
<GeometryDrawing Brush="{DynamicResource Colors.Images.OptionsMenu.Setting.Normal}" Geometry="F0 M24,24z M0,0z M10.1,1.3L10.1,1.1 12.7,1.1 12.7,1.3 13,2.6 13.2,3.7C14.2,3.9,15.1,4.3,15.9,4.8L16,4.8 17.7,3.5 17.8,3.4 18.1,3.4 18.9,4.2 19.7,5 19.7,5.3 19.6,5.4 19,6.2 18.4,7.1C18.9,7.9,19.3,8.8,19.6,9.8L19.6,9.9 20.5,10 20.7,10 21.7,10.2 21.9,10.2 21.9,12.8 21.7,12.8 20.7,13 19.6,13.2C19.4,14.2,19,15.1,18.5,15.9L19.8,17.6C19.8,17.6,19.8,17.7,19.9,17.7L19.9,18 19.1,18.8 18.3,19.6 18,19.6 17.9,19.5 16,18.4C15.2,18.9,14.2,19.3,13.3,19.5L13.3,19.6 13,21.7 13,21.9 10.4,21.9 10.4,21.7 10.2,20.5 10,19.4C9.1,19.2,8.2,18.8,7.4,18.3L7,18.4 5.3,19.7 5.2,19.8 4.9,19.8 4.1,19 3.3,18.2 3.3,17.9 3.4,17.8 4.2,16.7 4.6,16 4.8,15.7C4.4,15,4,14.2,3.8,13.3L3.4,13.2 1.4,12.9 1.2,12.9 1.2,10.3 1.4,10.3 3.5,9.99999999999999 3.8,9.9C4,8.99999999999999,4.3,8.2,4.8,7.4L4.1,6.4 3.3,5.4 3.2,5.3 3.2,5 4,4.1 4.8,3.3 5.1,3.3 5.2,3.4 7,4.7 7.2,4.9C8,4.3,8.8,3.9,9.8,3.7L10,2.6 10.1,1.3z M13.9,1.3L14.1,2.8C14.7,3,15.3,3.2,15.8,3.5L17,2.6C17.1,2.5 17.4,2.3 17.7,2.2 18,2.1 18.4,2.2 18.8,2.5L19.6,3.3 20.4,4.1C20.7,4.4 20.8,4.8 20.7,5.2 20.6,5.5 20.5,5.7 20.3,5.9L19.5,7C19.8,7.6,20.1,8.2,20.3,8.8L21.7,9C21.9,9 22.2,9.1 22.4,9.2 22.7,9.4 22.9,9.7 22.9,10.2L22.9,12.6C22.9,13.1 22.7,13.4 22.4,13.6 22.2,13.8 21.9,13.8 21.7,13.8L20.3,14C20.1,14.6,19.9,15.2,19.6,15.7L20.4,16.8C20.5,16.9 20.7,17.2 20.8,17.5 20.9,17.8 20.8,18.2 20.5,18.6L19.7,19.4 18.9,20.2C18.6,20.5 18.2,20.6 17.8,20.5 17.5,20.4 17.3,20.3 17.1,20.1L15.9,19.2C15.3,19.5,14.7,19.7,14.1,19.9L13.9,21.4C13.9,21.6 13.8,21.9 13.7,22.1 13.5,22.4 13.2,22.6 12.7,22.6L10.3,22.6C9.8,22.6 9.5,22.4 9.3,22.1 9.1,21.9 9.1,21.6 9.1,21.4L8.9,19.8C8.3,19.6,7.8,19.4,7.2,19.1L5.9,20.1C5.8,20.2 5.5,20.4 5.2,20.5 4.9,20.6 4.5,20.5 4.1,20.2L3.3,19.4 2.5,18.6C2.2,18.3 2.1,17.9 2.2,17.5 2.3,17.2 2.4,17 2.6,16.8L3.6,15.4C3.4,14.9,3.2,14.5,3,14L1.2,14C1,14 0.7,13.9 0.5,13.8 0.2,13.6 0,13.3 0,12.8L0,10.4C0,9.9 0.2,9.6 0.5,9.4 0.8,9.2 1,9.2 1.2,9.2L3,8.9 3.6,7.4 2.5,6C2.4,5.8 2.2,5.6 2.2,5.3 2.1,5 2.2,4.6 2.5,4.2L3.3,3.4 4.1,2.6C4.4,2.3 4.8,2.2 5.2,2.3 5.5,2.4 5.7,2.5 5.9,2.7L7.2,3.7C7.7,3.4,8.2,3.2,8.8,3L9,1.4C9,1.2 9.1,0.9 9.2,0.7 9.5,0.3 9.8,0 10.3,0L12.7,0C13.2,0 13.5,0.2 13.7,0.5 13.8,0.8 13.9,1.1 13.9,1.3z" />
|
||||||
|
<GeometryDrawing>
|
||||||
|
<GeometryDrawing.Pen>
|
||||||
|
<Pen Brush="{DynamicResource Colors.Images.OptionsMenu.Setting.Normal}" Thickness="1" StartLineCap="Flat" EndLineCap="Flat" LineJoin="Miter" />
|
||||||
|
</GeometryDrawing.Pen>
|
||||||
|
<GeometryDrawing.Geometry>
|
||||||
|
<EllipseGeometry RadiusX="3.4" RadiusY="3.4" Center="11.5,11.5" />
|
||||||
|
</GeometryDrawing.Geometry>
|
||||||
|
</GeometryDrawing>
|
||||||
|
</DrawingGroup>
|
||||||
|
</DrawingImage.Drawing>
|
||||||
|
</DrawingImage>
|
||||||
|
|
||||||
|
<DrawingImage x:Key="Images.OptionsMenu.Setting.Pressed">
|
||||||
|
<DrawingImage.Drawing>
|
||||||
|
<DrawingGroup ClipGeometry="M0,0 V24 H24 V0 H0 Z">
|
||||||
|
<GeometryDrawing Brush="{DynamicResource Colors.Images.OptionsMenu.Setting.Pressed}" Geometry="F0 M24,24z M0,0z M10.1,1.3L10.1,1.1 12.7,1.1 12.7,1.3 13,2.6 13.2,3.7C14.2,3.9,15.1,4.3,15.9,4.8L16,4.8 17.7,3.5 17.8,3.4 18.1,3.4 18.9,4.2 19.7,5 19.7,5.3 19.6,5.4 19,6.2 18.4,7.1C18.9,7.9,19.3,8.8,19.6,9.8L19.6,9.9 20.5,10 20.7,10 21.7,10.2 21.9,10.2 21.9,12.8 21.7,12.8 20.7,13 19.6,13.2C19.4,14.2,19,15.1,18.5,15.9L19.8,17.6C19.8,17.6,19.8,17.7,19.9,17.7L19.9,18 19.1,18.8 18.3,19.6 18,19.6 17.9,19.5 16,18.4C15.2,18.9,14.2,19.3,13.3,19.5L13.3,19.6 13,21.7 13,21.9 10.4,21.9 10.4,21.7 10.2,20.5 10,19.4C9.1,19.2,8.2,18.8,7.4,18.3L7,18.4 5.3,19.7 5.2,19.8 4.9,19.8 4.1,19 3.3,18.2 3.3,17.9 3.4,17.8 4.2,16.7 4.6,16 4.8,15.7C4.4,15,4,14.2,3.8,13.3L3.4,13.2 1.4,12.9 1.2,12.9 1.2,10.3 1.4,10.3 3.5,9.99999999999999 3.8,9.9C4,8.99999999999999,4.3,8.2,4.8,7.4L4.1,6.4 3.3,5.4 3.2,5.3 3.2,5 4,4.1 4.8,3.3 5.1,3.3 5.2,3.4 7,4.7 7.2,4.9C8,4.3,8.8,3.9,9.8,3.7L10,2.6 10.1,1.3z M13.9,1.3L14.1,2.8C14.7,3,15.3,3.2,15.8,3.5L17,2.6C17.1,2.5 17.4,2.3 17.7,2.2 18,2.1 18.4,2.2 18.8,2.5L19.6,3.3 20.4,4.1C20.7,4.4 20.8,4.8 20.7,5.2 20.6,5.5 20.5,5.7 20.3,5.9L19.5,7C19.8,7.6,20.1,8.2,20.3,8.8L21.7,9C21.9,9 22.2,9.1 22.4,9.2 22.7,9.4 22.9,9.7 22.9,10.2L22.9,12.6C22.9,13.1 22.7,13.4 22.4,13.6 22.2,13.8 21.9,13.8 21.7,13.8L20.3,14C20.1,14.6,19.9,15.2,19.6,15.7L20.4,16.8C20.5,16.9 20.7,17.2 20.8,17.5 20.9,17.8 20.8,18.2 20.5,18.6L19.7,19.4 18.9,20.2C18.6,20.5 18.2,20.6 17.8,20.5 17.5,20.4 17.3,20.3 17.1,20.1L15.9,19.2C15.3,19.5,14.7,19.7,14.1,19.9L13.9,21.4C13.9,21.6 13.8,21.9 13.7,22.1 13.5,22.4 13.2,22.6 12.7,22.6L10.3,22.6C9.8,22.6 9.5,22.4 9.3,22.1 9.1,21.9 9.1,21.6 9.1,21.4L8.9,19.8C8.3,19.6,7.8,19.4,7.2,19.1L5.9,20.1C5.8,20.2 5.5,20.4 5.2,20.5 4.9,20.6 4.5,20.5 4.1,20.2L3.3,19.4 2.5,18.6C2.2,18.3 2.1,17.9 2.2,17.5 2.3,17.2 2.4,17 2.6,16.8L3.6,15.4C3.4,14.9,3.2,14.5,3,14L1.2,14C1,14 0.7,13.9 0.5,13.8 0.2,13.6 0,13.3 0,12.8L0,10.4C0,9.9 0.2,9.6 0.5,9.4 0.8,9.2 1,9.2 1.2,9.2L3,8.9 3.6,7.4 2.5,6C2.4,5.8 2.2,5.6 2.2,5.3 2.1,5 2.2,4.6 2.5,4.2L3.3,3.4 4.1,2.6C4.4,2.3 4.8,2.2 5.2,2.3 5.5,2.4 5.7,2.5 5.9,2.7L7.2,3.7C7.7,3.4,8.2,3.2,8.8,3L9,1.4C9,1.2 9.1,0.9 9.2,0.7 9.5,0.3 9.8,0 10.3,0L12.7,0C13.2,0 13.5,0.2 13.7,0.5 13.8,0.8 13.9,1.1 13.9,1.3z" />
|
||||||
|
<GeometryDrawing>
|
||||||
|
<GeometryDrawing.Pen>
|
||||||
|
<Pen Brush="{DynamicResource Colors.Images.OptionsMenu.Setting.Pressed}" Thickness="1" StartLineCap="Flat" EndLineCap="Flat" LineJoin="Miter" />
|
||||||
|
</GeometryDrawing.Pen>
|
||||||
|
<GeometryDrawing.Geometry>
|
||||||
|
<EllipseGeometry RadiusX="3.4" RadiusY="3.4" Center="11.5,11.5" />
|
||||||
|
</GeometryDrawing.Geometry>
|
||||||
|
</GeometryDrawing>
|
||||||
|
</DrawingGroup>
|
||||||
|
</DrawingImage.Drawing>
|
||||||
|
</DrawingImage>
|
||||||
|
|
||||||
|
</ResourceDictionary>
|
||||||
BIN
src/WPFEduSolution/WPFBeginner/Resources/Images/bg_login.jpeg
Normal file
BIN
src/WPFEduSolution/WPFBeginner/Resources/Images/bg_login.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
BIN
src/WPFEduSolution/WPFBeginner/Resources/Images/ico_pw.png
Normal file
BIN
src/WPFEduSolution/WPFBeginner/Resources/Images/ico_pw.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 19 KiB |
BIN
src/WPFEduSolution/WPFBeginner/Resources/Images/ico_user.png
Normal file
BIN
src/WPFEduSolution/WPFBeginner/Resources/Images/ico_user.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
@@ -0,0 +1,48 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace WPFBeginner.Resources
|
||||||
|
{
|
||||||
|
public class SharedResourceDictionary : ResourceDictionary
|
||||||
|
{
|
||||||
|
private static Dictionary<Uri, WeakReference> _cache = new Dictionary<Uri, WeakReference>();
|
||||||
|
|
||||||
|
private Uri source;
|
||||||
|
|
||||||
|
public new Uri Source
|
||||||
|
{
|
||||||
|
get => source;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
source = value;
|
||||||
|
if (!_cache.ContainsKey(source))
|
||||||
|
{
|
||||||
|
AddToCache();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WeakReference weakReference = _cache[source];
|
||||||
|
if (weakReference != null && weakReference.IsAlive)
|
||||||
|
MergedDictionaries.Add((ResourceDictionary)weakReference.Target);
|
||||||
|
else
|
||||||
|
AddToCache();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddToCache()
|
||||||
|
{
|
||||||
|
base.Source = source;
|
||||||
|
if (_cache.ContainsKey(source))
|
||||||
|
_cache.Remove(source);
|
||||||
|
|
||||||
|
_cache.Add(source, new WeakReference(this, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace WPFBeginner.Services
|
||||||
|
{
|
||||||
|
public class EnterKeyTraversal
|
||||||
|
{
|
||||||
|
public static readonly DependencyProperty IsEnabledProperty =
|
||||||
|
DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(EnterKeyTraversal), new UIPropertyMetadata(false, IsEnabledChanged));
|
||||||
|
|
||||||
|
public static bool GetIsEnabled(DependencyObject obj) => (bool)obj.GetValue(IsEnabledProperty);
|
||||||
|
|
||||||
|
public static void SetIsEnabled(DependencyObject obj, bool value) => obj.SetValue(IsEnabledProperty, value);
|
||||||
|
|
||||||
|
static void PreviewKeyDown(object sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
var uiElement = e.OriginalSource as FrameworkElement;
|
||||||
|
|
||||||
|
if (e.Key == Key.Enter)
|
||||||
|
{
|
||||||
|
e.Handled = true;
|
||||||
|
uiElement.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Unloaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var uiElement = sender as FrameworkElement;
|
||||||
|
if (uiElement == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uiElement.Unloaded -= Unloaded;
|
||||||
|
uiElement.PreviewKeyDown -= PreviewKeyDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var ue = d as FrameworkElement;
|
||||||
|
if (ue == null) return;
|
||||||
|
|
||||||
|
if ((bool)e.NewValue)
|
||||||
|
{
|
||||||
|
ue.Unloaded += Unloaded;
|
||||||
|
ue.PreviewKeyDown += PreviewKeyDown;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ue.PreviewKeyDown -= PreviewKeyDown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace WPFBeginner.Services
|
||||||
|
{
|
||||||
|
public static class PasswordBoxAssistant
|
||||||
|
{
|
||||||
|
#region BoundPassword Property
|
||||||
|
|
||||||
|
public static readonly DependencyProperty BoundPassword =
|
||||||
|
DependencyProperty.RegisterAttached(nameof(BoundPassword), typeof(string), typeof(PasswordBoxAssistant), new PropertyMetadata(string.Empty, OnBoundPasswordChanged));
|
||||||
|
|
||||||
|
public static string GetBoundPassword(DependencyObject dp) => (string)dp.GetValue(BoundPassword);
|
||||||
|
|
||||||
|
public static void SetBoundPassword(DependencyObject dp, string value) => dp.SetValue(BoundPassword, value);
|
||||||
|
|
||||||
|
private static void OnBoundPasswordChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var box = d as PasswordBox;
|
||||||
|
|
||||||
|
// only handle this event when the property is attached to a PasswordBox
|
||||||
|
// and when the BindPassword attached property has been set to true
|
||||||
|
if (d == null || !GetEnableBindingPassword(d))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// avoid recursive updating by ignoring the box's changed event
|
||||||
|
box.PasswordChanged -= HandlePasswordChanged;
|
||||||
|
|
||||||
|
string newPassword = (string)e.NewValue;
|
||||||
|
|
||||||
|
if (!GetUpdatingPassword(box))
|
||||||
|
box.Password = newPassword;
|
||||||
|
|
||||||
|
box.PasswordChanged += HandlePasswordChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region EnableBindingPassword
|
||||||
|
|
||||||
|
public static readonly DependencyProperty EnableBindingPassword =
|
||||||
|
DependencyProperty.RegisterAttached(nameof(EnableBindingPassword), typeof(bool), typeof(PasswordBoxAssistant), new PropertyMetadata(false, OnEnableBindingPasswordChanged));
|
||||||
|
|
||||||
|
public static bool GetEnableBindingPassword(DependencyObject dp) => (bool)dp.GetValue(EnableBindingPassword);
|
||||||
|
|
||||||
|
public static void SetEnableBindingPassword(DependencyObject dp, bool value) => dp.SetValue(EnableBindingPassword, value);
|
||||||
|
|
||||||
|
private static void OnEnableBindingPasswordChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
// when the BindPassword attached property is set on a PasswordBox,
|
||||||
|
// start listening to its PasswordChanged event
|
||||||
|
|
||||||
|
var box = dp as PasswordBox;
|
||||||
|
|
||||||
|
if (box == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool wasBound = (bool)(e.OldValue);
|
||||||
|
bool needToBind = (bool)(e.NewValue);
|
||||||
|
|
||||||
|
if (wasBound)
|
||||||
|
box.PasswordChanged -= HandlePasswordChanged;
|
||||||
|
|
||||||
|
if (needToBind)
|
||||||
|
box.PasswordChanged += HandlePasswordChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region UpdatingPassword
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private static readonly DependencyProperty UpdatingPassword =
|
||||||
|
DependencyProperty.RegisterAttached(nameof(UpdatingPassword), typeof(bool), typeof(PasswordBoxAssistant), new PropertyMetadata(false));
|
||||||
|
|
||||||
|
private static bool GetUpdatingPassword(DependencyObject dp) => (bool)dp.GetValue(UpdatingPassword);
|
||||||
|
|
||||||
|
private static void SetUpdatingPassword(DependencyObject dp, bool value) => dp.SetValue(UpdatingPassword, value);
|
||||||
|
|
||||||
|
private static void HandlePasswordChanged(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var box = sender as PasswordBox;
|
||||||
|
|
||||||
|
// set a flag to indicate that we're updating the password
|
||||||
|
SetUpdatingPassword(box, true);
|
||||||
|
// push the new password into the BoundPassword property
|
||||||
|
SetBoundPassword(box, box.Password);
|
||||||
|
SetUpdatingPassword(box, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
62
src/WPFEduSolution/WPFBeginner/Services/ResourceExplorer.cs
Normal file
62
src/WPFEduSolution/WPFBeginner/Services/ResourceExplorer.cs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace WPFBeginner.Services
|
||||||
|
{
|
||||||
|
internal static class ResourceExplorer
|
||||||
|
{
|
||||||
|
public static string GetStringResource(string key)
|
||||||
|
{
|
||||||
|
var cultureCode = App.Config.Language;
|
||||||
|
var rd = App.Current.Resources.MergedDictionaries.FirstOrDefault(i => i.Source.AbsolutePath.EndsWith($"{cultureCode}.xaml"));
|
||||||
|
if (rd == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return rd[key] as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ChangeXamlResource(string oldRes, string newRes)
|
||||||
|
{
|
||||||
|
var found = App.Current.Resources.MergedDictionaries.Select((item, i) => new { Item = item, Index = i}).FirstOrDefault(i => i.Item.Source.AbsoluteUri.Equals($"{oldRes}", StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (found == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var newResource = new ResourceDictionary()
|
||||||
|
{
|
||||||
|
Source = new Uri(newRes, UriKind.RelativeOrAbsolute)
|
||||||
|
};
|
||||||
|
App.Current.Resources.MergedDictionaries.Remove(found.Item);
|
||||||
|
App.Current.Resources.MergedDictionaries.Add(newResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ResourceDictionary GetLanguageResourceDic(string name)
|
||||||
|
{
|
||||||
|
var foundName = $"pack://application:,,,/Themes/Cultures/{name}.xaml";
|
||||||
|
//var foundName = $"/WPFBeginner;component/Themes/Cultures/{name}.xaml";
|
||||||
|
var found = App.Current.Resources.MergedDictionaries.Select((item, i) => new { Item = item, Index = i }).FirstOrDefault(i => i.Item.Source.AbsoluteUri.Equals(foundName, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (found == null)
|
||||||
|
return new ResourceDictionary() { Source = new Uri(foundName, UriKind.RelativeOrAbsolute) };
|
||||||
|
|
||||||
|
return found.Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ResourceDictionary GetThemeResourceDic(string name)
|
||||||
|
{
|
||||||
|
var foundName = $"pack://application:,,,/Themes/Colors/{name}.xaml";
|
||||||
|
//var foundName = $"/WPFBeginner;component/Themes/Colors/{name}.xaml";
|
||||||
|
var found = App.Current.Resources.MergedDictionaries.Select((item, i) => new { Item = item, Index = i }).FirstOrDefault(i => i.Item.Source.AbsoluteUri.Equals(foundName, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (found == null)
|
||||||
|
return new ResourceDictionary(){ Source = new Uri(foundName, UriKind.RelativeOrAbsolute) };
|
||||||
|
|
||||||
|
return found.Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
15
src/WPFEduSolution/WPFBeginner/Services/ViewModelLocator.cs
Normal file
15
src/WPFEduSolution/WPFBeginner/Services/ViewModelLocator.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using CommunityToolkit.Mvvm.DependencyInjection;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using WPFBeginner.ViewModels;
|
||||||
|
|
||||||
|
namespace WPFBeginner.Services
|
||||||
|
{
|
||||||
|
internal class ViewModelLocator
|
||||||
|
{
|
||||||
|
public MainWindowViewModel MainWindowViewModel => Ioc.Default.GetService<MainWindowViewModel>();
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/WPFEduSolution/WPFBeginner/Spec.txt
Normal file
8
src/WPFEduSolution/WPFBeginner/Spec.txt
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
## 요구사항
|
||||||
|
|
||||||
|
1. 프로그램 중복실행 방지
|
||||||
|
2. 로그인 화면
|
||||||
|
- 파일로부터 데이터 읽어와 비교
|
||||||
|
3.
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
|
<SolidColorBrush x:Key="Colors.TitleBar.Title.Background" Color="#FF1E1E1E"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.TitleBar.Title.Foreground" Color="LightGreen"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.Section.HorizontalSeperator" Color="Cyan" Opacity="0.8"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.Main.Background" Color="#FF1E1E1E" />
|
||||||
|
<SolidColorBrush x:Key="Colors.SettingPopup.Background" Color="#FF383838" />
|
||||||
|
<SolidColorBrush x:Key="Colors.SettingPopup.BorderBrush" Color="#FF424242" />
|
||||||
|
<SolidColorBrush x:Key="Colors.SettingPopup.Foreground" Color="White" />
|
||||||
|
<SolidColorBrush x:Key="Colors.TextBox.Background" Color="#FF383838"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.TextBox.Foreground" Color="White"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.TextBox.BorderBrush" Color="#FF424242"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.Foreground.Normal" Color="White"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.Foreground.MouseOver" Color="Pink"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.Foreground.MousePressed" Color="Coral"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.BorderBrush.Normal" Color="#FF1F1F1F"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.BorderBrush.MouseOver" Color="Pink"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.BorderBrush.MousePressed" Color="Coral"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.Background.Normal" Color="#FF1F1F1F"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.Background.MouseOver" Color="#FF1F1F1F"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.Background.MousePressed" Color="#FF1F1F1F"/>
|
||||||
|
|
||||||
|
<LinearGradientBrush x:Key="Colors.DataGridButton.Background.Normal" StartPoint="0,0" EndPoint="0,1">
|
||||||
|
<GradientStop Color="#38301f" Offset="0.0"/>
|
||||||
|
<GradientStop Color="#4a3c2b" Offset="0.5"/>
|
||||||
|
<GradientStop Color="#342e1d" Offset="0.5"/>
|
||||||
|
<GradientStop Color="#342e1d" Offset="1.0"/>
|
||||||
|
</LinearGradientBrush>
|
||||||
|
|
||||||
|
<SolidColorBrush x:Key="Colors.DataGridButton.Foreground.Normal" Color="White" />
|
||||||
|
<!--<SolidColorBrush x:Key="Colors.DataGridButton.Background.MouseOver" Color="#FFEB530C" Opacity="0.6" />-->
|
||||||
|
<LinearGradientBrush x:Key="Colors.DataGridButton.Background.MouseOver" StartPoint="0,0" EndPoint="0,1" Opacity="0.6">
|
||||||
|
<GradientStop Color="#38301f" Offset="0.0"/>
|
||||||
|
<GradientStop Color="#4a3c2b" Offset="0.5"/>
|
||||||
|
<GradientStop Color="#342e1d" Offset="0.5"/>
|
||||||
|
<GradientStop Color="#342e1d" Offset="1.0"/>
|
||||||
|
</LinearGradientBrush>
|
||||||
|
<SolidColorBrush x:Key="Colors.DataGridButton.Foreground.MouseOver" Color="Yellow" />
|
||||||
|
<LinearGradientBrush x:Key="Colors.DataGridButton.Background.Pressed" StartPoint="0,0" EndPoint="0,1" Opacity="0.8">
|
||||||
|
<GradientStop Color="#38301f" Offset="0.0"/>
|
||||||
|
<GradientStop Color="#4a3c2b" Offset="0.5"/>
|
||||||
|
<GradientStop Color="#342e1d" Offset="0.5"/>
|
||||||
|
<GradientStop Color="#342e1d" Offset="1.0"/>
|
||||||
|
</LinearGradientBrush>
|
||||||
|
<!--<SolidColorBrush x:Key="Colors.DataGridButton.Background.Pressed" Color="#FFEB530C" Opacity="0.8" />-->
|
||||||
|
<SolidColorBrush x:Key="Colors.DataGridButton.Foreground.Pressed" Color="LightSkyBlue" />
|
||||||
|
|
||||||
|
<SolidColorBrush x:Key="Colors.Images.OptionsMenu.Setting.Normal" Color="#FFB8B8B9"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.Images.OptionsMenu.Setting.Pressed" Color="#FFB8B8B9" Opacity="0.6"/>
|
||||||
|
|
||||||
|
<SolidColorBrush x:Key="Colors.Images.OptionsMenu.Setting.Background.MouseOver" Color="#FF474D51"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.Images.OptionsMenu.Setting.Background.MousePressed" Color="#FF474D51"/>
|
||||||
|
|
||||||
|
</ResourceDictionary>
|
||||||
52
src/WPFEduSolution/WPFBeginner/Themes/Colors/LightTheme.xaml
Normal file
52
src/WPFEduSolution/WPFBeginner/Themes/Colors/LightTheme.xaml
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
|
<SolidColorBrush x:Key="Colors.TitleBar.Title.Background" Color="#FFF0F0F0"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.TitleBar.Title.Foreground" Color="DarkSlateBlue"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.Section.HorizontalSeperator" Color="Gray" Opacity="0.8"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.Main.Background" Color="#FFF0F0F0" />
|
||||||
|
<SolidColorBrush x:Key="Colors.SettingPopup.Background" Color="#FFF5F5F5" />
|
||||||
|
<SolidColorBrush x:Key="Colors.SettingPopup.BorderBrush" Color="#FFDDDDDD" />
|
||||||
|
<SolidColorBrush x:Key="Colors.SettingPopup.Foreground" Color="Black" />
|
||||||
|
<SolidColorBrush x:Key="Colors.TextBox.Background" Color="#FFF5F5F5"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.TextBox.Foreground" Color="Black"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.TextBox.BorderBrush" Color="#FFDDDDDD"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.Foreground.Normal" Color="Black"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.Foreground.MouseOver" Color="MediumSlateBlue"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.Foreground.MousePressed" Color="SlateBlue"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.BorderBrush.Normal" Color="#FFEEEEEE"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.BorderBrush.MouseOver" Color="MediumSlateBlue"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.BorderBrush.MousePressed" Color="SlateBlue"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.Background.Normal" Color="#FFEEEEEE"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.Background.MouseOver" Color="#FFE0E0E0"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.SearchButton.Background.MousePressed" Color="#FFD6D6D6"/>
|
||||||
|
|
||||||
|
<LinearGradientBrush x:Key="Colors.DataGridButton.Background.Normal" StartPoint="0,0" EndPoint="0,1">
|
||||||
|
<GradientStop Color="#E3EAF3" Offset="0.0"/>
|
||||||
|
<GradientStop Color="#D4DFEA" Offset="0.5"/>
|
||||||
|
<GradientStop Color="#C8D4E1" Offset="0.5"/>
|
||||||
|
<GradientStop Color="#BFCCE0" Offset="1.0"/>
|
||||||
|
</LinearGradientBrush>
|
||||||
|
|
||||||
|
<SolidColorBrush x:Key="Colors.DataGridButton.Foreground.Normal" Color="Black" />
|
||||||
|
<LinearGradientBrush x:Key="Colors.DataGridButton.Background.MouseOver" StartPoint="0,0" EndPoint="0,1" Opacity="0.6">
|
||||||
|
<GradientStop Color="#E3EAF3" Offset="0.0"/>
|
||||||
|
<GradientStop Color="#D4DFEA" Offset="0.5"/>
|
||||||
|
<GradientStop Color="#C8D4E1" Offset="0.5"/>
|
||||||
|
<GradientStop Color="#BFCCE0" Offset="1.0"/>
|
||||||
|
</LinearGradientBrush>
|
||||||
|
<SolidColorBrush x:Key="Colors.DataGridButton.Foreground.MouseOver" Color="DarkSlateBlue" />
|
||||||
|
<LinearGradientBrush x:Key="Colors.DataGridButton.Background.Pressed" StartPoint="0,0" EndPoint="0,1" Opacity="0.8">
|
||||||
|
<GradientStop Color="#E3EAF3" Offset="0.0"/>
|
||||||
|
<GradientStop Color="#D4DFEA" Offset="0.5"/>
|
||||||
|
<GradientStop Color="#C8D4E1" Offset="0.5"/>
|
||||||
|
<GradientStop Color="#BFCCE0" Offset="1.0"/>
|
||||||
|
</LinearGradientBrush>
|
||||||
|
<SolidColorBrush x:Key="Colors.DataGridButton.Foreground.Pressed" Color="CornflowerBlue" />
|
||||||
|
|
||||||
|
<SolidColorBrush x:Key="Colors.Images.OptionsMenu.Setting.Normal" Color="#FF6E6E70"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.Images.OptionsMenu.Setting.Pressed" Color="#FF6E6E70" Opacity="0.6"/>
|
||||||
|
|
||||||
|
<SolidColorBrush x:Key="Colors.Images.OptionsMenu.Setting.Background.MouseOver" Color="#FFD3D3D5"/>
|
||||||
|
<SolidColorBrush x:Key="Colors.Images.OptionsMenu.Setting.Background.MousePressed" Color="#FFD3D3D5"/>
|
||||||
|
</ResourceDictionary>
|
||||||
31
src/WPFEduSolution/WPFBeginner/Themes/Cultures/en-US.xaml
Normal file
31
src/WPFEduSolution/WPFBeginner/Themes/Cultures/en-US.xaml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
|
<sys:String x:Key="Cultures.LoginWindow.ErrorMessage.DuplicatedExecute">Duplicated execution.</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.LoginWindow.ErrorMessage.InvalidUser">Please check your ID and password again.</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.LoginWindow.LoginButtonText">Login</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.LoginWindow.Inform">Please enter your ID and password.</sys:String>
|
||||||
|
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Title">Contact Management Program</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Label.Name">Name:</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Label.Call">Contact</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Label.No">Employee Number:</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Label.Mail">Email:</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.ErrorMessage.SearchConditionEmpty">No search condition provided. Please enter a search condition.</sys:String>
|
||||||
|
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Button.Add">Add</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Button.Search">Search</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Button.Delete">Delete</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Button.Init">Reset</sys:String>
|
||||||
|
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.DatagGid.Column.Name">Name</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.DatagGid.Column.Call">Contact</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.DatagGid.Column.No">Employee Number</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.DatagGid.Column.Email">Email</sys:String>
|
||||||
|
|
||||||
|
<sys:String x:Key="Cultures.RegistMemberWindow.RegistButton">Register</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.RegistMemberWindow.CancelButton">Cancel</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.RegistMemberWindow.ErrorMessage.FillMustValue">Name or employee number is required.</sys:String>
|
||||||
|
|
||||||
|
</ResourceDictionary>
|
||||||
31
src/WPFEduSolution/WPFBeginner/Themes/Cultures/ko-KR.xaml
Normal file
31
src/WPFEduSolution/WPFBeginner/Themes/Cultures/ko-KR.xaml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
|
<sys:String x:Key="Cultures.LoginWindow.ErrorMessage.DuplicatedExecute">중복된 실행입니다.</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.LoginWindow.ErrorMessage.InvalidUser">아이디와 비번을 다시 한번 확인해주세요</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.LoginWindow.LoginButtonText">로그인</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.LoginWindow.Inform">아이디와 비번을 입력해주세요</sys:String>
|
||||||
|
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Title">연락처 관리 프로그램</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Label.Name">이름:</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Label.Call">연락처</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Label.No">사번:</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Label.Mail">이메일:</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.ErrorMessage.SearchConditionEmpty">검색 조건이 없습니다. 검색 조건을 입력해주세요</sys:String>
|
||||||
|
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Button.Add">추가</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Button.Search">검 색</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Button.Delete">삭제</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.Button.Init">초기화</sys:String>
|
||||||
|
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.DatagGid.Column.Name">이름</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.DatagGid.Column.Call">연락처</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.DatagGid.Column.No">사번</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.MainWindow.DatagGid.Column.Email">이메일</sys:String>
|
||||||
|
|
||||||
|
<sys:String x:Key="Cultures.RegistMemberWindow.RegistButton">등록</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.RegistMemberWindow.CancelButton">취소</sys:String>
|
||||||
|
<sys:String x:Key="Cultures.RegistMemberWindow.ErrorMessage.FillMustValue">이름 또는 사번은 반드시 필요합니다.</sys:String>
|
||||||
|
|
||||||
|
</ResourceDictionary>
|
||||||
164
src/WPFEduSolution/WPFBeginner/Themes/Styles/Buttons.xaml
Normal file
164
src/WPFEduSolution/WPFBeginner/Themes/Styles/Buttons.xaml
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||||
|
|
||||||
|
<!--Maximize Button-->
|
||||||
|
<Style x:Key="TiTleBarMaximizeButton" TargetType="{x:Type Button}">
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="Focusable" Value="False" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type Button}">
|
||||||
|
<Border Background="{TemplateBinding Background}">
|
||||||
|
<Path Fill="#FFB8B8B9" Height="14" Width="14" Canvas.Left="-7" Canvas.Top="5">
|
||||||
|
<Path.Style>
|
||||||
|
<Style TargetType="Path">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" Value="Normal">
|
||||||
|
<!--<Setter Property="Data" Value="F1M3,5C3,5 3,11 3,11 3,11 9,11 9,11 9,11 9,5 9,5 9,5 3,5 3,5z M5,3C5,3,5,3.375,5,3.938L5,4 6,4C8,4 10,4 10,4 10,4 10,6 10,8L10,9 10.062,9C10.625,9 11,9 11,9 11,9 11,3 11,3 11,3 5,3 5,3z M4,2C4,2 12,2 12,2 12,2 12,10 12,10 12,10 11.5,10 10.75,10L10,10 10,10.75C10,11.5 10,12 10,12 10,12 2,12 2,12 2,12 2,4 2,4 2,4 2.5,4 3.25,4L4,4 4,3.25C4,2.5,4,2,4,2z"/>-->
|
||||||
|
<Setter Property="Data" Value="F1M3,3C3,3 3,11 3,11 3,11 11,11 11,11 11,11 11,3 11,3 11,3 3,3 3,3z M2,2C2,2 12,2 12,2 12,2 12,12 12,12 12,12 2,12 2,12 2,12 2,2 2,2z" />
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" Value="Maximized">
|
||||||
|
<Setter Property="Data" Value="F1M3,5C3,5 3,11 3,11 3,11 9,11 9,11 9,11 9,5 9,5 9,5 3,5 3,5z M5,3C5,3 5,4 5,4 5,4 10,4 10,4 10,4 10,9 10,9 10,9 11,9 11,9 11,9 11,3 11,3 11,3 5,3 5,3z M4,2C4,2 12,2 12,2 12,2 12,10 12,10 12,10 10,10 10,10 10,10 10,12 10,12 10,12 2,12 2,12 2,12 2,4 2,4 2,4 4,4 4,4 4,4 4,2 4,2z"/>
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Path.Style>
|
||||||
|
</Path>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
|
||||||
|
<Style.Triggers>
|
||||||
|
<Trigger Property="IsMouseOver" Value="True">
|
||||||
|
<Setter Property="Background" Value="#FF474D51"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsPressed" Value="True">
|
||||||
|
<Setter Property="Background" Value="#FF3D4347"/>
|
||||||
|
</Trigger>
|
||||||
|
<DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" Value="Normal">
|
||||||
|
<Setter Property="ToolTip" Value="Maximize"/>
|
||||||
|
</DataTrigger>
|
||||||
|
<DataTrigger Binding="{Binding WindowState, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" Value="Maximized">
|
||||||
|
<Setter Property="ToolTip" Value="Restore"/>
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!--Minimize Button-->
|
||||||
|
<Style x:Key="TiTleBarMinimizeButton" TargetType="{x:Type Button}">
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="Focusable" Value="False" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type Button}">
|
||||||
|
<Border Background="{TemplateBinding Background}">
|
||||||
|
<Path Data="F1M2,2C2,2 12,2 12,2 12,2 12,3 12,3 12,3 2,3 2,3 2,3 2,2 2,2z" Fill="#FFB8B8B9" Height="4" Canvas.Left="0" Canvas.Top="0" Width="13"/>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Style.Triggers>
|
||||||
|
<Trigger Property="IsMouseOver" Value="True">
|
||||||
|
<Setter Property="Background" Value="#FF474D51"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsPressed" Value="True">
|
||||||
|
<Setter Property="Background" Value="#FF3D4347"/>
|
||||||
|
</Trigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!--Close Button-->
|
||||||
|
<Style x:Key="TiTleBarCloseButton" TargetType="{x:Type Button}">
|
||||||
|
<Setter Property="Background" Value="Transparent"/>
|
||||||
|
<Setter Property="Focusable" Value="False" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type Button}">
|
||||||
|
<Border Background="{TemplateBinding Background}">
|
||||||
|
<Path Data="F1M2,2C2,2,2.25,2,2.5,2L2.999,2 3,2 3,2.001 3.221,2.222C3.652,2.653,4.66,3.661,5.847,4.848L6.999,6 8.152,4.848C9.734,3.266,10.999,2,10.999,2L11,2.001 11,2C11,2 12,2 12,2 12,2 12,3 12,3 12,3 10.734,4.266 9.152,5.848L8,7 9.152,8.152C10.734,9.734 12,11 12,11 12,11 12,12 12,12 12,12 11,12 11,12L11,11.999 10.999,12C10.999,12,9.733,10.734,8.151,9.152L6.999,8 5.847,9.152C4.66,10.339,3.652,11.347,3.221,11.778L3,11.999 3,12 2.999,12C3,12 2,12 2,12 2,12 2,11 2,11 2,11 3.265,9.734 4.847,8.152L5.999,7 4.847,5.848C3.265,4.266,1.999,3,1.999,3L2,2.999 2,2.844C2,2.562,2,2,2,2z"
|
||||||
|
Fill="#FFB8B8B9" Height="13" Canvas.Left="0" Canvas.Top="0" Width="13"/>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Style.Triggers>
|
||||||
|
<Trigger Property="IsMouseOver" Value="True">
|
||||||
|
<Setter Property="Background" Value="#FFF06251"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsPressed" Value="True">
|
||||||
|
<Setter Property="Background" Value="#FFED3F2B"/>
|
||||||
|
</Trigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="SettingButtonStyle" TargetType="ToggleButton">
|
||||||
|
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||||
|
<Setter Property="Focusable" Value="False"/>
|
||||||
|
<Setter Property="Height" Value="22" />
|
||||||
|
<Setter Property="Width" Value="22" />
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="ToggleButton">
|
||||||
|
<Border x:Name="border" Padding="{TemplateBinding Padding}">
|
||||||
|
<Viewbox HorizontalAlignment="Center">
|
||||||
|
<Image Grid.Column="0" x:Name="img" Stretch="Fill" Source="{DynamicResource Images.OptionsMenu.Setting.Normal}" />
|
||||||
|
</Viewbox>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<Trigger Property="IsMouseOver" Value="True">
|
||||||
|
<Setter TargetName="border" Property="Background" Value="{DynamicResource Colors.Images.OptionsMenu.Setting.Background.MouseOver}" />
|
||||||
|
<Setter TargetName="img" Property="Source" Value="{DynamicResource Images.OptionsMenu.Setting.Pressed}"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsPressed" Value="True">
|
||||||
|
<Setter TargetName="border" Property="Background" Value="{DynamicResource Colors.Images.OptionsMenu.Setting.Background.MousePressed}"/>
|
||||||
|
<Setter TargetName="img" Property="Source" Value="{DynamicResource Images.OptionsMenu.Setting.Pressed}"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsChecked" Value="True">
|
||||||
|
<Setter TargetName="border" Property="Background" Value="{DynamicResource Colors.Images.OptionsMenu.Setting.Background.MousePressed}"/>
|
||||||
|
<Setter TargetName="img" Property="Source" Value="{DynamicResource Images.OptionsMenu.Setting.Pressed}"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsEnabled" Value="False">
|
||||||
|
<Setter Property="Opacity" Value="0.3" />
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style x:Key="DataGridEditButtonStyle" TargetType="Button">
|
||||||
|
<Setter Property="BorderBrush" Value="Transparent"/>
|
||||||
|
<Setter Property="BorderThickness" Value="0"/>
|
||||||
|
<Setter Property="VerticalAlignment" Value="Bottom"/>
|
||||||
|
<Setter Property="Width" Value="56"/>
|
||||||
|
<Setter Property="Height" Value="20"/>
|
||||||
|
<Setter Property="Margin" Value="3 0"/>
|
||||||
|
<Setter Property="Background" Value="{DynamicResource Colors.DataGridButton.Background.Normal}"/>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource Colors.DataGridButton.Foreground.Normal}"/>
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="Button">
|
||||||
|
<Border CornerRadius="10" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
|
||||||
|
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Content="{TemplateBinding Content}"/>
|
||||||
|
</Border>
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<Trigger Property="IsMouseOver" Value="True">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource Colors.DataGridButton.Background.MouseOver}"/>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource Colors.DataGridButton.Foreground.MouseOver}"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsPressed" Value="True">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource Colors.DataGridButton.Background.Pressed}"/>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource Colors.DataGridButton.Foreground.Pressed}"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsEnabled" Value="False">
|
||||||
|
<Setter Property="Opacity" Value="0.3" />
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
</ResourceDictionary>
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using WPFBeginner.Services;
|
||||||
|
|
||||||
|
namespace WPFBeginner.ViewModels
|
||||||
|
{
|
||||||
|
public partial class LoginWindowViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private string user;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string password;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string message;
|
||||||
|
|
||||||
|
public ICommand LoginClickCommand => new RelayCommand<Window>((window) =>
|
||||||
|
{
|
||||||
|
if (CheckID() && CheckPassword())
|
||||||
|
window.DialogResult = true;
|
||||||
|
else
|
||||||
|
Message = ResourceExplorer.GetStringResource("Cultures.LoginWindow.ErrorMessage.InvalidUser");
|
||||||
|
});
|
||||||
|
|
||||||
|
public ICommand CloseClickCommand => new RelayCommand<Window>((window) =>
|
||||||
|
{
|
||||||
|
window.DialogResult = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
private bool CheckID() => user?.Equals(App.Config.Login.User, StringComparison.OrdinalIgnoreCase) ?? false;
|
||||||
|
|
||||||
|
private bool CheckPassword() => user?.Equals(App.Config.Login.User, StringComparison.OrdinalIgnoreCase) ?? false;
|
||||||
|
}
|
||||||
|
}
|
||||||
201
src/WPFEduSolution/WPFBeginner/ViewModels/MainWindowViewModel.cs
Normal file
201
src/WPFEduSolution/WPFBeginner/ViewModels/MainWindowViewModel.cs
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using WPFBeginner.Models;
|
||||||
|
using WPFBeginner.Services;
|
||||||
|
using WPFBeginner.Views;
|
||||||
|
|
||||||
|
namespace WPFBeginner.ViewModels
|
||||||
|
{
|
||||||
|
public partial class MainWindowViewModel : ObservableRecipient
|
||||||
|
{
|
||||||
|
private ObservableCollection<Member> members;
|
||||||
|
public ObservableCollection<Member> Members
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(filterMemebers != null)
|
||||||
|
return filterMemebers;
|
||||||
|
|
||||||
|
return members;
|
||||||
|
}
|
||||||
|
set => SetProperty(ref members, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObservableCollection<Member> filterMemebers;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private Member selectedMember;
|
||||||
|
|
||||||
|
private Member searchModel;
|
||||||
|
|
||||||
|
public string MemberName
|
||||||
|
{
|
||||||
|
get => searchModel?.Name;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (searchModel == null)
|
||||||
|
searchModel = new Member();
|
||||||
|
|
||||||
|
searchModel.Name = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Call
|
||||||
|
{
|
||||||
|
get => searchModel?.Call;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (searchModel == null)
|
||||||
|
searchModel = new Member();
|
||||||
|
|
||||||
|
searchModel.Call = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string EmployeeNo
|
||||||
|
{
|
||||||
|
get => searchModel?.EmployeeNo;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (searchModel == null)
|
||||||
|
searchModel = new Member();
|
||||||
|
|
||||||
|
searchModel.EmployeeNo = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string EMail
|
||||||
|
{
|
||||||
|
get => searchModel.EMail;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (searchModel == null)
|
||||||
|
searchModel = new Member();
|
||||||
|
|
||||||
|
searchModel.EMail = value;
|
||||||
|
OnPropertyChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool isKorean;
|
||||||
|
public bool IsKorean
|
||||||
|
{
|
||||||
|
get => isKorean;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetProperty(ref isKorean, value);
|
||||||
|
App.Config.Language = value ? "ko-KR" : "en-US";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool isDefaultTheme;
|
||||||
|
public bool IsDefaultTheme
|
||||||
|
{
|
||||||
|
get => isDefaultTheme;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetProperty(ref isDefaultTheme, value);
|
||||||
|
App.Config.Theme = value ? "DefaultTheme" : "LightTheme";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICommand SearchClickCommand => new RelayCommand(() =>
|
||||||
|
{
|
||||||
|
var errorMessage = ValidateSearchValues();
|
||||||
|
if (errorMessage != null)
|
||||||
|
{
|
||||||
|
MessageBox.Show(errorMessage);
|
||||||
|
filterMemebers = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
IEnumerable<Member> result = Members;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(MemberName))
|
||||||
|
result = result.Where(i => i.Name?.Contains(MemberName) ?? false);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(EMail))
|
||||||
|
result = result.Where(i => i.EMail?.Contains(EMail) ?? false);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(Call))
|
||||||
|
result = result.Where(i => i.Call?.Contains(Call) ?? false);
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(EmployeeNo))
|
||||||
|
result = result.Where(i => i.EmployeeNo?.Contains(EmployeeNo) ?? false);
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
filterMemebers = new ObservableCollection<Member>();
|
||||||
|
else
|
||||||
|
filterMemebers = new ObservableCollection<Member>(result);
|
||||||
|
|
||||||
|
OnPropertyChanged(nameof(Members));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
private string ValidateSearchValues()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(MemberName)
|
||||||
|
&& string.IsNullOrWhiteSpace(EmployeeNo)
|
||||||
|
&& string.IsNullOrWhiteSpace(Call)
|
||||||
|
&& string.IsNullOrWhiteSpace(EMail))
|
||||||
|
return ResourceExplorer.GetStringResource("Cultures.MainWindow.ErrorMessage.SearchConditionEmpty");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ICommand DeleteClickCommand => new RelayCommand(() =>
|
||||||
|
{
|
||||||
|
if (SelectedMember == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Members.Remove(SelectedMember);
|
||||||
|
});
|
||||||
|
|
||||||
|
public ICommand InitClickCommand => new RelayCommand(() =>
|
||||||
|
{
|
||||||
|
filterMemebers = null;
|
||||||
|
searchModel = new Member();
|
||||||
|
OnPropertyChanged(nameof(MemberName));
|
||||||
|
OnPropertyChanged(nameof(EmployeeNo));
|
||||||
|
OnPropertyChanged(nameof(EMail));
|
||||||
|
OnPropertyChanged(nameof(Call));
|
||||||
|
OnPropertyChanged(nameof(Members));
|
||||||
|
});
|
||||||
|
|
||||||
|
public ICommand AddClickCommand => new RelayCommand(() =>
|
||||||
|
{
|
||||||
|
var registDialog = new RegistMemberWindow();
|
||||||
|
var result = registDialog.ShowDialog();
|
||||||
|
if (result == true)
|
||||||
|
{
|
||||||
|
var dx = registDialog.DataContext as RegistMemberWindowViewModel;
|
||||||
|
if (dx == null)
|
||||||
|
return;
|
||||||
|
Members.Add(Member.Create(dx.MemberName, dx.Call, dx.Email, dx.EmployeeNo));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
public MainWindowViewModel()
|
||||||
|
{
|
||||||
|
CreateDefaultMember();
|
||||||
|
searchModel = new Member();
|
||||||
|
isKorean = App.Config.Language.Equals("ko-KR", StringComparison.OrdinalIgnoreCase);
|
||||||
|
isDefaultTheme = App.Config.Theme.Equals("DefaultTheme", StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateDefaultMember()
|
||||||
|
{
|
||||||
|
members = new ObservableCollection<Member>();
|
||||||
|
foreach (var member in App.Config.Members)
|
||||||
|
members.Add(Member.Create(member.Name, member.Call, member.EMail, member.EmployeeNo));
|
||||||
|
OnPropertyChanged(nameof(Members));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using WPFBeginner.Services;
|
||||||
|
using WPFBeginner.Views;
|
||||||
|
|
||||||
|
namespace WPFBeginner.ViewModels
|
||||||
|
{
|
||||||
|
public partial class RegistMemberWindowViewModel : ObservableRecipient
|
||||||
|
{
|
||||||
|
[ObservableProperty]
|
||||||
|
private string memberName;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string call;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string employeeNo;
|
||||||
|
|
||||||
|
[ObservableProperty]
|
||||||
|
private string email;
|
||||||
|
|
||||||
|
public ICommand RegistClickCommand => new RelayCommand<Window>((window) =>
|
||||||
|
{
|
||||||
|
var result = Validate();
|
||||||
|
if (result != null)
|
||||||
|
MessageBox.Show(result);
|
||||||
|
else
|
||||||
|
window.DialogResult = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
public ICommand CancelClickCommand => new RelayCommand<Window>((window) =>
|
||||||
|
{
|
||||||
|
window.DialogResult = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
private string Validate()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(MemberName) || string.IsNullOrWhiteSpace(EmployeeNo))
|
||||||
|
return ResourceExplorer.GetStringResource("Cultures.RegistMemberWindow.ErrorMessage.FillMustValue");
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
90
src/WPFEduSolution/WPFBeginner/Views/LoginWindow.xaml
Normal file
90
src/WPFEduSolution/WPFBeginner/Views/LoginWindow.xaml
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<Window x:Class="WPFBeginner.Views.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:vm="clr-namespace:WPFBeginner.ViewModels"
|
||||||
|
xmlns:sv="clr-namespace:WPFBeginner.Services"
|
||||||
|
Background="Transparent" AllowsTransparency="True"
|
||||||
|
WindowStyle="None" Name="root"
|
||||||
|
mc:Ignorable="d" Height="436" Width="720">
|
||||||
|
|
||||||
|
<Window.DataContext>
|
||||||
|
<vm:LoginWindowViewModel/>
|
||||||
|
</Window.DataContext>
|
||||||
|
|
||||||
|
<WindowChrome.WindowChrome>
|
||||||
|
<WindowChrome CaptionHeight="{Binding ElementName=root, Path=ActualHeight}" />
|
||||||
|
</WindowChrome.WindowChrome>
|
||||||
|
|
||||||
|
<Window.Resources>
|
||||||
|
<Style x:Key="LoginButtonStyle" TargetType="Button">
|
||||||
|
<Setter Property="Template" >
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="Button">
|
||||||
|
<Border CornerRadius="15" Background="{TemplateBinding Background}">
|
||||||
|
<Label HorizontalAlignment="Center" VerticalAlignment="Center"
|
||||||
|
Foreground="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Foreground}"
|
||||||
|
Content="{Binding RelativeSource={RelativeSource AncestorType=Button}, Path=Content}"/>
|
||||||
|
</Border>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</Window.Resources>
|
||||||
|
|
||||||
|
<Window.Clip>
|
||||||
|
<RectangleGeometry Rect="0,0,720,436" RadiusX="25" RadiusY="25"/>
|
||||||
|
</Window.Clip>
|
||||||
|
|
||||||
|
<Border Background="Transparent">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="36"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Image Source="/Resources/Images/bg_login.jpeg" Stretch="Fill" Grid.RowSpan="2"/>
|
||||||
|
<Grid Grid.Row="0">
|
||||||
|
<StackPanel Orientation="Horizontal" Margin="0,0,17,0" Height="29" HorizontalAlignment="Right" VerticalAlignment="Top" WindowChrome.IsHitTestVisibleInChrome="True">
|
||||||
|
<Button Width="46" Height="29" Style="{DynamicResource TiTleBarCloseButton}" Command="{Binding CloseClickCommand}" CommandParameter="{Binding ElementName=root}"
|
||||||
|
IsTabStop="True" TabIndex="4"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="1">
|
||||||
|
<Label Content="WPF toy project" FontFamily="Noto Sans CJK KR Medium" FontSize="48" Foreground="White" Margin="0,93,0,0" Width="Auto" Height="Auto" HorizontalAlignment="Center" VerticalAlignment="Top"/>
|
||||||
|
<Label Content="For beginner" FontFamily="Noto Sans CJK KR Medium" FontSize="24" Foreground="White" Margin="389,60,0,0" Width="Auto" Height="Auto" HorizontalAlignment="Left" VerticalAlignment="Top"/>
|
||||||
|
<Border CornerRadius="5" Margin="150,179,150,32" Background="#4CFFFFFF" WindowChrome.IsHitTestVisibleInChrome="True">
|
||||||
|
<Grid FocusManager.FocusedElement="{Binding ElementName=TB_User}">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="1.2*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="40"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Label Grid.ColumnSpan="2" Content="{StaticResource Cultures.LoginWindow.Inform}" Margin="15,0" FontSize="24" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Bold" FontFamily="Noto Sans CJK KR Medium" Foreground="Black" />
|
||||||
|
<Image Grid.Row="1" Grid.Column="0" Source="/Resources/Images/ico_user.png" Margin="10"/>
|
||||||
|
<TextBox Grid.Row="1" Grid.Column="1" Name="TB_User" Text="{Binding User}" Margin="5,5,15,0" FontSize="14"
|
||||||
|
Background="#7FFFFFFF" VerticalContentAlignment="Center" Padding="10,0,0,0"
|
||||||
|
IsTabStop="True" TabIndex="1" Focusable="True" sv:EnterKeyTraversal.IsEnabled="True"/>
|
||||||
|
<Image Grid.Row="2" Grid.Column="0" Source="/Resources/Images/ico_pw.png" Margin="10"/>
|
||||||
|
<PasswordBox Grid.Row="2" Grid.Column="1" sv:PasswordBoxAssistant.EnableBindingPassword="True" sv:EnterKeyTraversal.IsEnabled="True"
|
||||||
|
sv:PasswordBoxAssistant.BoundPassword="{Binding Path=Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Margin="5,5,15,0"
|
||||||
|
FontSize="14" Background="#7FFFFFFF" VerticalContentAlignment="Center" Padding="10,0,0,0" IsTabStop="True" TabIndex="2"/>
|
||||||
|
<Grid Grid.Row="3" Grid.ColumnSpan="2">
|
||||||
|
<Button Style="{StaticResource LoginButtonStyle}" Content="{StaticResource Cultures.LoginWindow.LoginButtonText}" Margin="100,5" Background="#FFFF7575" FontSize="14" Foreground="White" FontWeight="Bold"
|
||||||
|
Command="{Binding LoginClickCommand}" CommandParameter="{Binding ElementName=root}" IsTabStop="True" TabIndex="3"/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Label Content="{Binding Message}" FontFamily="Noto Sans CJK KR Medium" FontSize="11" Foreground="Yellow"
|
||||||
|
Margin="159,369,0,0" Width="Auto" Height="Auto" HorizontalAlignment="Left" VerticalAlignment="Top" d:Content="ddd"/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</Window>
|
||||||
15
src/WPFEduSolution/WPFBeginner/Views/LoginWindow.xaml.cs
Normal file
15
src/WPFEduSolution/WPFBeginner/Views/LoginWindow.xaml.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace WPFBeginner.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// LoginWindow.xaml에 대한 상호 작용 논리
|
||||||
|
/// </summary>
|
||||||
|
public partial class LoginWindow : Window
|
||||||
|
{
|
||||||
|
public LoginWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
152
src/WPFEduSolution/WPFBeginner/Views/MainWindow.xaml
Normal file
152
src/WPFEduSolution/WPFBeginner/Views/MainWindow.xaml
Normal file
@@ -0,0 +1,152 @@
|
|||||||
|
<Window x:Class="WPFBeginner.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:uc="clr-namespace:WPFBeginner.Controls"
|
||||||
|
WindowStyle="None" ResizeMode="CanResize"
|
||||||
|
mc:Ignorable="d" Title="MainWindow" Height="500" Width="400" Padding="20">
|
||||||
|
|
||||||
|
<WindowChrome.WindowChrome>
|
||||||
|
<WindowChrome CaptionHeight="{Binding ElementName=titleBar, Path=ActualHeight}" ResizeBorderThickness="0 5 0 5"/>
|
||||||
|
</WindowChrome.WindowChrome>
|
||||||
|
|
||||||
|
<Window.DataContext>
|
||||||
|
<Binding Source="{StaticResource ViewModelLocator}" Path="MainWindowViewModel"/>
|
||||||
|
</Window.DataContext>
|
||||||
|
|
||||||
|
<Window.Resources>
|
||||||
|
<Style x:Key="SearchButton" TargetType="Button">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource Colors.SearchButton.Background.Normal}"/>
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource Colors.SearchButton.BorderBrush.Normal}"/>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource Colors.SearchButton.Foreground.Normal}"/>
|
||||||
|
<Setter Property="BorderThickness" Value="1"/>
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="Button">
|
||||||
|
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
|
||||||
|
<ContentControl Content="{TemplateBinding Content}"/>
|
||||||
|
</Border>
|
||||||
|
<ControlTemplate.Triggers>
|
||||||
|
<Trigger Property="IsMouseOver" Value="True">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource Colors.SearchButton.Background.MouseOver}"/>
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource Colors.SearchButton.BorderBrush.MouseOver}"/>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource Colors.SearchButton.Foreground.MouseOver}"/>
|
||||||
|
</Trigger>
|
||||||
|
<Trigger Property="IsPressed" Value="True">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource Colors.SearchButton.Background.MousePressed}"/>
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource Colors.SearchButton.BorderBrush.MousePressed}"/>
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource Colors.SearchButton.Foreground.MousePressed}"/>
|
||||||
|
</Trigger>
|
||||||
|
</ControlTemplate.Triggers>
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</Window.Resources>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="40"/>
|
||||||
|
<RowDefinition Height="130"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<!--Title Bar-->
|
||||||
|
<Grid x:Name="titleBar" Background="{DynamicResource Colors.TitleBar.Title.Background}" >
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Label Content="{StaticResource Cultures.MainWindow.Title}" Foreground="{StaticResource Colors.TitleBar.Title.Foreground}"
|
||||||
|
FontSize="14" FontFamily="NanumSquareOTF_ac Bold" VerticalContentAlignment="Center" Padding="10 0"/>
|
||||||
|
<Grid Grid.Column="2">
|
||||||
|
<StackPanel Orientation="Horizontal" WindowChrome.IsHitTestVisibleInChrome="True" VerticalAlignment="Top">
|
||||||
|
<ToggleButton Width="22" Height="22" Style="{DynamicResource SettingButtonStyle}" Name="bt_settings"/>
|
||||||
|
<Button Width="39" Height="27" Style="{DynamicResource TiTleBarMinimizeButton}" Command="{Binding MinimizeCommand}"/>
|
||||||
|
<Button Width="39" Height="27" Style="{DynamicResource TiTleBarMaximizeButton}" Command="{Binding MaximizeCommad}"/>
|
||||||
|
<Button Width="39" Height="27" Style="{DynamicResource TiTleBarCloseButton}" Command="{Binding CloseCommand}"/>
|
||||||
|
</StackPanel>
|
||||||
|
<Popup PlacementTarget="{Binding ElementName=bt_settings}" Placement="Bottom" IsOpen="{Binding ElementName=bt_settings, Path=IsChecked}" StaysOpen="False">
|
||||||
|
<Border Background="{DynamicResource Colors.SettingPopup.Background}" BorderThickness="1" BorderBrush="{DynamicResource Colors.SettingPopup.BorderBrush}" >
|
||||||
|
<StackPanel Orientation="Vertical" Width="100">
|
||||||
|
<Grid Margin="5">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="5"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<StackPanel>
|
||||||
|
<RadioButton Content="한글판" Foreground="{DynamicResource Colors.SettingPopup.Foreground}" GroupName="Cultures" IsChecked="{Binding IsKorean}"/>
|
||||||
|
<RadioButton Content="English" Foreground="{DynamicResource Colors.SettingPopup.Foreground}" GroupName="Cultures" IsChecked="{Binding IsKorean, Converter={StaticResource InverseBoolConverter}}"/>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="2">
|
||||||
|
<RadioButton Content="Dark" Foreground="{DynamicResource Colors.SettingPopup.Foreground}" GroupName="Themes"/>
|
||||||
|
<RadioButton Content="Light" Foreground="{DynamicResource Colors.SettingPopup.Foreground}" GroupName="Themes"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</Popup>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
<Border HorizontalAlignment="Stretch" VerticalAlignment="Bottom" BorderThickness="0.5" BorderBrush="{DynamicResource Colors.Section.HorizontalSeperator}"/>
|
||||||
|
|
||||||
|
<!-- Filter Box -->
|
||||||
|
<Border Grid.Row="1" Padding="0 10" HorizontalAlignment="Right" Width="400" Background="{DynamicResource Colors.Main.Background}">
|
||||||
|
<Grid HorizontalAlignment="Right" Width="400">
|
||||||
|
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="Auto"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<uc:MemberInputPanel MemberName="{Binding MemberName}" Call="{Binding Call}"
|
||||||
|
EmployeeNo="{Binding EmployeeNo}" Email="{Binding Email}"/>
|
||||||
|
|
||||||
|
<Grid Grid.RowSpan="4" Grid.Column="1">
|
||||||
|
<Button Margin="3" HorizontalAlignment="Center" VerticalAlignment="Center" Padding="2" Style="{StaticResource SearchButton}"
|
||||||
|
Command="{Binding SearchClickCommand}">
|
||||||
|
<StackPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
|
||||||
|
<Image Source="/Resources/Images/btn_search_001.png" Stretch="UniformToFill"/>
|
||||||
|
<Label Content="{StaticResource Cultures.MainWindow.Button.Search}"
|
||||||
|
Foreground="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType=Button}}"
|
||||||
|
HorizontalAlignment="Center" FontFamily="Yu Gothic UI" FontWeight="Bold" FontSize="12" Margin="0" Padding="0"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Border Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" BorderThickness="0.5" BorderBrush="{DynamicResource Colors.Section.HorizontalSeperator}"/>
|
||||||
|
|
||||||
|
<!-- Search Result -->
|
||||||
|
<Grid Grid.Row="3" Background="{DynamicResource Colors.Main.Background}">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="50"/>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="10 5">
|
||||||
|
<Button Content="{StaticResource Cultures.MainWindow.Button.Add}" Style="{DynamicResource DataGridEditButtonStyle}" Command="{Binding AddClickCommand}"/>
|
||||||
|
<Button Content="{StaticResource Cultures.MainWindow.Button.Delete}" Style="{DynamicResource DataGridEditButtonStyle}" Command="{Binding DeleteClickCommand}"/>
|
||||||
|
<Button Content="{StaticResource Cultures.MainWindow.Button.Init}" Style="{DynamicResource DataGridEditButtonStyle}" Command="{Binding InitClickCommand}"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<DataGrid Grid.Row="1" Margin="5" ItemsSource="{Binding Members}" SelectedItem="{Binding SelectedMember}" AutoGenerateColumns="False" IsReadOnly="True">
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Header="{DynamicResource Cultures.MainWindow.DatagGid.Column.Name}" Binding="{Binding Name}" Width="*"/>
|
||||||
|
<DataGridTextColumn Header="{DynamicResource Cultures.MainWindow.DatagGid.Column.Call}" Binding="{Binding Call}" Width="*"/>
|
||||||
|
<DataGridTextColumn Header="{DynamicResource Cultures.MainWindow.DatagGid.Column.No}" Binding="{Binding EmployeeNo}" Width="*"/>
|
||||||
|
<DataGridTextColumn Header="{DynamicResource Cultures.MainWindow.DatagGid.Column.Email}" Binding="{Binding EMail}" Width="*"/>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
24
src/WPFEduSolution/WPFBeginner/Views/MainWindow.xaml.cs
Normal file
24
src/WPFEduSolution/WPFBeginner/Views/MainWindow.xaml.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using System.Text;
|
||||||
|
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 WPFBeginner
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for MainWindow.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class MainWindow : Window
|
||||||
|
{
|
||||||
|
public MainWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/WPFEduSolution/WPFBeginner/Views/RegistMemberWindow.xaml
Normal file
46
src/WPFEduSolution/WPFBeginner/Views/RegistMemberWindow.xaml
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<Window x:Class="WPFBeginner.Views.RegistMemberWindow"
|
||||||
|
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:uc="clr-namespace:WPFBeginner.Controls"
|
||||||
|
xmlns:bh="clr-namespace:WPFBeginner.Behaviors"
|
||||||
|
WindowStyle="SingleBorderWindow"
|
||||||
|
xmlns:vm ="clr-namespace:WPFBeginner.ViewModels"
|
||||||
|
mc:Ignorable="d" WindowStartupLocation="CenterOwner" Name="root"
|
||||||
|
Title="Regist" SizeToContent="WidthAndHeight" MinWidth="200" MinHeight="200" d:DesignHeight="200" d:DesignWidth="200"
|
||||||
|
bh:WindowBehavior.HideCloseButton="True">
|
||||||
|
|
||||||
|
<Window.DataContext>
|
||||||
|
<vm:RegistMemberWindowViewModel />
|
||||||
|
</Window.DataContext>
|
||||||
|
|
||||||
|
<Border Background="{DynamicResource Colors.Main.Background}" Padding="5">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="*"/>
|
||||||
|
<RowDefinition Height="30"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<uc:MemberInputPanel x:Name="memberPanel"
|
||||||
|
MemberName="{Binding MemberName}"
|
||||||
|
Call="{Binding Call}"
|
||||||
|
EmployeeNo="{Binding EmployeeNo}"
|
||||||
|
Email="{Binding Email}"/>
|
||||||
|
|
||||||
|
<Grid Grid.Row="1">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
<ColumnDefinition Width="10"/>
|
||||||
|
<ColumnDefinition Width="*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Button Content="{DynamicResource Cultures.RegistMemberWindow.RegistButton}" HorizontalAlignment="Stretch" Width="Auto"
|
||||||
|
Command="{Binding RegistClickCommand}" CommandParameter="{Binding ElementName=root}"/>
|
||||||
|
<Button Grid.Column="2" Content="{DynamicResource Cultures.RegistMemberWindow.CancelButton}" HorizontalAlignment="Stretch" Width="Auto"
|
||||||
|
Command="{Binding CancelClickCommand}" CommandParameter="{Binding ElementName=root}"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Border>
|
||||||
|
</Window>
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
namespace WPFBeginner.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// RegistMemberWindow.xaml에 대한 상호 작용 논리
|
||||||
|
/// </summary>
|
||||||
|
public partial class RegistMemberWindow : Window
|
||||||
|
{
|
||||||
|
public RegistMemberWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/WPFEduSolution/WPFBeginner/WPFBeginner.csproj
Normal file
46
src/WPFEduSolution/WPFBeginner/WPFBeginner.csproj
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net8.0-windows</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<UseWPF>true</UseWPF>
|
||||||
|
<StartupObject>WPFBeginner.App</StartupObject>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="appsettings.json" />
|
||||||
|
<None Remove="Resources\Images\bg_login.jpeg" />
|
||||||
|
<None Remove="Resources\Images\btn_search_001.png" />
|
||||||
|
<None Remove="Resources\Images\ico_pw.png" />
|
||||||
|
<None Remove="Resources\Images\ico_user.png" />
|
||||||
|
<None Remove="Spec.txt" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="appsettings.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Spec.txt" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Resource Include="Resources\Images\bg_login.jpeg" />
|
||||||
|
<Resource Include="Resources\Images\btn_search_001.png" />
|
||||||
|
<Resource Include="Resources\Images\ico_pw.png" />
|
||||||
|
<Resource Include="Resources\Images\ico_user.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ApplicationDefinition Update="App.xaml">
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</ApplicationDefinition>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
46
src/WPFEduSolution/WPFBeginner/appsettings.json
Normal file
46
src/WPFEduSolution/WPFBeginner/appsettings.json
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"Login": {
|
||||||
|
"User": "admin",
|
||||||
|
"Password": "0000"
|
||||||
|
},
|
||||||
|
"Language": "ko-KR",
|
||||||
|
"Theme": "DefaultTheme",
|
||||||
|
"DefaultMembers": [
|
||||||
|
{
|
||||||
|
"Name": "최준영",
|
||||||
|
"Call": "02-2141-7523",
|
||||||
|
"EMail": "b17314.tdc.hanmacgroup@gmail.com",
|
||||||
|
"No": "b17314"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "엄지숙",
|
||||||
|
"Call": "-",
|
||||||
|
"EMail": "b23072@hanmaceng.co.kr",
|
||||||
|
"No": "b23072"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "정나래",
|
||||||
|
"Call": "-",
|
||||||
|
"EMail": "b23009@hanmaceng.co.kr",
|
||||||
|
"No": "b23009"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "강근아",
|
||||||
|
"Call": "02-2141-7317",
|
||||||
|
"EMail": "m21318.tdc.hanmacgroup@gmail.com",
|
||||||
|
"No": "m21318"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "김근형",
|
||||||
|
"Call": "02-2141-7508",
|
||||||
|
"EMail": "b20311.tdc.hanmacgroup@gmail.com",
|
||||||
|
"No": "b20311"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "정호진",
|
||||||
|
"Call": "-",
|
||||||
|
"EMail": "b23022@hanmaceng.co.kr",
|
||||||
|
"No": "b23022"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
25
src/WPFEduSolution/WPFEduSolution.sln
Normal file
25
src/WPFEduSolution/WPFEduSolution.sln
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.9.34607.119
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WPFBeginner", "WPFBeginner\WPFBeginner.csproj", "{8A5A2302-7A11-434B-8C98-D586BDC85E4C}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{8A5A2302-7A11-434B-8C98-D586BDC85E4C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{8A5A2302-7A11-434B-8C98-D586BDC85E4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{8A5A2302-7A11-434B-8C98-D586BDC85E4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{8A5A2302-7A11-434B-8C98-D586BDC85E4C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {65B27DF8-6AA9-4BC1-964B-51069FA5B003}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
Reference in New Issue
Block a user