Simple WPF application for POS

Simple WPF application for POS

Here, we are creating a simple WPF application for POS systems using WPF, C# and MSSQL.

This demo is created in Visual Studio 2022 using Dapper.

The database schema looks like below:


Here, for simplicity, we are considering that a customer can have one or more orders. Each order can have one or more products in it.

Below data is prepopulated in the database tables:

Below is the project structure in Visual studio 2022.

Model classes are created as shown below :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace POS.Models
{
    public class Customer
    {
        public int CustomerID { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
    }
}        
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace POS.Models
{
    public class Order
    {
        public int OrderID { get; set; }
        public int CustomerID { get; set; }
        public DateTime OrderDate { get; set; }
        public decimal TotalAmount { get; set; }
    }
}        
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace POS.Models
{
    public class Product
    {
        public int ProductID { get; set; }
        public int OrderID { get; set; }
        public string ProductName { get; set; }
        public decimal Price { get; set; }
        public int Quantity { get; set; }
    }
}        

Views are created as below :

MainWindow.xaml

<Window x:Class="POS.MainWindow"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" WindowStartupLocation="CenterScreen"
        Title="Sales Management" Height="350" Width="600" VerticalAlignment="Center" HorizontalAlignment="Center">
    <Grid>
        <!-- DataGrid for Customers -->
        <DataGrid x:Name="CustomersDataGrid" 
                  ItemsSource="{Binding Path=Customers, Mode=TwoWay}" 
                  AutoGenerateColumns="False" 
                  SelectedItem="{Binding SelectedCustomer}">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Customer ID" Binding="{Binding CustomerID}"/>
                <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
                <DataGridTextColumn Header="Email" Binding="{Binding Email}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>        

Code behind: Here we are setting the datacontext to MainViewModel.cs


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 POS
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new MainViewModel();
        }
    }
}        

OrdersWindow.xaml

<Window x:Class="POS.OrdersWindow"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml" WindowStartupLocation="CenterScreen"
        Title="Orders" Height="350" Width="400" VerticalAlignment="Center" HorizontalAlignment="Center">
    <Grid>
        <DataGrid ItemsSource="{Binding Orders}" 
                  AutoGenerateColumns="False" 
                  SelectedItem="{Binding SelectedOrder}"
                  HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Order ID" Binding="{Binding OrderID}"/>
                <DataGridTextColumn Header="Order Date" Binding="{Binding OrderDate}"/>
                <DataGridTextColumn Header="Total Amount" Binding="{Binding TotalAmount}"/>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>        

ProductsWindow.xaml

<Window x:Class="POS.ProductsWindow"
        xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="https://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="https://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:POS"
        mc:Ignorable="d" WindowStartupLocation="CenterScreen"
        Title="ProductsWindow" Height="450" Width="800" VerticalAlignment="Center" HorizontalAlignment="Center">
    <StackPanel>
        
        <DataGrid ItemsSource="{Binding Products}" 
                          AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Product Name" Binding="{Binding ProductName}"/>
                <DataGridTextColumn Header="Price" Binding="{Binding Price}"/>
                <DataGridTextColumn Header="Quantity" Binding="{Binding Quantity}"/>
            </DataGrid.Columns>
        </DataGrid>
        <StackPanel Orientation="Horizontal">
            <Label Content="Total" />
            <TextBlock Text="{Binding TotalBillAmount}" FontSize="14" FontWeight="Bold" 
                           HorizontalAlignment="Right" Margin="10"/>
        </StackPanel>
    </StackPanel>
</Window>        

MainViewModel.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using POS.DAL;
using POS.Models;

namespace POS
{
    public class MainViewModel : INotifyPropertyChanged
    {
        private ObservableCollection<Customer> _customers;
        private ObservableCollection<Order> _orders;
        private ObservableCollection<Product> _products;

        private Customer _selectedCustomer;
        private Order _selectedOrder;

        public ObservableCollection<Customer> Customers
        {
            get => _customers;
            set { _customers = value; OnPropertyChanged(); }
        }

        public ObservableCollection<Order> Orders
        {
            get => _orders;
            set { _orders = value; OnPropertyChanged(); }
        }

        public ObservableCollection<Product> Products
        {
            get => _products;
            set { _products = value; OnPropertyChanged(); }
        }

        public Customer SelectedCustomer
        {
            get => _selectedCustomer;
            set
            {
                _selectedCustomer = value;
                LoadOrdersForCustomer();
                OnPropertyChanged();
            }
        }

        public Order SelectedOrder
        {
            get => _selectedOrder;
            set
            {
                _selectedOrder = value;
                LoadProductsForOrder();
                OnPropertyChanged();
            }
        }

        public decimal TotalBillAmount { get; set; }

        public MainViewModel()
        {
            LoadCustomers();
        }

        private void LoadCustomers()
        {
            // Load data from the database (this is a simplified version)
            Customers = new ObservableCollection<Customer>(DatabaseHelper.GetCustomers());
        }

        private void LoadOrdersForCustomer()
        {
            if (SelectedCustomer != null)
            {
                Orders = new ObservableCollection<Order>(DatabaseHelper.GetOrders(SelectedCustomer.CustomerID));
                ShowOrdersWindow();
            }
        }

        private void LoadProductsForOrder()
        {
            if (SelectedOrder != null)
            {
                Products = new ObservableCollection<Product>(DatabaseHelper.GetProducts(SelectedOrder.OrderID));
                TotalBillAmount = Products.Sum(p => p.Price * p.Quantity);

                ShowProductsWindow();
            }
        }

        private void ShowOrdersWindow()
        {
            // Create the OrdersWindow and pass the data
            OrdersWindow ordersWindow = new OrdersWindow
            {
                DataContext = this  // Pass the current ViewModel or a new ViewModel
            };
            ordersWindow.ShowDialog();  // Use ShowDialog() to make it modal
        }

        private void ShowProductsWindow()
        {
            // Assuming you have another ProductsWindow
            ProductsWindow productsWindow = new ProductsWindow
            {
                DataContext = this  // Pass the current ViewModel or a new ViewModel for products
            };
            productsWindow.ShowDialog();  // Show modal window for products
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }
}        

Data access layer using Dapper:

using Dapper;
using POS.Models;
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;


namespace POS.DAL
{
    public static class DatabaseHelper
    {
        private static string connectionString = @"Server=localhost\SQLEXPRESS;Database=SalesDB;Trusted_Connection=True";

        public static List<Customer> GetCustomers()
        {
            using (var connection = new SqlConnection(connectionString))
            {
                connection.Open();
                var query = "SELECT * FROM Customers";
                return connection.Query<Customer>(query).ToList();
            }
        }

        public static List<Order> GetOrders(int customerId)
        {
            using (var connection = new SqlConnection(connectionString))
            {
                connection.Open();
                var query = "SELECT * FROM Orders WHERE CustomerID = @CustomerID";
                return connection.Query<Order>(query, new { CustomerID = customerId }).ToList();
            }
        }

        public static List<Product> GetProducts(int orderId)
        {
            using (var connection = new SqlConnection(connectionString))
            {
                connection.Open();
                var query = "SELECT * FROM Products WHERE OrderID = @OrderID";
                return connection.Query<Product>(query, new { OrderID = orderId }).ToList();
            }
        }
    }
}        

Output:

On running the application, we will get window populated with customer information. On double click on any customer record, orders for that particular customer will be shown in Orders window. On double click on any orders record, the product window will open. It contains the products and total bill amount for that particular order for the selected customer.

Summary:

Thus we have seen a simple WPF application using MVVM pattern. Any corrections or suggestions are most welcome. Thank you for reading the article.

Github link: https://github.com/dheerajkarwa89/POS



要查看或添加评论,请登录

社区洞察

其他会员也浏览了