
MainWindow.xaml
<Window x:Class="calcu.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:local="clr-namespace:calcu"
mc:Ignorable="d"
Title="MainWindow"
Height="400" Width="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="4" />
<RowDefinition Height="auto" />
<RowDefinition Height="4" />
<RowDefinition Height="auto" />
<RowDefinition Height="4" />
<RowDefinition Height="auto" />
<RowDefinition Height="4" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="4" />
</Grid.ColumnDefinitions>
<Button Grid.Row="1" Grid.Column="1"
Content="New Contact"
Click="Button_Click"/>
<TextBox Grid.Row="3"
Grid.Column="1"
TextChanged="TextBox_TextChanged"/>
<ListView Grid.Row="5"
Grid.Column="1"
Height="350"
x:Name="contactListView" IsSynchronizedWithCurrentItem="False">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<!--데이터 바인딩 Contact 객체의 Name 필드-->
<TextBlock Text="{Binding Name}"
FontSize="20"
FontWeight="Bold"/>
<!--데이터 바인딩 Contact 객체의 Email 필드-->
<TextBlock Text="{Binding Email}"
FontSize="15"
Foreground="DodgerBlue"/>
<!--데이터 바인딩 Contact 객체의 Phone 필드-->
<TextBlock Text="{Binding Phone}"
FontStyle="Italic"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>

MainWindow.xaml.cs
using System.DirectoryServices;
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;
using calcu.Model;
using SQLite;
namespace calcu
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
List<Contact> contacts;
public MainWindow()
{
InitializeComponent();
contacts = new List<Contact>();
// 최초 프로그램 실행시, 저장된 데이터베이스 정보 출력을 갱신한다.
ReadDatabase();
}
private void ReadDatabase()
{
// Contact 객체 형태를 리스트로 선언하여 준비하고
//List<Contact> contacts;
// SQLite에서 테이블을 읽어와 Contact 리스트에 담고
using (SQLiteConnection connection = new SQLiteConnection(App.databasePath))
{
connection.CreateTable<Contact>();
contacts = connection.Table<Contact>().ToList();
}
if (contacts != null)
{
//Contact 모델의 리스트 요소를 하나씩 가져와
//foreach (var item in contacts)
//{
// // contactListView 컨트롤에 읽어들인 객체를 추가합니다.
// contactListView.Items.Add(new ListViewItem
// {
// Content = item
// });
//}
// 위 코드는 추가된 정보가 중복되고, 갱신시 사라지지 않습니다.
// contact 추가시, 이전 로드된 데이터는 UI에서 사라지도록 구현합니다.
contactListView.ItemsSource = contacts;
}
// 이 방식의 문제점은, 기존에 입력된 객체의 정보가 누적되는 점입니다.
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
// sender를 통해, searchTextBox 객체를 가져와
TextBox? searchTextBox = sender as TextBox;
// contacts 객체 Name 필드 중, searchTextBox.Text 값이 포함된(Contains) 결과를 searchResultList에 담아
// contacts 객체 Name 필드 값을 소문자로 가져옵니다.
// searchTextBox 컨트롤 객체의 text 요소를 소문자로 가져옵니다.
var searchResultList = contacts.Where(contact => contact.Name.ToLower().Contains(searchTextBox.Text.ToLower())).ToList();
// contactListView 컨트롤에 출력
contactListView.ItemsSource = searchResultList;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// contact를 추가하기 위한 새로운 윈도우 객체를 만들고,
NewContractWindow newContactWindow = new NewContractWindow();
// 출력한다.
newContactWindow.ShowDialog();
// newContactWindow 화면이 닫히면, 저장된 데이터베이스 정보 출력을 갱신한다.
ReadDatabase();
}
}
}
메인쪽 화면 및 코드
데이터베이스에서 가져온 데이터를 리스트에 담고 리스트뷰로 값을 출력한다.
폰트와 글꼴도 바꿀 수 있다.
소문자 대문자 구분도 된다.
맨 위의 New Contact를 클릭하면 새로운 계정 정보를 만들 수 있고, 그 밑의 TextBox에서는 필터링 서치를 할 수 있다.
데이터베이스 프로그램에 연결

DBeaver라는 프로그램인데, 여러 데이터베이스가 있고 하나를 골라서 연결할 수 있다.
SQLite에 연결한 상태고 Contacts.db에 올라간 데이터를 저렇게 확인할 수 있다.
Contact.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SQLite;
namespace calcu.Model
{
public class Contact
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public override string ToString()
{
return $"{Name} - {Email} - {Phone}";
}
}
}
계정 생성에 사용할 클래스와 이 값들을 리턴하는 함수가 들어있다.
프로퍼티를 사용해 값을 수정할 수 있게 되어있다.
App.xaml.cs
using System.Configuration;
using System.Data;
using System.Windows;
namespace calcu
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
// SQLite DB 파일 이름 지정
static string databaseName = "Contacts.db";
// 현재 프로젝트 경로 가져오기
static string projectPath = "../../../";
// 생성될 DB 경로(현재 프로젝트 경로 + 파일이름) 지정
public static string databasePath = System.IO.Path.Combine(projectPath, databaseName);
}
}
db 파일의 경로를 저장해놓은 파일
"../../../"는 로컬 파일 경로를 의미한다.
NewContractWindow.xaml
<Window x:Class="calcu.NewContractWindow"
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:calcu"
mc:Ignorable="d"
Title="NewContractWindow"
Height="300"
Width="260"
WindowStyle="None"
ResizeMode="NoResize"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="4" />
<RowDefinition Height="auto" />
<RowDefinition Height="4" />
<RowDefinition Height="auto" />
<RowDefinition Height="4" />
<RowDefinition Height="auto" />
<RowDefinition Height="4" />
<RowDefinition Height="auto" />
<RowDefinition Height="4" />
<RowDefinition Height="auto" />
<RowDefinition Height="4" />
<RowDefinition Height="auto" />
<RowDefinition Height="4" />
<RowDefinition Height="auto" />
<RowDefinition Height="4" />
<RowDefinition Height="auto" />
<RowDefinition Height="4" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="4" />
</Grid.ColumnDefinitions>
<TextBlock Text="Name:"
Grid.Row="1"
Grid.Column="1" />
<TextBox x:Name="nameTextBox"
Grid.Row="3"
Grid.Column="1" />
<TextBlock Text="Email:"
Grid.Row="5"
Grid.Column="1" />
<TextBox x:Name="emailTextBox"
Grid.Row="7"
Grid.Column="1" />
<TextBlock Text="Phone:"
Grid.Row="9"
Grid.Column="1" />
<TextBox x:Name="PhoneTextBox"
Grid.Row="11"
Grid.Column="1" />
<Button Grid.Row="13"
Grid.Column="1"
Content="Add New Contact" Click="Button_Click"/>
</Grid>
</Window>

계정 생성쪽에 있는 창의 자믈 코드
특이사항으로는
WindowStyle="None"
ResizeMode="NoResize"
가 있는데, 테두리 창을 없애고 크기 고정을 한다.

NewContractWindow.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 calcu.Model;
using SQLite;
namespace calcu
{
/// <summary>
/// NewContractWindow.xaml에 대한 상호 작용 논리
/// </summary>
public partial class NewContractWindow : Window
{
public NewContractWindow()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// AddNewContactWindow 윈도우의 입력 TextBox 컨트롤에서 값을 가져와
// Contact 데이터 모델 객체의 필드에 각각 값을 할당한다.
Contact contact = new Contact()
{
// 모델에서 Id 필드는 [PrimaryKey, AutoIncrement] 이기 때문에
// 값을 지정하지 않아도, PK는 자동으로 AutoIncrement 된다.
// 그외 Name, Email, Phone 필드 프로퍼티에 값을 할당한다.
Name = nameTextBox.Text,
Email = emailTextBox.Text,
Phone = PhoneTextBox.Text
};
// 지정된 경로에 생성할 DB 연결 객체 생성
// using 문을 벗어나면, connection 객체가 자동 메모리 해제됨
using (SQLiteConnection connection = new SQLiteConnection(App.databasePath))
{
// Contact 클래스 정의를 기반으로 SQLite DB Table 생성 (테이블이 없을 경우, 있으면 X)
connection.CreateTable<Contact>();
// UI 컨트롤에 입력된 데이터를 Contact 객체 형태로, 생성한 SQLite DB Table에 삽입
connection.Insert(contact);
}
// AddNewContact 윈도우에서 "Save"버튼을 누르면 화면이 닫히도록 구현한다.
Close();
}
}
}
버튼을 누르면 데이터베이스에 연결해서 값을 전달해주고 창을 닫는다.
테이블이 비어있을 경우도 대비해서 CreateTable도 있다.
현재 Linq까지 진행했다. 이런 데이터베이스 쪽 연결을 다룰 때마다 느끼는 건데, 데이터베이스를 로컬로 활용하는 것은 크게 까다롭지 않다. 다만 이걸 네트워크에 연결해서 사용하려고 할 때마다 숨이 턱 막히는 기분이다.
C#에서는 네트워크로 골치 아플 일이 적었으면 좋겠다.
'C#' 카테고리의 다른 글
LMS5_Project09 C# WPF 프로젝트 - 서버/클라이언트 채팅 프로그램 (0) | 2025.03.06 |
---|---|
LMS5_Project08 C# WPF 프로젝트 - Resource Monitoring Tool (0) | 2025.02.22 |
C# 문제풀이 2 (0) | 2025.01.24 |
C# 문제풀이 1 (3) | 2025.01.24 |
C# 클래스 과제 마무리 (0) | 2025.01.24 |