一个Color ViewModel
Color始终提供了探索图形用户界面功能的好方法,因此您可能不会惊讶于Xamarin.FormsBook.Toolkit库包含一个名为ColorViewModel的类。
ColorViewModel类公开Color属性,但也显示Red,Green,Blue,Alpha,Hue,Saturation和Luminosity属性,所有这些属性都是可单独设置的。这不是Xamarin.Form Color结构提供的功能。从Color构造函数或Color中的其中一个方法创建Color值时,以Add,From,Multiply或With开头,它是不可变的。
ColorViewModel类因其Color属性和所有组件属性的相互关系而变得复杂。例如,假设已设置Color属性。该类应该不仅为Color而且还为任何也发生变化的组件(如Red或Hue)触发PropertyChanged处理程序。同样,如果Red属性发生变化,那么该类应该为Red和Color以及可能的Hue,Saturation和Luminosity触发PropertyChanged事件。
ColorViewModel类通过仅为Color属性存储支持字段来解决此问题。通过调用Color.FromRgba或Color.FromHsla使用传入值,各个组件的所有Set访问器都会创建一个新Color。此新Color值设置为Color属性而不是Color字段,这意味着新Color值将在Color属性的Set访问器中进行处理:
-
public class ColorViewModel : INotifyPropertyChanged
-
{
-
Color color;
-
public event PropertyChangedEventHandler PropertyChanged;
-
public double Red
-
{
-
set
-
{
-
if (Round(color.R) != value)
-
Color = Color.FromRgba(value, color.G, color.B, color.A);
-
}
-
get
-
{
-
return Round(color.R);
-
}
-
}
-
public double Green
-
{
-
set
-
{
-
if (Round(color.G) != value)
-
Color = Color.FromRgba(color.R, value, color.B, color.A);
-
}
-
-
get
-
{
-
return Round(color.G);
-
}
-
}
-
public double Blue
-
{
-
set
-
{
-
if (Round(color.B) != value)
-
Color = Color.FromRgba(color.R, color.G, value, color.A);
-
}
-
get
-
{
-
return Round(color.B);
-
}
-
}
-
public double Alpha
-
{
-
set
-
{
-
if (Round(color.A) != value)
-
Color = Color.FromRgba(color.R, color.G, color.B, value);
-
}
-
get
-
{
-
return Round(color.A);
-
}
-
}
-
public double Hue
-
{
-
set
-
{
-
if (Round(color.Hue) != value)
-
Color = Color.FromHsla(value, color.Saturation, color.Luminosity, color.A);
-
}
-
get
-
{
-
return Round(color.Hue);
-
}
-
}
-
public double Saturation
-
{
-
set
-
{
-
if (Round(color.Saturation) != value)
-
Color = Color.FromHsla(color.Hue, value, color.Luminosity, color.A);
-
}
-
get
-
{
-
return Round(color.Saturation);
-
}
-
}
-
public double Luminosity
-
{
-
set
-
{
-
if (Round(color.Luminosity) != value)
-
Color = Color.FromHsla(color.Hue, color.Saturation, value, color.A);
-
}
-
get
-
{
-
return Round(color.Luminosity);
-
}
-
}
-
public Color Color
-
{
-
set
-
{
-
Color oldColor = color;
-
if (color != value)
-
{
-
color = value;
-
OnPropertyChanged("Color");
-
}
-
if (color.R != oldColor.R)
-
OnPropertyChanged("Red");
-
if (color.G != oldColor.G)
-
OnPropertyChanged("Green");
-
if (color.B != oldColor.B)
-
OnPropertyChanged("Blue");
-
if (color.A != oldColor.A)
-
OnPropertyChanged("Alpha");
-
if (color.Hue != oldColor.Hue)
-
OnPropertyChanged("Hue");
-
if (color.Saturation != oldColor.Saturation)
-
OnPropertyChanged("Saturation");
-
if (color.Luminosity != oldColor.Luminosity)
-
OnPropertyChanged("Luminosity");
-
}
-
get
-
{
-
return color;
-
}
-
}
-
protected void OnPropertyChanged(string propertyName)
-
{
-
PropertyChangedEventHandler handler = PropertyChanged;
-
if (handler != null)
-
{
-
handler(this, new PropertyChangedEventArgs(propertyName));
-
}
-
}
-
double Round(double value)
-
{
-
return Device.OnPlatform(value, Math.Round(value, 3), value);
-
}
-
}
Color属性的Set访问器负责根据属性的更改来触发所有PropertyChanged事件。
请注意类底部的设备相关Round方法及其在set中的使用以及前七个属性的get访问器。 当第23章“触发器和行为”中的MultiColorSliders示例显示出问题时,会添加此项。 Android似乎在内部舍入颜色组件,导致传递给它的属性之间的不一致Color.FromRgba和Color.FromHsla方法以及由此产生的Color值的属性,从而导致无限集和get循环。
HslSliders程序在Grid.BindingContext标记之间实例化ColorViewModel,使其成为Grid中所有Slider和Label元素的BindingContext:
-
<ContentPage xmlns=""
-
xmlns:x=""
-
xmlns:toolkit=
-
"clr-namespace:Xamarin.FormsBook.Toolkit;assembly=Xamarin.FormsBook.Toolkit"
-
x:Class="HslSliders.HslSlidersPage"
-
SizeChanged="OnPageSizeChanged">
-
-
<ContentPage.Padding>
-
<OnPlatform x:TypeArguments="Thickness"
-
iOS="0, 20, 0, 0" />
-
</ContentPage.Padding>
-
<Grid x:Name="mainGrid">
-
<Grid.BindingContext>
-
<toolkit:ColorViewModel Color="Gray" />
-
</Grid.BindingContext>
-
<Grid.Resources>
-
<ResourceDictionary>
-
<Style TargetType="Label">
-
<Setter Property="FontSize" Value="Large" />
-
<Setter Property="HorizontalTextAlignment" Value="Center" />
-
</Style>
-
</ResourceDictionary>
-
</Grid.Resources>
-
<!-- Initialized for portrait mode. -->
-
<Grid.RowDefinitions>
-
<RowDefinition Height="*" />
-
<RowDefinition Height="Auto" />
-
</Grid.RowDefinitions>
-
<Grid.ColumnDefinitions>
-
<ColumnDefinition Width="*" />
-
<ColumnDefinition Width="0" />
-
</Grid.ColumnDefinitions>
-
<BoxView Color="{Binding Color}"
-
Grid.Row="0" Grid.Column="0" />
-
<StackLayout x:Name="controlPanelStack"
-
Grid.Row="1" Grid.Column="0"
-
Padding="10, 5">
-
-
<StackLayout VerticalOptions="CenterAndExpand">
-
<Slider Value="{Binding Hue}" />
-
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
-
</StackLayout>
-
<StackLayout VerticalOptions="CenterAndExpand">
-
<Slider Value="{Binding Saturation}" />
-
<Label Text="{Binding Saturation,StringFormat='Saturation = {0:F2}'}" />
-
</StackLayout>
-
<StackLayout VerticalOptions="CenterAndExpand">
-
<Slider Value="{Binding Luminosity}" />
-
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
-
</StackLayout>
-
</StackLayout>
-
</Grid>
-
</ContentPage>
请注意,实例化ColorViewModel时,ColorViewModel的Color属性已初始化。 然后滑块的双向绑定将获取Hue,Saturation和Luminosity属性的结果值。
如果您想要实现红色,绿色和蓝色的十六进制值的显示,则可以使用与前一章中的GridRgbSliders程序相关的DoubleToIntConverter类。
HslSliders程序实现了与纵向和横向模式之间切换相同的技术,如GridRgbSliders程序。 代码隐藏文件处理此开关的机制:
这个代码隐藏文件不像只调用InitializeComponent的文件那么漂亮,但即使在MVVM的上下文中,纵向和横向模式之间的切换也是代码隐藏文件的合法使用,因为它仅用于 用户界面而不是底层业务逻辑。
这是HslSliders计划的实际应用:
阅读(4348) | 评论(0) | 转发(0) |