티스토리 뷰

WPF .NET

Kiosk 만들기 - Part3

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

주문시작 화면 만들기를 시작합니다.

1. 주문 시작 화면의 기능

  • 매장이나 포장을 선택해서 메뉴 화면으로 이동합니다.
  • 첫화면으로 이동할 수 있습니다.
  • 장애인 UI로 전환할 수 있습니다.
  • 30초가 지나면 처음화면으로 이동합니다.

 

2. AppContext.cs

키오스크의 현재 상태(주문이나 화면 위치등의 정보)를 보관하고, 사용합니다.

/// <summary>
/// AppContext - 애플리케이션에서 전체적으로 유지하는 데이터 보관
/// </summary>
public class AppContext : BindableBase, IAppContext
{
    /// <summary>
    /// 관리자 로그인 여부
    /// </summary>
    public bool IsLogin { get; set; }

    private bool _isOpenCase;
    /// <summary>
    /// 케이스 오픈 여부
    /// </summary>
    public bool IsOpenCase
    {
        get { return _isOpenCase; }
        set { SetProperty(ref _isOpenCase, value); }
    }
    private bool _isDisabledUi;
    /// <summary>
    /// 장애인 UI 여부
    /// </summary>
    public bool IsDisabledUi
    {
        get { return _isDisabledUi; }
        set { SetProperty(ref _isDisabledUi, value); }
    }
    private StatusEnum _kioskStatus;
    /// <summary>
    /// 키오스크 상태
    /// </summary>
    public StatusEnum KioskStatus
    {
        get { return _kioskStatus; }
        set { SetProperty(ref _kioskStatus, value); }
    }
    private bool _isEatIn;
    /// <summary>
    /// 매장 이용 여부 false이면 포장
    /// </summary>
    public bool IsEatIn
    {
        get { return _isEatIn; }
        set { SetProperty(ref _isEatIn, value); }
    }
}
  • AppContext는 애플리케이션에서 1개만 존재해야 하기 때문에 싱글톤 인스턴스로 관리합니다.
    • App.xaml.cs -> RegisterTypes -> containerRegistry.RegisterSingleton<IAppContext, AppContext>();
  • ViewModelBase.cs에서 AppContext를 주입받아서 사용할 수 있도록 만들었습니다.
private IAppContext _appContext;
/// <summary>
/// 앱 컨텍스트
/// </summary>
public IAppContext AppContext
{
    get { return _appContext; }
    set { SetProperty(ref _appContext, value); }
}

//...

/// <summary>
/// 런타임 생성자
/// </summary>
/// <param name="containerProvider"></param>
public ViewModelBase(IContainerProvider containerProvider)
{
    ContainerProvider = containerProvider;
    RegionManager = ContainerProvider.Resolve<IRegionManager>();
    AppContext = ContainerProvider.Resolve<IAppContext>();
    Init();
}

Xaml에서 AppContext에 바로 접근해서 사용할 수 있도록, public으로 생성했습니다.

 

3. OrderStart.xaml

<UserControl
    x:Class="PrismKiosk.Views.OrderStart"
    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:OrderStartViewModel,
                                     IsDesignTimeCreatable=True}"
    d:DesignHeight="1080"
    d:DesignWidth="640"
    prism:ViewModelLocator.AutoWireViewModel="True"
    mc:Ignorable="d">
    <Grid>
        <!--  일반UI  -->
        <Grid Visibility="{Binding AppContext.IsDisabledUi, Converter={StaticResource InverterBoolToVisibilityConverter}}">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="0.3*" />
                <RowDefinition Height="0.7*" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Button
                Grid.Column="1"
                Margin="10"
                Padding="10"
                HorizontalAlignment="Right"
                Command="{Binding HomeCommand}"
                CommandParameter="kiosk"
                Content="처음으로" />
            <Button
                Grid.Row="1"
                Margin="10"
                Command="{Binding OrderTypeCommand}"
                CommandParameter="EatIn"
                Content="매장 (EAT-IN)" />
            <Button
                Grid.Row="1"
                Grid.Column="1"
                Margin="10"
                Command="{Binding OrderTypeCommand}"
                CommandParameter="ToGo"
                Content="포장 (TO-GO)" />
            <Image
                Grid.Row="2"
                Grid.ColumnSpan="2"
                Margin="10"
                Source="/Assets/Images/delicious-ice-cream-in-studio.jpg"
                Stretch="UniformToFill" />
            <TextBlock
                Grid.Row="2"
                Grid.ColumnSpan="2"
                Text="출처 Freepik" />
            <Button
                Grid.Row="3"
                Grid.Column="1"
                Margin="10"
                Padding="10"
                HorizontalAlignment="Right"
                Command="{Binding DisabledCommand}"
                CommandParameter="Disabled"
                Content="장애인" />
        </Grid>
        <!--  장애인UI  -->
        <Grid Visibility="{Binding AppContext.IsDisabledUi, Converter={StaticResource BoolToVisibilityConverter}}">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="0.7*" />
                <RowDefinition Height="0.3*" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Image
                Grid.Row="1"
                Grid.ColumnSpan="2"
                Margin="5"
                Source="/Assets/Images/delicious-ice-cream-in-studio.jpg"
                Stretch="UniformToFill" />
            <Button
                Grid.Row="2"
                Margin="10"
                Command="{Binding OrderTypeCommand}"
                CommandParameter="EatIn"
                Content="매장 (EAT-IN)" />
            <Button
                Grid.Row="2"
                Grid.Column="1"
                Margin="10"
                Command="{Binding OrderTypeCommand}"
                CommandParameter="ToGo"
                Content="포장 (TO-GO)" />
            <TextBlock
                Grid.Row="2"
                Grid.ColumnSpan="2"
                Margin="5"
                HorizontalAlignment="Left"
                VerticalAlignment="Top"
                Text="출처 Freepik" />
            <Button
                Grid.Row="3"
                Grid.Column="0"
                Margin="10"
                Padding="10"
                HorizontalAlignment="Left"
                Command="{Binding HomeCommand}"
                CommandParameter="kiosk"
                Content="처음으로" />
            <Button
                Grid.Row="3"
                Grid.Column="1"
                Margin="10"
                Padding="10"
                HorizontalAlignment="Right"
                Command="{Binding DisabledCommand}"
                CommandParameter="Normal"
                Content="일반" />
        </Grid>
    </Grid>
</UserControl>
  • 일반UI와 장애인UI 전환은 간단하게 Grid를 보이기/숨기기를 통해서 구현했습니다.
    • <Grid Visibility="{Binding AppContext.IsDisabledUi, Converter={StaticResource InverterBoolToVisibilityConverter}}">
    • VisualState를 이용하는 방법도 사용할 수 있습니다만 복잡하기 때문에 여기서는 사용하지 않았습니다.

 

4. OrderStartViewModel.cs

/// <summary>
/// 주문 구분(시작) 뷰모델
/// </summary>
public class OrderStartViewModel : ViewModelBase
{
    /// <summary>
    /// 타이머
    /// </summary>
    private DispatcherTimer _timer;

    /// <summary>
    /// 주문 구분 선택 커맨드
    /// </summary>
    public ICommand OrderTypeCommand { get; set; }
    /// <summary>
    /// 장애인UI 커맨드
    /// </summary>
    public ICommand DisabledCommand { get; set; }
    /// <summary>
    /// 기본 생성자
    /// </summary>
    public OrderStartViewModel()
    {

    }
    /// <summary>
    /// 런타임 생성자
    /// </summary>
    /// <param name="containerProvider"></param>
    public OrderStartViewModel(IContainerProvider containerProvider) : base(containerProvider)
    {
        Init();
    }

    private void Init()
    {
        OrderTypeCommand = new DelegateCommand<string>(OnOrderType);
        DisabledCommand = new DelegateCommand<string>(OnDisabled);

        _timer = new DispatcherTimer(TimeSpan.FromSeconds(30),
                    DispatcherPriority.Normal, TimerTick, App.Current.Dispatcher);
    }
    private void TimerTick(object sender, EventArgs e)
    {
        ClearAppContextAndGoHome();
    }

    /// <summary>
    /// 장애인 UI, 일반 UI 전환
    /// </summary>
    private void OnDisabled(string para)
    {
        AppContext.IsDisabledUi = para.ToLower() == "disabled" ? true : false;
    }

    /// <summary>
    /// 주문 구분 선택
    /// </summary>
    /// <param name="orderType"></param>
    private void OnOrderType(string orderType)
    {
        AppContext.IsEatIn = orderType.ToLower() == "eatin" ? true : false;
        //주문 구분 선택 후 메뉴 선택 화면으로 이동
        RegionManager.RequestNavigate("KioskContentRegion", "SelectMenu");
    }

    /// <summary>
    /// 들어올때
    /// </summary>
    /// <param name="navigationContext"></param>
    public override void OnNavigatedTo(NavigationContext navigationContext)
    {
        AppContext.KioskStatus = Commons.StatusEnum.OrderStart;
        _timer.Stop();
        _timer.Start();
    }
    /// <summary>
    /// 나갈때
    /// </summary>
    /// <param name="navigationContext"></param>
    public override void OnNavigatedFrom(NavigationContext navigationContext)
    {
        DestroyTimer();
    }
    /// <summary>
    /// 지워질 때
    /// </summary>
    public override void Destroy()
    {
        DestroyTimer();
    }
    private void DestroyTimer()
    {
        _timer.Stop();
        _timer = null;
    }
}
  • Timer는 DispatcherTimer를 사용했습니다.
    • Init()에서 생성하면서 UI Thread를 지정해서 화면 변경시 에러가 발생하지 않습니다.
    • TimerTick에서 ClearAppContextAndGoHome() 메서드를 실행해서 처음 화면으로 이동합니다.
    • DestoryTimer() 메서드에서 timer를 정지하고 null을 할당합니다. 이 메서드는 OnNavigatedFrom과 Destory()에서 호출됩니다.
    • Destory()는 Prism에서 제공하는, IDestructible 인터페이스에서 제공되며, 뷰가 제거되는 경우에 호출됩니다.

 

5. 소스

GitHub - kaki104/PrismKiosk at Part3/edit-orderstart

 

GitHub - kaki104/PrismKiosk

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

github.com

 

반응형

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

Kiosk 만들기 - Part5  (0) 2023.10.25
Kiosk 만들기 - Part4  (2) 2023.10.23
Prism - ContentControl에 화면 생성해서 넣기 1/2  (2) 2023.10.19
Kiosk 만들기 - Part2  (0) 2023.10.18
Kiosk 만들기 - Part1  (0) 2023.10.16
댓글