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

■ INotifyPropertyChanged 인터페이스를 사용해 HSL 색상 뷰 모델을 바인딩하는 방법을 보여준다.

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
}

 

▶ HSLColorViewModel.cs

using System.ComponentModel;

namespace TestProject;

/// <summary>
/// HSL 색상 뷰 모델
/// </summary>
public class HSLColorViewModel : 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;

    /// <summary>
    /// 색조
    /// </summary>
    private float hue;

    /// <summary>
    /// 채도
    /// </summary>
    private float saturation;

    /// <summary>
    /// 명도
    /// </summary>
    private float luminosity;

    #endregion

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

    #region 색조 - Hue

    /// <summary>
    /// 색조
    /// </summary>
    public float Hue
    {
        get
        {
            return this.hue;
        }
        set
        {
            if(this.hue != value)
            {
                Color = Color.FromHsla(value, this.saturation, this.luminosity);
            }
        }
    }

    #endregion
    #region 채도 - Saturation

    /// <summary>
    /// 채도
    /// </summary>
    public float Saturation
    {
        get
        {
            return this.saturation;
        }
        set
        {
            if(this.saturation != value)
            {
                Color = Color.FromHsla(this.hue, value, this.luminosity);
            }
        }
    }

    #endregion
    #region 명도 - Luminosity

    /// <summary>
    /// 명도
    /// </summary>
    public float Luminosity
    {
        get
        {
            return this.luminosity;
        }
        set
        {
            if(this.luminosity != value)
            {
                Color = Color.FromHsla(this.hue, this.saturation, value);
            }
        }
    }

    #endregion

    #region 색상 - Color

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

                this.hue        = color.GetHue();
                this.saturation = color.GetSaturation();
                this.luminosity = color.GetLuminosity();

                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Hue"       ));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Saturation"));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Luminosity"));
                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">
    <ContentPage.BindingContext>
        <local:HSLColorViewModel Color="MediumTurquoise" />
    </ContentPage.BindingContext>
    <ContentPage.Resources>
        <Style TargetType="Slider">
            <Setter Property="VerticalOptions" Value="CenterAndExpand" />
        </Style>
    </ContentPage.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <BoxView Grid.Row="0"
            Color="{Binding Color}" />
        <StackLayout Grid.Row="1"
            Margin="10,0">
            <Label
                HorizontalTextAlignment="Center"
                Text="{Binding Name}" />
            <Slider Value="{Binding Hue}" />
            <Slider Value="{Binding Saturation}" />
            <Slider Value="{Binding Luminosity}" />
        </StackLayout>
    </Grid>
</ContentPage>
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요