첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

■ x:DataType 속성에서 컴파일된 바인딩과 클래식 바인딩을 함께 사용하는 방법을 보여준다.

TestProject.zip
0.15MB

▶ NamedColor.cs

using System.Reflection;
using System.Text;

namespace TestProject;

/// <summary>
/// 이름있는 색상
/// </summary>
public class NamedColor : IEquatable<NamedColor>, IComparable<NamedColor>
{
    //////////////////////////////////////////////////////////////////////////////////////////////////// Property
    ////////////////////////////////////////////////////////////////////////////////////////// Static
    //////////////////////////////////////////////////////////////////////////////// Public

    #region 이름있는 색상 리스트 - NamedColorList

    /// <summary>
    /// 이름있는 색상 리스트
    /// </summary>
    public static IList<NamedColor> NamedColorList { private set; get; }

    #endregion

    ////////////////////////////////////////////////////////////////////////////////////////// Instance
    //////////////////////////////////////////////////////////////////////////////// Public

    #region 명칭 - Name

    /// <summary>
    /// 명칭
    /// </summary>
    public string Name { private set; get; }

    #endregion
    #region 친숙한 명칭 - FriendlyName

    /// <summary>
    /// 친숙한 명칭
    /// </summary>
    public string FriendlyName { private set; get; }

    #endregion
    #region 색상 - Color

    /// <summary>
    /// 색상
    /// </summary>
    public Color Color { private set; get; }

    #endregion
    #region RGB 디스플레이 - RGBDisplay

    /// <summary>
    /// RGB 디스플레이
    /// </summary>
    public string RGBDisplay { private set; get; }

    #endregion

    //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
    ////////////////////////////////////////////////////////////////////////////////////////// Static

    #region 생성자 - NamedColor()

    /// <summary>
    /// 생성자
    /// </summary>
    static NamedColor()
    {
        List<NamedColor> namedColorList = new List<NamedColor>();

        StringBuilder stringBuilder = new StringBuilder();

        foreach(FieldInfo fieldInfo in typeof(Colors).GetRuntimeFields())
        {
            if(fieldInfo.IsPublic && fieldInfo.IsStatic && fieldInfo.FieldType == typeof(Color))
            {
                string name = fieldInfo.Name;

                stringBuilder.Clear();

                int index = 0;

                foreach(char character in name)
                {
                    if(index != 0 && Char.IsUpper(character))
                    {
                        stringBuilder.Append(' ');
                    }

                    stringBuilder.Append(character);

                    index++;
                }

                Color color = (Color)fieldInfo.GetValue(null);

                NamedColor namedColor = new NamedColor
                {
                    Name         = name,
                    FriendlyName = stringBuilder.ToString(),
                    Color        = color,
                    RGBDisplay   = string.Format
                    (
                        "{0:X2}-{1:X2}-{2:X2}",
                        (int)(255 * color.Red  ),
                        (int)(255 * color.Green),
                        (int)(255 * color.Blue )
                    )
                };

                namedColorList.Add(namedColor);
            }
        }

        namedColorList.TrimExcess();

        namedColorList.Sort();

        NamedColorList = namedColorList;
    }

    #endregion

    ////////////////////////////////////////////////////////////////////////////////////////// Instance
    //////////////////////////////////////////////////////////////////////////////// Private

    #region 생성자 - NamedColor()

    /// <summary>
    /// 생성자
    /// </summary>
    private NamedColor()
    {
    }

    #endregion

    //////////////////////////////////////////////////////////////////////////////////////////////////// Method
    ////////////////////////////////////////////////////////////////////////////////////////// Static
    //////////////////////////////////////////////////////////////////////////////// Public

    #region 찾기 - Find(name)

    /// <summary>
    /// 찾기
    /// </summary>
    /// <param name="name">명칭</param>
    /// <returns>이름있는 색상</returns>
    public static NamedColor Find(string name)
    {
        return ((List<NamedColor>)NamedColorList).Find(nc => nc.Name == name);
    }

    #endregion
    #region 최근접 색상명 구하기 - GetNearestColorName(color)

    /// <summary>
    /// 최근접 색상명 구하기
    /// </summary>
    /// <param name="color">색상</param>
    /// <returns>최근접 색상명</returns>
    public static string GetNearestColorName(Color color)
    {
        double shortestDistance = 1000;

        NamedColor closestColor = null;

        foreach(NamedColor namedColor in NamedColor.NamedColorList)
        {
            double distance = Math.Sqrt
            (
                Math.Pow(color.Red   - namedColor.Color.Red  , 2) +
                Math.Pow(color.Green - namedColor.Color.Green, 2) +
                Math.Pow(color.Blue  - namedColor.Color.Blue , 2)
            );

            if(distance < shortestDistance)
            {
                shortestDistance = distance;
                closestColor     = namedColor;
            }
        }

        return closestColor.Name;
    }

    #endregion

    ////////////////////////////////////////////////////////////////////////////////////////// Instance
    //////////////////////////////////////////////////////////////////////////////// Public

    #region 동일 여부 구하기 - Equals(other)

    /// <summary>
    /// 동일 여부 구하기
    /// </summary>
    /// <param name="other">다른 이름있는 색상</param>
    /// <returns>동일 여부</returns>
    public bool Equals(NamedColor other)
    {
        return Name.Equals(other.Name);
    }

    #endregion
    #region 비교하기 - CompareTo(other)

    /// <summary>
    /// 비교하기
    /// </summary>
    /// <param name="other">다른 이름있는 색상</param>
    /// <returns>비교 결과</returns>
    public int CompareTo(NamedColor other)
    {
        return Name.CompareTo(other.Name);
    }

    #endregion
}

 

▶ FloatToIntegerConverter.cs

using System.Globalization;

namespace TestProject;

/// <summary>
/// 단정도 실수↔정수 변환자
/// </summary>
public class FloatToIntegerConverter : IValueConverter
{
    //////////////////////////////////////////////////////////////////////////////////////////////////// Method
    ////////////////////////////////////////////////////////////////////////////////////////// Public

    #region 변환하기 - Convert(sourceValue, targetType, parameter, cultureInfo)

    /// <summary>
    /// 변환하기
    /// </summary>
    /// <param name="sourceValue">소스 값</param>
    /// <param name="targetType">타겟 타입</param>
    /// <param name="parameter">매개 변수</param>
    /// <param name="cultureInfo">문화 정보</param>
    /// <returns>변환 값</returns>
    public object Convert(object sourceValue, Type targetType, object parameter, CultureInfo cultureInfo)
    {
        return (int)Math.Round((float)sourceValue * GetParameter(parameter));
    }

    #endregion
    #region 역변환하기 - ConvertBack(sourceValue, targetType, parameter, cultureInfo)

    /// <summary>
    /// 역변환하기
    /// </summary>
    /// <param name="sourceValue">소스 값</param>
    /// <param name="targetType">타겟 타입</param>
    /// <param name="parameter">매개 변수</param>
    /// <param name="cultureInfo">문화 정보</param>
    /// <returns>역변환 값</returns>
    public object ConvertBack(object sourceValue, Type targetType, object parameter, CultureInfo cultureInfo)
    {
        return (int)sourceValue / GetParameter(parameter);
    }

    #endregion

    ////////////////////////////////////////////////////////////////////////////////////////// Private

    #region 매개 변수 구하기 - GetParameter(parameter)

    /// <summary>
    /// 매개 변수 구하기
    /// </summary>
    /// <param name="parameter">매개 변수</param>
    /// <returns>매개 변수</returns>
    private double GetParameter(object parameter)
    {
        if(parameter is float)
        {
            return (float)parameter;
        }
        else if(parameter is int)
        {
            return (int)parameter;
        }
        else if(parameter is string)
        {
            return float.Parse((string)parameter);
        }

        return 1;
    }

    #endregion
}

 

▶ RGBColorViewModel.cs

using System.ComponentModel;

namespace TestProject;

/// <summary>
/// RGB 색상 뷰 모델
/// </summary>
public class RGBColorViewModel : INotifyPropertyChanged
{
    //////////////////////////////////////////////////////////////////////////////////////////////////// Event
    ////////////////////////////////////////////////////////////////////////////////////////// Public

    #region 속성 변경시 - PropertyChanged

    /// <summary>
    /// 속성 변경시
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

    //////////////////////////////////////////////////////////////////////////////////////////////////// Field
    ////////////////////////////////////////////////////////////////////////////////////////// Private

    #region Field

    /// <summary>
    /// 색상
    /// </summary>
    private Color color;

    /// <summary>
    /// 명칭
    /// </summary>
    private string name;

    #endregion

    //////////////////////////////////////////////////////////////////////////////////////////////////// Property
    ////////////////////////////////////////////////////////////////////////////////////////// Public

    #region 적색 - Red

    /// <summary>
    /// 적색
    /// </summary>
    public float Red
    {
        get
        {
            return this.color.Red;
        }
        set
        {
            if(this.color.Red != value)
            {
                Color = new Color(value, this.color.Green, this.color.Blue);
            }
        }
    }

    #endregion
    #region 녹색 - Green

    /// <summary>
    /// 녹색
    /// </summary>
    public float Green
    {
        get
        {
            return this.color.Green;
        }
        set
        {
            if(this.color.Green != value)
            {
                Color = new Color(this.color.Red, value, this.color.Blue);
            }
        }
    }

    #endregion
    #region 청색 - Blue

    /// <summary>
    /// 청색
    /// </summary>
    public float Blue
    {
        get
        {
            return this.color.Blue;
        }
        set
        {
            if(this.color.Blue != value)
            {
                Color = new Color(this.color.Red, this.color.Green, value);
            }
        }
    }

    #endregion

    #region 색상 - Color

    /// <summary>
    /// 색상
    /// </summary>
    public Color Color
    {
        get
        {
            return this.color;
        }
        set
        {
            if(this.color != value)
            {
                this.color = value;

                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Red"  ));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Green"));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Blue" ));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Color"));

                Name = NamedColor.GetNearestColorName(this.color);
            }
        }
    }

    #endregion
    #region 명칭 - Name

    /// <summary>
    /// 명칭
    /// </summary>
    public string Name
    {
        get
        {
            return this.name;
        }
        private set
        {
            if(this.name != value)
            {
                this.name = value;

                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
            }
        }
    }

    #endregion
}

 

▶ MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="TestProject.MainPage"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:TestProject"
    x:DataType="local:RGBColorViewModel">
    <ContentPage.BindingContext>
        <local:RGBColorViewModel Color="Orange" />
    </ContentPage.BindingContext>
    <ContentPage.Resources>
        <Style TargetType="Slider">
            <Setter Property="VerticalOptions" Value="Center" />
        </Style>
        <Style TargetType="Label">
            <Setter Property="HorizontalTextAlignment" Value="Center" />
        </Style>
        <local:FloatToIntegerConverter x:Key="FloatToIntegerConverterKey" />
    </ContentPage.Resources>
    <StackLayout
        HorizontalOptions="Center"
        VerticalOptions="Center">
        <BoxView
            Color="{Binding Color}"
            HeightRequest="300"
            WidthRequest="300"
            HorizontalOptions="Center" />
        <StackLayout
            Margin="0,10,0,0"
            x:DataType="{x:Null}">
            <Label Text="{Binding Name}" />
            <Slider
                Margin="0,30,0,0"
                Value="{Binding Red}" />
            <Label
                Text="{Binding Red,
                    Converter={StaticResource FloatToIntegerConverterKey},
                    ConverterParameter=255,
                    StringFormat='적색 : {0:X2}'}" />
            <Slider
                Margin="0,10,0,0"
                Value="{Binding Green}" />
            <Label
                Text="{Binding Green,
                    Converter={StaticResource FloatToIntegerConverterKey},
                    ConverterParameter=255,
                    StringFormat='녹색 : {0:X2}'}" />
            <Slider
                Margin="0,10,0,0"
                Value="{Binding Blue}" />
            <Label>
                <Label.Text>
                    <Binding
                        Path="Blue"
                        StringFormat="청색 : {0:X2}"
                        Converter="{StaticResource FloatToIntegerConverterKey}">
                        <Binding.ConverterParameter>
                            <x:Single>255</x:Single>
                        </Binding.ConverterParameter>
                    </Binding>
                </Label.Text>
            </Label>
        </StackLayout>
    </StackLayout>
</ContentPage>
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요