개발노트

23. [.NET MAUI] ObservationCollection의 Item랜덤하게 가져오기(with Random) 본문

앱 개발/.NET MAUI

23. [.NET MAUI] ObservationCollection의 Item랜덤하게 가져오기(with Random)

mroh1226 2022. 8. 31. 17:23
반응형

.NET MAUI App에 같은 유형의 여러개 문제를 내는 화면을 만들어 본다.

 

문제 하나당 Page를 각각 따로 만드는 것보다 하나의 Page에 문제만 변경하여 뿌려주는 것이 효율 적이다.

 

또한, 이 문제가 한 화면에서 랜덤하게 나오려면 어떻게 해야할지 알고리즘을 작성해본다.

 

이를 예시로 아래 MyMaui라는 토이프로젝트에 구현해본다.

 

[시나리오]

FoodQuizPage라는 화면에서 4개의 음식 가격을 맞추게되면 RewardPage라는 보상화면으로 이동한다.

이때, ObservableCollection<FoodQuiz>를 이용하여 문제가 랜덤하게 나오도록 알고리즘을 작성해본다.

 


 

QuizEntity.cs (Model)
using SkiaSharp.Extended.UI.Controls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MyMAUI.Models
{
    class QuizEntity
    {
        public class FoodQuiz
        {
            public string Name { get; set; }
            public int Price { get; set; }
            public string Path { get; set; }
            public FoodQuiz(string _Name, int _Price, string _Path)
            {
                Name = _Name;
                Path = _Path;
                Price = _Price;
            }
        }
}

1. MVVM 형식을 따르기 위해 Models에 있는 QuizEntity.cs 의 FoodQuiz 객체를 사용한다.

2. FoodQuiz의 구성은 Name, Price 그리고 Image Source에 사용할 Path를 속성에 넣어준다.


 

FoodQuizPage.xaml (View)
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyMAUI.Views.FoodQuizPage"
             Title="FoodQuizPage">
    <StackLayout>
        <Frame>
            <Image Source="{Binding foodQuiz.Path}"/>
        </Frame>
        <Frame>
            <Label Text="{Binding foodQuiz.Name}"/>
        </Frame>
        <Frame>
            <Label Text="{Binding foodQuiz.Price}" IsVisible="false"/>
        </Frame>
        <Frame>
            <Entry x:Name="Answer" HorizontalOptions="FillAndExpand" ClearButtonVisibility="WhileEditing" />
        </Frame>
        <Frame>
            <Button Command="{Binding cmd_NextQuiz}"
                    CommandParameter="{Binding Source={x:Reference Answer},Path=Text}"/>
        </Frame>
    </StackLayout>
</ContentPage>

 

1. Views에는 FoodQuizPage.xaml을 생성하여 음식의 Image, Name,Price 그리고  답변으로 가격을 입력할 Entry를 만들어준다.

2. 각각 Path, Name, Price를 Binding해주고 Entry에 x:Name = Answer 로 지정한다.

3. Button의 Command에 cmd_NextQuiz를 Binding 해주고 CommandParameter를 사용하여 위에서 작성해준 Entry의 Text를 Binding하여 Button을 클릭했을 때 파라미터 값으로 넘겨준다.


 

FoodQuizVM.cs (ViewModel)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MyMAUI.Services;
using static MyMAUI.Models.QuizEntity;
using System.Windows.Input;
using System.Collections.ObjectModel;
using Javax.Xml.Namespace;

namespace MyMAUI.ViewModels
{
    class FoodQuizVM : Notify
    {
        public int randomNum;
        public ICommand cmd_NextQuiz { get; set; }
        public FoodQuiz _foodQuiz { get; set; }
        public FoodQuiz foodQuiz
        {
            get=> _foodQuiz;
            set
            {
                if(_foodQuiz != value)
                {
                    _foodQuiz = value;
                    OnPropertyChanged("foodQuiz");
                }
            }
        }

        public ObservableCollection<FoodQuiz> _foods = new ObservableCollection<FoodQuiz>();
        public ObservableCollection<FoodQuiz> foods
        {
            get=> _foods;
            set
            {
                if(_foods != value)
                {
                    _foods = value;
                    OnPropertyChanged("foods");
                }
            }
        }
        public FoodQuizVM()
        {
            AddFood();
            SetQuiz();
            cmd_NextQuiz = new Command(async(obj) =>
            {
                if (foods.Count <= 1)
                {
                    Shell.Current.SendBackButtonPressed();
                    await App.Current.MainPage.DisplayAlert("확인","보상을 얻었습니다.", "OK");
                    await Shell.Current.GoToAsync("//App/RewardPage");
                    return;

                }
                string sPrice = (string)obj;
                if (foods[randomNum].Price.ToString() == sPrice)
                {
                    foods.Remove(foodQuiz);
                    SetQuiz();
                }
            });
        }
        public void AddFood()
        {
            foods.Add(new FoodQuiz("아이스크림", 8000, "dotnet_bot"));
            foods.Add(new FoodQuiz("라면", 8000, "dotnet_bot"));
            foods.Add(new FoodQuiz("밥", 8000, "dotnet_bot"));
            foods.Add(new FoodQuiz("케잌", 8000, "dotnet_bot"));
        }
        public void SetQuiz()
        {
            if (foods.Count == 0) return;
            Random random = new Random();
            randomNum = random.Next(0,foods.Count);
            foodQuiz = foods[randomNum];
        }
    }
}

1. foods라는 ObservationCollection을 선언하여 FoodQuiz 객체를 List처럼 넣어준다.

2. Property가 변경되었을 때 알릴수있는 INotifyPropertyChanged를 Notify에 만들어주고 ViewModel에 상속시킨다.

3. AddFood() 메소드를 통해 문제로 낼 음식들을 추가해준다.

4. SetQuiz() 메소드를 통해 foods에 있는 Item을 가져올 수 있도록 만든다.

5. SetQuiz()에 Random 객체를 이용하여 random.Next(최소숫자,최대숫자) 처럼 Next() 메소드로 난수를 가져온다.

6. Random을 통해 생성된 난수를 전역변수인 randomNum에 넣어주고 이를 foods[randomNum] 처럼 ObservationCollection[Index] 를 사용하여 foods에 있는 인덱스의 Item을 가져와 foodQuiz에 바인딩할 수 있게한다.

 


빌드된 모습

*편의를 위해 가격은 8000원으로 통일했습니다.

반응형
Comments