개발노트

24. [.NET MAUI] IMultiValueConverter 사용하기(CommandParameter 에MultiBinding 하기) 본문

앱 개발/.NET MAUI

24. [.NET MAUI] IMultiValueConverter 사용하기(CommandParameter 에MultiBinding 하기)

mroh1226 2022. 9. 14. 11:36
반응형

하나의 컨트롤에 2가지 값을 넘겨주고싶을 때 MultiBinding을 사용하여 이를 해결 할 수 있다.

 

같은 컨트롤의 여러 값이 필요한 상황이라면 {Binding .} 이나 ObservationCollection<>을 사용하면 해결된다.

 

하지만, 다른 컨트롤의 여러값이 필요한 상황이라면 이야기가 달라진다.

 

예를 들어 하나의 Button에 여러개의 CommandParameter를 줘야하는 상황이 온다면, IMultiValueConverter 를 이용하여 MultiBinding을 할 수 있다.

 

Button에 버튼클릭 Command도 Binding하고, CommandParameter로 2개 이상의 Parameter 값을 전달 받아보자.

 

 


 

1. 자신이 원하는 Parameter들을 받을 수 있는 객체를 Model에 생성한다.

 

QuizEntity.cs
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 PriorityQuiz
        {
            public string Name { get; set; }
            public string Path { get; set; }
            public int Priority { get; set; }
            public PriorityQuiz(string _Name, string _Path, int _Priority)
            {
                Name = _Name;
                Path = _Path;
                Priority = _Priority;
            }

        }
        
        public class PrioritySkia
        {
            public SKLottieView Skia { get; set; }
            public PriorityQuiz Priority { get; set; }

            public PrioritySkia(PriorityQuiz _Priority, SKLottieView _Skia)
            {
                this.Priority = _Priority;
                this.Skia = _Skia;
            }
        }

    }

}

PriorityQuiz 와 SKLottieview 이 2가지의 Parameter를 받을 PrioritySkia 라는 객체를 생성하였다.

 

PriorityQuiz 객체는 위에서 확인가능하고, SKLottieview는 이전 포스터를 확인 하시면됩니다.

 

https://mroh1226.tistory.com/35

 

20. SkiaSharp로 Lottie 사용하기(애니메이션 효과)

마우이 커뮤니티에서 깃허브 링크를 공유받았는데 .NET MAUI 에서도 이제 Lottie를 사용할 수 있게 된 것 같다. Gif 파일에 IsAnimationPlaying = True 로 줘도 실행이 안되는 문제에 대한 고민이 다른 방법으

mroh1226.tistory.com

 


2. IMultiValueConverter 를 상속받는 Class를 생성하여 Convert 인터페이스를 작성한다.

 

PrioritySkiaMultiConverter.cs
using SkiaSharp.Extended.UI.Controls;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static MyMAUI.Models.QuizEntity;

namespace MyMAUI.Services
{

    public class PrioritySkiaMultiConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            //PriorityQuiz, SKLottieView 순서대로 values 배열에 넣음
            return new PrioritySkia((PriorityQuiz)values[0], (SKLottieView)values[1]);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            //Mode = "TwoWay" 일때 사용
            throw new NotImplementedException();
        }

    }

}

values[0] 에는 PriorityQuiz 객체를, values[1]에는 SKLottieView 객체를 넣기 위해  (변수형)values[] 로 미리 변수형을 정해준다.

 


3. 마크업 소스 작성 ResourceDictionary에  PrioritySkiaMultiConverter를 추가해주고 컨트롤.CommandParameter를 통해 <MultiBinding의 Converter>를 연결한다.

4. <Binding Path와 Source>를 이용하여 위에서 정해줬던 values[0], values[1] 순서대로 바인딩해준다.

 

PriorityQuizPage.xaml
<?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"
             xmlns:skia="clr-namespace:SkiaSharp.Extended.UI.Controls;assembly=SkiaSharp.Extended.UI"
             xmlns:service="clr-namespace:MyMAUI.Services"
             x:Class="MyMAUI.Views.PriorityQuizPage"
             Title="PriorityQuizPage">
    <ContentPage.Resources>
        <ResourceDictionary>
            <service:PrioritySkiaMultiConverter x:Key="convert"/>
        </ResourceDictionary>
    </ContentPage.Resources>
    
    <Grid RowDefinitions="*,*,*,*,*" ColumnDefinitions="*,*">
        <ImageButton x:Name="Image_A" 
                     Grid.Row="0" 
                     Grid.RowSpan="3" 
                     Grid.Column="0"
                     Source="{Binding priorityA.Path}" 
                     Command="{Binding cmd_Select}"/>
        <skia:SKLottieView x:Name="pick_A" 
                           Grid.Row="0" 
                           Grid.RowSpan="3" 
                           Grid.Column="0" 
                           IsAnimationEnabled="False"
                           RepeatCount="0" 
                           Source="pop_like.json"/>

        <ImageButton x:Name="Image_B" 
                     Grid.Row="0" 
                     Grid.RowSpan="3" 
                     Grid.Column="1"
                     Source="{Binding priorityB.Path}" 
                     Command="{Binding cmd_Select}"/>
        <skia:SKLottieView x:Name="pick_B" 
                           Grid.Row="0" 
                           Grid.RowSpan="3" 
                           Grid.Column="1"
                           IsAnimationEnabled="False" 
                           RepeatCount="0" 
                           Source="pop_like.json"/>
        <Label Text="{Binding priorityA.Name}" 
               Grid.Row="3" 
               Grid.Column="0"/>
        <Label Text="{Binding priorityB.Name}" 
               Grid.Row="3" 
               Grid.Column="1"/>
        
        
        <Button Text="A" 
                Grid.Row="4" 
                Grid.Column="0"
                Command="{Binding cmd}">
            <Button.CommandParameter>
                <MultiBinding Converter="{StaticResource convert}">
                    <Binding Path="priorityA"/>
                    <Binding Source="{x:Reference pick_A}"/>
                </MultiBinding>
            </Button.CommandParameter>
        </Button>
        <Button Text="B" 
                Grid.Row="4" 
                Grid.Column="1"
                Command="{Binding cmd}">
            <Button.CommandParameter>
                <MultiBinding Converter="{StaticResource convert}">
                    <Binding Path="priorityB"/>
                    <Binding Source="{x:Reference pick_B}"/>
                </MultiBinding>
            </Button.CommandParameter>
        </Button>
    </Grid>
</ContentPage>

*ViewModel에 있는 PriorityQuiz를 Source로 바인딩시켜줬을 때 엉뚱한 값이 들어가거나 초기 값만 들어간다. 또한, ViewModel에서 변경되어 OnPropertyChange("PriorityQuiz")를 타고 변경되어도 이상하게 마크업에서 바인딩된 값은 안변한다... Command에 바인딩된 소스에서도 값이 바뀌지 않고 초기값만 가져옴..

(ViewModel에서 바인딩 할 변수는 위 마크업 소스와 같이 Path로 연결시켜주니 잘 작동한다.

x:Reference 로 연결한 값은 Source로 잘 바인딩 됨.!      차이점이 뭔지 공부 필요)

 


5. ViewModel을 아래와 같이 작성한다.

Command<> 에 Converter에 사용한 객체(PrioritySkia)를 넣어준다. →  Command<PrioritySkia>

6. Parameter로 받은 object를 o라고 정하고 임의로 받아 안에 있는 객체를 각각 사용할 수 있다.

PriorityQuizVM.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MyMAUI.Services;
using System.Collections.ObjectModel;
using System.Windows.Input;
using static MyMAUI.Models.QuizEntity;
using SkiaSharp.Extended.UI.Controls;


namespace MyMAUI.ViewModels
{
    class PriorityQuizVM : Notify
    {
        public ICommand cmd_pick { get; set; }
        public ICommand cmd_Select { get; set; }
        public ICommand cmd { get; set; }
        int RandomNumA;
        int RandomNumB;
        public PriorityQuiz _priorityA { get; set; }
        public PriorityQuiz priorityA
        {
            get => _priorityA;
            set
            {
                if(_priorityA != value)
                {
                    _priorityA = value;
                    OnPropertyChanged("priorityA");
                }
            }
        }
        public PriorityQuiz _priorityB { get; set; }
        public PriorityQuiz priorityB
        {
            get => _priorityB;
            set
            {
                if (_priorityB != value)
                {
                    _priorityB = value;
                    OnPropertyChanged("priorityB");
                }
            }
        }
        public ObservableCollection<PriorityQuiz> _priorityQuiz = new ObservableCollection<PriorityQuiz>();
        public ObservableCollection<PriorityQuiz> priorityQuiz
        {
            get => _priorityQuiz;
            set
            {
                if(_priorityQuiz != value)
                {
                    _priorityQuiz = value;
                    OnPropertyChanged("priorityQuiz");
                }
            }
        }
        public PriorityQuizVM()
        {
            AddPriorityQuiz();
            SetPriorityQuiz();

            cmd_Select = new Command(() =>
            {
                SetPriorityQuiz();
            });

            //MultiConverter로 받아오기
            cmd = new Command<PrioritySkia>(async(o) =>
            {
                PriorityQuiz pp = o.Priority;
                SKLottieView ss = o.Skia;
                ss.IsAnimationEnabled = true;
                await Task.Delay(700);
                
                await App.Current.MainPage.DisplayAlert("확인", pp.Name, "OK");
            });

        }

        public void AddPriorityQuiz()
        {
            priorityQuiz.Add(new PriorityQuiz("Name0", "dotnet_bot.svg", 0));
            priorityQuiz.Add(new PriorityQuiz("Name1", "dotnet_bot.svg", 1));
            priorityQuiz.Add(new PriorityQuiz("Name2", "dotnet_bot.svg", 2));
            priorityQuiz.Add(new PriorityQuiz("Name3", "dotnet_bot.svg", 3));
            priorityQuiz.Add(new PriorityQuiz("Name4", "dotnet_bot.svg", 4));
            priorityQuiz.Add(new PriorityQuiz("Name5", "dotnet_bot.svg", 5));
        }

        public void SetPriorityQuiz()
        {
            if (priorityQuiz.Count == 1) return;
            Random random = new Random();
            do
            {
                RandomNumA = random.Next(0,priorityQuiz.Count);
                RandomNumB = random.Next(0,priorityQuiz.Count);
            } while (RandomNumA == RandomNumB); //난수끼리 같다면 다시 난수발생 시키기
            
            priorityA = priorityQuiz[RandomNumA];
            priorityB = priorityQuiz[RandomNumB];
        }


    }
}

 

PriorityQuiz pp = o.Priority;
SKLottieView ss = o.Skia;

위 소스로 pp와 ss로 값을 받아 이용할 수 있다.

 

*테스트를 위해 ss.IsAnimationEnabled = true; 로 Lottie 이미지를 실행하고, 

await App.Current.MainPage.DisplayAlert("확인", pp.Name, "OK"); 를 통해 바인딩된 PriorityQuiz의 Name을 확인한다.

 

 


빌드된 모습

반응형
Comments