Bustop
계속해서 리팩토링 중, GitHub 주소 첨부(23.05.02)
https://github.com/PKNU-IOT3/bustop_adminpage/blob/main/README.md
Mahapps(WPF), Mysql 이용 관리자 화면
1) 누겟 - MahApps.Metro/MahApps.Metro.Icon 설치
2) 누겟 - MySQL.Data 설치
3) MySQL 스키마 작성(버스 정보)
4) MySQL 스키마 작성(관리자 정보)
5) Logics/commons.cs 작성
6) Models/businfor.cs 작성
7) Models/managerinfor.cs 작성
8) LoginWindow.xaml(관리자 로그인 페이지) 작성
9) insertbusinfo.xaml(버스 정보 추가 페이지) 작성
App.xaml
<Application x:Class="bustop_mahapp.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:bustop_mahapp" StartupUri="MainWindow.xaml"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! --> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" /> <!-- Theme setting --> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Crimson.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application>
Logics/commons.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using MahApps.Metro.Controls; using MahApps.Metro.Controls.Dialogs; using System.Windows; namespace bustop_mahapp.Logics { public class commons { public static readonly string myConnString = "Server=localhost;" + "Port=3306;" + "Database=bus;" + "Uid=root;" + "Pwd=12345;"; public static async Task<MessageDialogResult> ShowMessageAsync(string title, string message, MessageDialogStyle style = MessageDialogStyle.Affirmative) { return await ((MetroWindow)Application.Current.MainWindow).ShowMessageAsync(title, message, style, null); } public static bool isManager = false; } }
Models/businfor.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace bustop_mahapp.Models { class businfor { public int Bus_idx { get; set; } public string Bus_num { get; set; } public string Bus_cnt { get; set; } public string Bus_gap { get; set; } } }
Models/managerinfor.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace bustop_mahapp.Models { class managerinfor { public string Manager_id { get; set; } public string Manager_pwd { get; set; } } }
Mainwindow.xaml
<mah:MetroWindow x:Class="bustop_mahapp.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:mah="http://metro.mahapps.com/winfx/xaml/controls" xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks" xmlns:local="clr-namespace:bustop_mahapp" mc:Ignorable="d" Title="관리자모드" Height="450" Width="800" FontFamily="NanumGothic" FontSize="14" Loaded="MetroWindow_Loaded"> <mah:MetroWindow.IconTemplate> <DataTemplate> <iconPacks:PackIconCodicons Kind="Account" Foreground="White" Margin="5,7"/> </DataTemplate> </mah:MetroWindow.IconTemplate> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*"/> <ColumnDefinition Width="1*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="60"/> <RowDefinition Height="1*"/> <RowDefinition Height="25"/> </Grid.RowDefinitions> <Grid Grid.Row="0" Grid.ColumnSpan="2"> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*"/> <ColumnDefinition Width="1*"/> </Grid.ColumnDefinitions> <!--<Label Grid.Column="0" Content="BUSTOP 관리자 모드" FontSize="30" FontWeight="Bold" Margin="5" HorizontalAlignment="Center" FontStyle="Italic"/>--> <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal" HorizontalAlignment="Center"> <Button x:Name="BtnBusInfor" Content="버스 현황 조회" Margin="5" Width="150" Style="{StaticResource MahApps.Styles.Button.Dialogs.Accent}" Click="BtnBusInfor_Click"/> <Button x:Name="BtnInsertBusInfor" Content="버스 정보 추가" Margin="5" Width="150" Style="{StaticResource MahApps.Styles.Button.Dialogs.Accent}" Click="BtnInsertBusInfor_Click"/> <Button x:Name="BtnLogin" Content="로그인" Margin="5" Width="100" Style="{StaticResource MahApps.Styles.Button.Dialogs.Accent}" Click="BtnLogin_Click"/> <Button x:Name="BtnLogout" Content="로그아웃" Margin="5" Width="100" Style="{StaticResource MahApps.Styles.Button.Dialogs.Accent}" Click="BtnLogout_Click"/> </StackPanel> </Grid> <DataGrid Grid.Row="1" Grid.ColumnSpan="2" x:Name="GrdResult" Style="{StaticResource MahApps.Styles.DataGrid.Azure}" Margin="10,10,10,10" IsReadOnly="True" ItemsSource="{Binding}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding Bus_idx}" Header="버스 등록 번호" FontWeight="Bold" Width="150"> <DataGridTextColumn.ElementStyle> <Style> <Setter Property="TextBlock.TextAlignment" Value="Center"/> </Style> </DataGridTextColumn.ElementStyle> </DataGridTextColumn> <DataGridTextColumn Binding="{Binding Bus_num}" Header="버스 번호" FontWeight="Bold" Width="150"> <DataGridTextColumn.ElementStyle> <Style> <Setter Property="TextBlock.TextAlignment" Value="Center"/> </Style> </DataGridTextColumn.ElementStyle> </DataGridTextColumn> <DataGridTextColumn Binding="{Binding Bus_cnt}" Header="탑승 대기 인원" FontWeight="Bold" Width="130"> <DataGridTextColumn.ElementStyle> <Style> <Setter Property="TextBlock.TextAlignment" Value="Center"/> </Style> </DataGridTextColumn.ElementStyle> </DataGridTextColumn> <DataGridTextColumn Binding="{Binding Bus_gap}" Header="배차 간격" FontWeight="Bold" Width="100"> <DataGridTextColumn.ElementStyle> <Style> <Setter Property="TextBlock.TextAlignment" Value="Center"/> </Style> </DataGridTextColumn.ElementStyle> </DataGridTextColumn> </DataGrid.Columns> </DataGrid> <StatusBar Grid.Row="2" Grid.ColumnSpan="2"> <StatusBarItem Content="BUSTOP!"/> <Separator Style="{StaticResource MahApps.Styles.Separator.StatusBar}"/> <StatusBarItem x:Name="StsResult"/> </StatusBar> </Grid> </mah:MetroWindow>
Loginwindow.xaml
<mah:MetroWindow x:Class="bustop_mahapp.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:mah="http://metro.mahapps.com/winfx/xaml/controls" xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks" xmlns:local="clr-namespace:bustop_mahapp" mc:Ignorable="d" Title="로그인" Height="400" Width="300" FontFamily="NanumGothic" ResizeMode="NoResize" Loaded="MetroWindow_Loaded"> <mah:MetroWindow.IconTemplate> <DataTemplate> <iconPacks:PackIconBoxIcons Kind="RegularLogInCircle" Foreground="White" Margin="5,7"/> </DataTemplate> </mah:MetroWindow.IconTemplate> <Grid Margin="20,20"> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*"/> <ColumnDefinition Width="2*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="1*"/> <RowDefinition Height="1*"/> <RowDefinition Height="1*"/> </Grid.RowDefinitions> <Label Grid.Row="0" Grid.Column="0" Content="ID" FontSize="15" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> <Label Grid.Row="1" Grid.Column="0" Content="PW" FontSize="15" FontWeight="Bold" HorizontalAlignment="center" VerticalAlignment="Center"/> <Button x:Name="login" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Content="로그인" Width="100" Style="{StaticResource MahApps.Styles.Button.Dialogs.Accent}" Click="login_Click"/> <TextBox x:Name="TxtID" Grid.Row="0" Grid.Column="1" Margin="10,5" FontSize="15" Height="45" Text="{Binding Manager_id}" mah:TextBoxHelper.Watermark="ID를 입력하세요" mah:TextBoxHelper.UseFloatingWatermark="True" mah:TextBoxHelper.ClearTextButton="True" KeyDown="TxtID_KeyDown"/> <TextBox x:Name="TxtPW" Grid.Row="1" Grid.Column="1" Margin="5,5" FontSize="11" Height="45" Text="{Binding Manager_id}" mah:TextBoxHelper.Watermark=" 비밀번호를 입력하세요" mah:TextBoxHelper.UseFloatingWatermark="True" mah:TextBoxHelper.ClearTextButton="True" KeyDown="TxtPW_KeyDown"/> </Grid> </mah:MetroWindow>
insertbusinfo.xaml
<mah:MetroWindow x:Class="bustop_mahapp.insertbusinfo" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:bustop_mahapp" xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks" mc:Ignorable="d" Title="버스 정보 추가" Height="500" Width="300" FontFamily="NanumGothic" ResizeMode="NoResize" Loaded="MetroWindow_Loaded"> <mah:MetroWindow.IconTemplate> <DataTemplate> <iconPacks:PackIconBoxIcons Kind="RegularBus" Foreground="White" Margin="5,7"/> </DataTemplate> </mah:MetroWindow.IconTemplate> <Grid Margin="20,20"> <Grid.RowDefinitions> <RowDefinition Height="1*"/> <RowDefinition Height="1*"/> <RowDefinition Height="1*"/> <RowDefinition Height="1*"/> <RowDefinition Height="1*"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*"/> <ColumnDefinition Width="2*"/> </Grid.ColumnDefinitions> <Label Grid.Row="0" Grid.Column="0" Content="버스 등록 번호" FontSize="12" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> <Label Grid.Row="1" Grid.Column="0" Content="버스 번호" FontSize="12" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> <Label Grid.Row="2" Grid.Column="0" Content="탑승 대기 인원" FontSize="12" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> <Label Grid.Row="3" Grid.Column="0" Content="배차 간격" FontSize="12" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/> <Button x:Name="insert" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" Content="저장" Width="100" Style="{StaticResource MahApps.Styles.Button.Dialogs.Accent}" Click="insert_Click"/> <TextBox x:Name="TxtBus_idx" Grid.Row="0" Grid.Column="1" Margin="10,5" FontSize="12" Height="45" Text="{Binding Bus_idx}" mah:TextBoxHelper.Watermark="버스 등록 번호 입력" mah:TextBoxHelper.UseFloatingWatermark="True" mah:TextBoxHelper.ClearTextButton="True" KeyDown="TxtBus_idx_KeyDown"/> <TextBox x:Name="TxtBus_num" Grid.Row="1" Grid.Column="1" Margin="10,5" FontSize="12" Height="45" Text="{Binding Bus_num}" mah:TextBoxHelper.Watermark="버스 번호 입력" mah:TextBoxHelper.UseFloatingWatermark="True" mah:TextBoxHelper.ClearTextButton="True" KeyDown="TxtBus_num_KeyDown"/> <TextBox x:Name="TxtBus_cnt" Grid.Row="2" Grid.Column="1" Margin="10,5" FontSize="12" Height="45" Text="{Binding Bus_cnt}" mah:TextBoxHelper.Watermark="탑승 대기 인원 입력" mah:TextBoxHelper.UseFloatingWatermark="True" mah:TextBoxHelper.ClearTextButton="True" KeyDown="TxtBus_cnt_KeyDown"/> <TextBox x:Name="TxtBus_gap" Grid.Row="3" Grid.Column="1" Margin="10,5" FontSize="12" Height="45" Text="{Binding Bus_gap}" mah:TextBoxHelper.Watermark="배차 간격 입력" mah:TextBoxHelper.UseFloatingWatermark="True" mah:TextBoxHelper.ClearTextButton="True" KeyDown="TxtBus_gap_KeyDown"/> </Grid> </mah:MetroWindow>
MainWindow.xaml.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using MahApps.Metro.Controls; using MySql.Data.MySqlClient; using bustop_mahapp.Logics; using bustop_mahapp.Models; using System.Data; namespace bustop_mahapp { /// <summary> /// MainWindow.xaml에 대한 상호 작용 논리 /// </summary> public partial class MainWindow : MetroWindow { public MainWindow() { InitializeComponent(); } private void MetroWindow_Loaded(object sender, RoutedEventArgs e) { //if(!commons.isManager) //{ // StsResult.Content = "로그인을 먼저 진행해주세요"; //} //else //{ // StsResult.Content = "관리자 모드 활성화"; //} } private async void BtnBusInfor_Click(object sender, RoutedEventArgs e) { if(!commons.isManager) { await commons.ShowMessageAsync("권한 없음", $"먼저 관리자모드로 로그인 해주세요!"); } else { this.DataContext = null; List<businfor> list = new List<businfor>(); try { using (MySqlConnection conn = new MySqlConnection(commons.myConnString)) { if (conn.State == ConnectionState.Closed) conn.Open(); var query = @"SELECT bus_idx, bus_num, bus_cnt, bus_gap FROM bus_table ORDER BY bus_idx ASC"; var cmd = new MySqlCommand(query, conn); var adapter = new MySqlDataAdapter(cmd); var dSet = new DataSet(); adapter.Fill(dSet, "businfor"); foreach (DataRow dr in dSet.Tables["businfor"].Rows) { list.Add(new businfor { Bus_idx = Convert.ToInt32(dr["bus_idx"]), Bus_num = Convert.ToString(dr["bus_num"]), Bus_cnt = Convert.ToInt32(dr["bus_cnt"]) + "명", Bus_gap = Convert.ToInt32(dr["bus_gap"]) + "분" }); } this.DataContext = list; StsResult.Content = $"버스 {list.Count}대 정보 조회 완료!"; } } catch (Exception ex) { await commons.ShowMessageAsync("오류", $"버스 정보 출력 오류 {ex.Message}"); } } } private async void BtnInsertBusInfor_Click(object sender, RoutedEventArgs e) { if(!commons.isManager) { await commons.ShowMessageAsync("권한 없음", "먼저 관리자모드로 로그인 해주세요!"); } else { var insertbusinforWindow = new insertbusinfo(); insertbusinforWindow.Owner = this; insertbusinforWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner; insertbusinforWindow.ShowDialog(); } } private async void BtnLogin_Click(object sender, RoutedEventArgs e) { if(commons.isManager) { await commons.ShowMessageAsync("오류", "이미 관리자 모드로 로그인 된 상태입니다!"); } else { var loginWindow = new LoginWindow(); loginWindow.Owner = this; loginWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner; loginWindow.ShowDialog(); } } private async void BtnLogout_Click(object sender, RoutedEventArgs e) { if(!commons.isManager) { await commons.ShowMessageAsync("오류", "로그아웃 된 상태입니다!"); } else { await commons.ShowMessageAsync("로그아웃", "관리자모드 비활성화"); commons.isManager = false; this.DataContext = null; } } } }
LoginWindow.xaml.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using MahApps.Metro.Controls; using MySql.Data.MySqlClient; using MahApps.Metro.Controls.Dialogs; using System.Windows; using bustop_mahapp.Logics; using bustop_mahapp.Models; using System.Data; namespace bustop_mahapp { /// <summary> /// LoginWindow.xaml에 대한 상호 작용 논리 /// </summary> public partial class LoginWindow : MetroWindow { public LoginWindow() { InitializeComponent(); } private async void login_Click(object sender, RoutedEventArgs e) { string strTxtID = ""; string strTxtPW = ""; if(string.IsNullOrEmpty(TxtID.Text)||string.IsNullOrEmpty(TxtPW.Text)) { await this.ShowMessageAsync("오류", "아이디/패스워드를 입력해주세요!",MessageDialogStyle.Affirmative,null); return; } try { using(MySqlConnection conn = new MySqlConnection(commons.myConnString)) { conn.Open(); string selQuery = @"SELECT manager_id, manager_pwd FROM manager_table WHERE manager_id = @manager_id AND manager_pwd = @manager_pwd"; MySqlCommand selCmd = new MySqlCommand(selQuery, conn); MySqlParameter prmManager_id = new MySqlParameter("@manager_id", TxtID.Text); MySqlParameter prmManager_pwd = new MySqlParameter("@manager_pwd", TxtPW.Text); selCmd.Parameters.Add(prmManager_id); selCmd.Parameters.Add(prmManager_pwd); MySqlDataReader reader = selCmd.ExecuteReader(); // manager_id,manager_pwd 읽어옴 if(reader.Read()) { strTxtID = reader["manager_id"] != null ? reader["manager_id"].ToString() : "-"; // id 아니면 - 반환 strTxtPW = reader["manager_pwd"] != null ? reader["manager_pwd"].ToString() : "-"; // pwd 아니면 -- 반환 commons.isManager = true; await this.ShowMessageAsync("로그인 성공", "관리자 모드 활성화", MessageDialogStyle.Affirmative, null); this.Close(); } else { TxtID.Focus(); await this.ShowMessageAsync("로그인 실패", "관리자 모드 비활성화", MessageDialogStyle.Affirmative, null); TxtID.Text = ""; TxtPW.Text = ""; } } } catch (Exception ex) { await this.ShowMessageAsync("로그인 오류", $"{ex.Message}", MessageDialogStyle.Affirmative, null); } } private void MetroWindow_Loaded(object sender, RoutedEventArgs e) { TxtID.Focus(); } private void TxtID_KeyDown(object sender, KeyEventArgs e) { if(e.Key==Key.Enter) { login_Click(sender, e); } } private void TxtPW_KeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Enter) { login_Click(sender, e); } } } }
insertbusinfo.xaml.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Shapes; using MahApps.Metro.Controls; using MySql.Data.MySqlClient; using MahApps.Metro.Controls.Dialogs; using bustop_mahapp.Logics; using System.Data; namespace bustop_mahapp { /// <summary> /// insertbusinfo.xaml에 대한 상호 작용 논리 /// </summary> public partial class insertbusinfo : MetroWindow { public insertbusinfo() { InitializeComponent(); } private async void insert_Click(object sender, RoutedEventArgs e) { string strBus_idx = TxtBus_idx.Text; string strBus_num = TxtBus_num.Text; string strBus_cnt = TxtBus_cnt.Text; string strBus_gap = TxtBus_gap.Text; if (string.IsNullOrEmpty(TxtBus_idx.Text)|| string.IsNullOrEmpty(TxtBus_num.Text)|| string.IsNullOrEmpty(TxtBus_cnt.Text)|| string.IsNullOrEmpty(TxtBus_gap.Text)) { await this.ShowMessageAsync("오류", "버스 정보를 모두 입력해주세요!", MessageDialogStyle.Affirmative, null); return; } try { using(MySqlConnection conn = new MySqlConnection(commons.myConnString)) { if (conn.State == ConnectionState.Closed) conn.Open(); var query = @"INSERT INTO bus_table (bus_idx, bus_num, bus_cnt, bus_gap) VALUES (@bus_idx, @bus_num, @bus_cnt, @bus_gap)"; MySqlCommand cmd = new MySqlCommand(query, conn); cmd.Parameters.AddWithValue("@bus_idx", Convert.ToInt32(strBus_idx)); cmd.Parameters.AddWithValue("@bus_num", Convert.ToInt32(strBus_num)); cmd.Parameters.AddWithValue("@bus_cnt", Convert.ToInt32(strBus_cnt)); cmd.Parameters.AddWithValue("@bus_gap", Convert.ToInt32(strBus_gap)); cmd.ExecuteNonQuery(); // DB에 실질적으로 저장시킴 await this.ShowMessageAsync("성공", "버스 정보 DB 저장 성공!", MessageDialogStyle.Affirmative, null); this.Close(); } } catch (Exception ex) { await this.ShowMessageAsync("오류", $"DB 저장 오류 {ex.Message}",MessageDialogStyle.Affirmative,null); return; } } private void TxtBus_idx_KeyDown(object sender, KeyEventArgs e) { if(e.Key==Key.Enter) { insert_Click(sender, e); } } private void TxtBus_num_KeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Enter) { insert_Click(sender, e); } } private void TxtBus_cnt_KeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Enter) { insert_Click(sender, e); } } private void TxtBus_gap_KeyDown(object sender, KeyEventArgs e) { if (e.Key == Key.Enter) { insert_Click(sender, e); } } private void MetroWindow_Loaded(object sender, RoutedEventArgs e) { TxtBus_idx.Focus(); } } }