티스토리 뷰

WPF .NET

Kiosk 만들기 - Part4

kaki104 2023. 10. 23. 10:00
반응형

메뉴 선택 화면 작업을 시작합니다.

1. SelectMenu.xaml

<UserControl
    x:Class="PrismKiosk.Views.SelectMenu"
    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:local="clr-namespace:PrismKiosk.Views"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:prism="http://prismlibrary.com/"
    xmlns:vm="clr-namespace:PrismKiosk.ViewModels"
    d:DataContext="{d:DesignInstance vm:SelectMenuViewModel,
                                     IsDesignTimeCreatable=True}"
    d:DesignHeight="1080"
    d:DesignWidth="640"
    prism:ViewModelLocator.AutoWireViewModel="True"
    mc:Ignorable="d">
    <UserControl.Resources>
        <Style TargetType="TabItem">
            <Setter Property="HeaderTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <Border>
                            <TextBlock Padding="20" Text="{Binding}" />
                        </Border>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="0.6*" />
            <RowDefinition Height="0.4*" />
        </Grid.RowDefinitions>
        <Button
            Grid.Column="0"
            Margin="10"
            Padding="10"
            HorizontalAlignment="Left"
            Command="{Binding GoBackCommand}"
            CommandParameter="kiosk"
            Content="이전으로" />
        <Button
            Grid.Column="0"
            Margin="10"
            Padding="10"
            HorizontalAlignment="Right"
            Command="{Binding HomeCommand}"
            CommandParameter="kiosk"
            Content="처음으로" />
        <TabControl Grid.Row="1">
            <TabItem Header="커피">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <ItemsControl ItemsSource="{Binding Coffees}">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <WrapPanel
                                    IsItemsHost="True"
                                    ItemHeight="230"
                                    ItemWidth="310" />
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <Grid Margin="10">
                                    <Grid.RowDefinitions>
                                        <RowDefinition />
                                        <RowDefinition Height="Auto" />
                                    </Grid.RowDefinitions>
                                    <Image Source="{Binding ImageUri}" Stretch="UniformToFill" />
                                    <StackPanel Grid.Row="1">
                                        <TextBlock HorizontalAlignment="Center" Text="{Binding Name}" />
                                        <TextBlock HorizontalAlignment="Center" Text="{Binding Price, StringFormat={}{0:N0}}" />
                                    </StackPanel>
                                </Grid>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                    <Button
                        Grid.Row="1"
                        Grid.Column="0"
                        Margin="10"
                        Padding="10"
                        HorizontalAlignment="Left"
                        Command="{Binding GoBackCommand}"
                        CommandParameter="kiosk"
                        Content="이전" />
                    <Button
                        Grid.Row="1"
                        Grid.Column="0"
                        Margin="10"
                        Padding="10"
                        HorizontalAlignment="Right"
                        Command="{Binding HomeCommand}"
                        CommandParameter="kiosk"
                        Content="다음" />
                </Grid>
            </TabItem>
            <TabItem Header="프라프치노" />
            <TabItem Header="논커피" />
            <TabItem Header="에이드" />
        </TabControl>
        <Grid Grid.Row="2" Margin="0,10">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0.8*" />
                <ColumnDefinition Width="0.2*" />
            </Grid.ColumnDefinitions>
            <DataGrid>
                <DataGrid.Columns>
                    <DataGridTextColumn Header="메뉴명" />
                    <DataGridTextColumn Header="단가" />
                    <DataGridTextColumn Header="수량" />
                    <DataGridTextColumn Header="금액" />
                </DataGrid.Columns>
            </DataGrid>
            <Button
                Grid.Column="1"
                Margin="10,0,0,0"
                Content="결제" />
        </Grid>
    </Grid>
</UserControl>
  • 상품 목록 출력을 위해 ItemsControl을 이용했습니다.
    • ListBox는 아이템을 선택한 경우 선택된 아이템의 주위의 색을 변경하기 때문에, 아이템이 선택되어도 아무런 표시가 나지 않는 ItemsControl을 이용했습니다.
    • ItemsControl을 이용해서 데이터를 표시하려면, ItemTemplate를 이용해야 합니다.
    • 아이템의 배치를 2x2로 만들기 위해 WrapPanel을 이용했습니다.
    • 하단부에 DataGrid를 이용해서 선택한 상품들의 목록을 출력합니다.
  • 화면 중간에 이전, 다음 버튼은 상품이 여러개인 경우 페이지 이동을 위해서 추가한 버튼입니다. 완성된 버튼이 아니라 이 포스트에서는 무시합니다.
  • TabItem의 Header 스타일을 입력하기 위해서 UserControl.Resources에 Style을 추가했습니다.
    • UserControl.Resource에 Style을 추가하면, 현재 화면내에서만 적용됩니다.
    • TargetType="TabItem"으로 지정하고 x:Key를 지정하지 않으면, 모든 TabItem에 대해 스타일이 자동으로 적용됩니다.

2. SelectedMenuViewModel.cs

using Prism.Ioc;
using PrismKiosk.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PrismKiosk.ViewModels
{
    /// <summary>
    /// 메뉴 선택 뷰 모델
    /// </summary>
    public class SelectMenuViewModel : ViewModelBase
    {
        private IList<Product> _coffees;
        /// <summary>
        /// 커피 목록
        /// </summary>
        public IList<Product> Coffees
        {
            get { return _coffees; }
            set { SetProperty(ref _coffees, value); }
        }
        private IList<Product> _frappuccinos;
        /// <summary>
        /// 프라프치노 목록
        /// </summary>
        public IList<Product> Frappuccinos
        {
            get { return _frappuccinos; }
            set { SetProperty(ref _frappuccinos, value); }
        }
        /// <summary>
        /// 기본 생성자
        /// </summary>
        public SelectMenuViewModel()
        {
            Coffees = new List<Product>
            {
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "아이스 아메리카노", Price = 1500 },
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "아메리카노", Price = 1500 },
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "아이스 바닐라 라떼", Price = 3500 },
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "바닐라 라떼", Price = 3500 },
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "페이지2-1", Price = 1500 },
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "페이지2-2", Price = 1500 },
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "페이지2-3", Price = 3500 },
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "페이지2-4", Price = 3500 },
            };
        }
        /// <summary>
        /// 런타임 생성자
        /// </summary>
        /// <param name="containerProvider"></param>
        public SelectMenuViewModel(IContainerProvider containerProvider) : base(containerProvider)
        {
            Init();
        }

        private void Init()
        {
            Coffees = new List<Product>
            {
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "아이스 아메리카노", Price = 1500, ImageUri = new Uri("pack://application:,,,/Assets/Images/delicious-ice-cream-in-studio.jpg") },
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "아메리카노", Price = 1500, ImageUri = new Uri("pack://application:,,,/Assets/Images/delicious-ice-cream-in-studio.jpg") },
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "아이스 바닐라 라떼", Price = 3500, ImageUri = new Uri("pack://application:,,,/Assets/Images/delicious-ice-cream-in-studio.jpg") },
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "바닐라 라떼", Price = 3500, ImageUri = new Uri("pack://application:,,,/Assets/Images/delicious-ice-cream-in-studio.jpg") },
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "페이지2-1", Price = 1500 , ImageUri = new Uri("pack://application:,,,/Assets/Images/delicious-ice-cream-in-studio.jpg")},
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "페이지2-2", Price = 1500 , ImageUri = new Uri("pack://application:,,,/Assets/Images/delicious-ice-cream-in-studio.jpg")},
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "페이지2-3", Price = 3500 , ImageUri = new Uri("pack://application:,,,/Assets/Images/delicious-ice-cream-in-studio.jpg")},
                new Product{ Category = Commons.ProductCategory.Coffee, Name = "페이지2-4", Price = 3500 , ImageUri = new Uri("pack://application:,,,/Assets/Images/delicious-ice-cream-in-studio.jpg")},
            };

        }
    }
}
  • Coffees에 new List<Product>()를 기본 생성자에서 한번하고, Init()에서 한번 실행하는데, 이유는 디자인 타임과 런타임에서 실행되는 생성자가 다르기 때문입니다.
    • 물론 CreateProducts() 메서드를 한개 만들어서 처리하는 것이 더 좋습니다.
    • 실제 상품 데이터를 이용하는 경우에는 Init()에서 처리하면 됩니다.

3. ViewModelBase.cs

/// <summary>
/// 타이머
/// </summary>
protected DispatcherTimer Timer;

/// <summary>
/// 뒤로가기 커맨드
/// </summary>
public ICommand GoBackCommand { get; set; }

/// <summary>
/// 뒤로 돌아가기
/// </summary>
private void OnGoBack(string viewType)
{
    if (viewType != "kiosk")
    {
        return;
    }
    var regionJournal = RegionManager.Regions["KioskContentRegion"].NavigationService.Journal;
    if(regionJournal != null && regionJournal.CanGoBack)
    {
        regionJournal.GoBack();
    }
}
  • DispatcherTimer를 ViewModelBase로 이동했습니다.
    • 모든 화면들이 30초가 입력이 없는 경우 홈화면으로 이동을 해야해서 그렇게 처리했습니다.
    • 여기서는 무조건 30초가 지나면 홈화면으로 이동하고 있습니다. 이 부분은 1초에 한번씩 확인해서 사용자의 입력이 없는 상태가 30초가 넘으면 홈화면으로 이동하도록 수정되어야 할 것 같습니다. 추후 반영하도록 하겠습니다.
  • GoBackCommand를 추가했습니다. 이전 페이지로 이동할 수 있습니다.
    • NavigationService.Journal 개체를 확인하면 뒤로 가기가 가능한지 아닌지 확인 할 수 있습니다.

4. 기타

ProductCategory.cs, Product,cs, Order.cs, OrderDetail.cs 등의 데이터 모델을 추가했습니다. 상품 선택하는 용도는 Product 모델을 사용하고, 사용자가 주문 화면을 시작하면 Order가 발생하고, 상품을 선택하면 OrderDetail이 생성되어서 Order에 연결되는 형태로 구현할 예정입니다.

5. 소스

kaki104/PrismKiosk at Part4/edit-selectmenu (github.com)

 

GitHub - kaki104/PrismKiosk

Contribute to kaki104/PrismKiosk development by creating an account on GitHub.

github.com

 

반응형

'WPF .NET' 카테고리의 다른 글

Kiosk 만들기 - Part6  (0) 2023.10.27
Kiosk 만들기 - Part5  (0) 2023.10.25
Kiosk 만들기 - Part3  (0) 2023.10.20
Prism - ContentControl에 화면 생성해서 넣기 1/2  (2) 2023.10.19
Kiosk 만들기 - Part2  (0) 2023.10.18
댓글