2022. 7. 26. 00:00ㆍMAUI
모든 .NET 다중 플랫폼 앱 UI(.NET MAUI) 바인딩 가능 속성에는 바인딩 가능한 속성을 만들 때 설정되고 개체의 BindableProperty 속성에서 사용할 수 있는 기본 바인딩 모드가 있다.
기본 바인딩 모드는 속성이 데이터 바인딩 대상일 때 적용되는 모드를 나타낸다.
Rotation, Scale 및 Opacity와 같은 대부분의 속성에 대한 기본 바인딩 모드는 OneWay이다.
이러한 속성이 데이터 바인딩 대상인 경우에는 대상 속성이 원본에서 설정된다.
<?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="MauiApp1.Xaml.BindingMode.MainPage"
Title="MainPage">
<StackLayout Padding="10, 0">
<Label x:Name="label"
Text="TEXT"
FontSize="80"
HorizontalOptions="Center"
VerticalOptions="Center" />
<Slider x:Name="slider"
VerticalOptions="Center"
Value="{Binding Opacity, Source={x:Reference label}}" />
</StackLayout>
</ContentPage>
초기에 Slider 은 Label 의 Opacity 속성을 참조 하며 기본값은 1이다. 따라서 1로 초기화 된다.
Slider 에 Value 속성에 대한 기본 바인딩 모드가 Twoway 이기 때문에
Slider 를 조정하면 Label의 Opacity 값도 바뀐다.
Binding Mode 는 다음 중에서 하나로 재정의 할 수 있다.
- TwoWay — 데이터가 소스와 대상 간에 양방향으로 이동
- OneWay — 소스에서 타겟으로 데이터 이동
- OneWayToSource — 데이터가 대상에서 소스로 이동
- OneTime — 데이터가 소스에서 대상으로 한번만 이동 (.NET MAUI 3.0의 새로운 기능)
대부분의 바인딩 가능한 속성에는 OneWay의 기본 바인딩 모드가 있지만
다음을 포함하여 일부 속성에는 TwoWay의 기본 바인딩 모드가 있다.
TwoWay
- DatePicker의 날짜 속성
- Editor, Entry, SearchBar, EntryCell의 Text 속성
- ListView의 IsRefreshing 속성
- MultiPage의 SelectedItem 속성
- Picker의 SelectedIndex 및 SelectedItem 속성
- Slider와 Stepper의 Value 속성
- Switch의 IsToggled 속성
- SwitchCell의 속성에
- TimePicker의 시간 속성
One-way-to-source bindings
ListView의 SelectedItem 속성에는 OneWayToSource의 기본 바인딩 모드가 있다.
OneTime
바인딩 컨텍스트가 변경되는 경우에만 업데이트된다.
원본 속성의 변경 사항을 모니터링할 필요가 없기 때문에 바인딩 인프라가 간소화된다.
ViewModels 및 속성 변경 알림
데이터 바인딩에서 ViewModel 을 사용할때 ViewModel 은 데이터 바이딩 소스에 해당한다.
ViewModel 은 속성 값이 변경될 때 바인딩 인프라가 알림을 받을 수 있도록 하는 알림 메커니즘을 구현한다.
이것은 PropertyChanged 라는 이벤트를 정의 하는 INotifyPropertyChanged 인터페이스 이다.
이 인터페이스는 공용 속성 중 하나가 값을 변경 할 때 이벤트를 발생 시킨다.
다음 예제를 보자
HslColorView.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"
x:Class="MauiApp1.Xaml.BindingMode.HslColorView"
xmlns:local="clr-namespace:MauiApp1.Xaml.BindingMode"
Title="ViewModel">
<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 Color="{Binding Color}"
Grid.Row="0" />
<StackLayout Grid.Row="1">
<Label Text="{Binding Name}"
HorizontalTextAlignment="Center" FontSize="Large"/>
<Slider Value="{Binding Hue}"/>
<Label Text="{Binding Hue, StringFormat='색조 : {0:F2}'}" FontSize="Large" />
<Slider Value="{Binding Saturation}"/>
<Label Text="{Binding Saturation, StringFormat='채도 : {0:F2}'}" FontSize="Large" />
<Slider Value="{Binding Luminosity}"/>
<Label Text="{Binding Luminosity, StringFormat='명도 : {0:F2}'}" FontSize="Large" />
</StackLayout>
</Grid>
</ContentPage>
NamedColor.cs
(참조 : https://icodebroker.tistory.com/11584)
using System.Reflection;
using System.Text;
namespace MauiApp1.Xaml.BindingMode;
public class NamedColor : IEquatable<NamedColor>, IComparable<NamedColor>
{
#region 이름있는 색상 리스트 - NamedColorList
/// <summary>
/// 이름있는 색상 리스트
/// </summary>
public static IList<NamedColor> NamedColorList { private set; get; }
#endregion
#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
#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
#region 생성자 - NamedColor()
/// <summary>
/// 생성자
/// </summary>
private NamedColor()
{
}
#endregion
#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
#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 MauiApp1.Xaml.BindingMode;
public class HslColorViewModel : INotifyPropertyChanged
{
Color color;
string name;
float hue;
float saturation;
float luminosity;
public event PropertyChangedEventHandler PropertyChanged;
public float Hue
{
get
{
return hue;
}
set
{
if (hue != value)
{
Color = Color.FromHsla(value, saturation, luminosity);
}
}
}
public float Saturation
{
get
{
return saturation;
}
set
{
if (saturation != value)
{
Color = Color.FromHsla(hue, value, luminosity);
}
}
}
public float Luminosity
{
get
{
return luminosity;
}
set
{
if (luminosity != value)
{
Color = Color.FromHsla(hue, saturation, value);
}
}
}
public Color Color
{
get
{
return color;
}
set
{
if (color != value)
{
color = value;
hue = color.GetHue();
saturation = color.GetSaturation();
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(color);
}
}
}
public string Name
{
get
{
return name;
}
private set
{
if (name != value)
{
name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
}
}
내용을 보면 HslColorViewModel.cs (이하 뷰모델) 에 각 Xaml Binding Propery 와 mapping 되는 속성을 선언한다.
그리고 해당 속성이 set 될때 PropertyChanged 를 통해 속성의 변경을 Update 하라고 XAML 에 알린다.
XAML 은 해당 속성에 맞는 {Binding xxxx} 를 update 시켜 화면을 갱신한다.
실행
관련영상
'MAUI' 카테고리의 다른 글
.NET MAUI - Binding Value Converters (0) | 2022.07.28 |
---|---|
.NET MAUI - Binding 경로 (Path) (0) | 2022.07.27 |
.NET MAUI - Binding 기본 (0) | 2022.07.25 |
.NET MAUI - XAML stack navigation (0) | 2022.07.22 |
NET MAUI - XAML tab navigation (0) | 2022.07.21 |