传统的CheckBox
在更传统的图形环境中,允许用户选择布尔值的用户界面对象称为CheckBox,通常具有一些文本,其中的框可以为空或填充X或复选标记。 CheckBox优于Switch的一个优点是文本标识符是visual的一部分,不需要添加单独的Label。
在Xamarin.Forms中创建自定义视图的一种方法是编写特定于每个平台的渲染器的特殊类,并在每个平台中引用视图。第27章对此进行了论证。
但是,也可以通过组合来自其他视图的视图在Xamarin.Forms中创建自定义视图。首先从ContentView派生一个类,将其Content属性设置为StackLayout(例如),然后在其上添加一个或多个视图。 (您在第8章的ColorView类中看到了这种技术的示例。)您可能还需要定义一个或多个属性,并且可能需要一些事件,但您将希望利用已建立的可绑定基础结构由BindableObject和BindableProperty类。这样可以对属性进行样式设置并成为数据绑定的目标。
CheckBox只包含ContentView上的两个Label元素:一个Label显示与CheckBox关联的texta,另一个显示一个框。 TapGestureRecognizer检测何时点击CheckBox。
CheckBox类已添加到Xamarin.FormsBook.Toolkit库中,该库包含在本书的可下载代码中。以下是您自己做的方法:
在Visual Studio中,您可以从“添加新项”对话框中选择“表单Xaml页”。但是,当您真正想要一个派生自Con?tentView的类时,这将创建一个派生自ContentPage的类。只需将XAML文件的根元素从ContentPage更改为ContentView,并将代码隐藏文件中的基类从ContentPage更改为ContentView。
但是,在Xamarin Studio中,您只需从“新建文件”对话框中选择“表单ContentView Xaml”即可。
这是CheckBox.xaml文件:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Xamarin.FormsBook.Toolkit.CheckBox">
<StackLayout Orientation="Horizontal">
<Label x:Name="boxLabel" Text="☐" />
<Label x:Name="textLabel" />
</StackLayout>
<ContentView.GestureRecognizers>
<TapGestureRecognizer Tapped="OnCheckBoxTapped" />
</ContentView.GestureRecognizers>
</ContentView>
那个Unicode字符称为投票箱字符,它只是一个空方块。 字符 u2611是带支票的投票箱,而 u2612是带X的投票箱。为了表示已检查状态,此CheckBox代码隐藏文件将boxLabel的Text属性设置为 u2611(您很快就会看到)。
CheckBox的代码隐藏文件定义了三个属性:
- Text
- FontSize
- IsChecked
CheckBox还定义了一个名为IsCheckedChanged的事件。
CheckBox还应该像Label和But?那样定义FontAttributes和FontFamily属性吗? 也许,但这些额外的属性对于专注于用户的视图并不十分重要。
CheckBox定义的所有三个属性都由可绑定属性支持。 code-be?hind文件创建所有三个BindableProperty对象,属性更改的处理程序在这些方法中定义为lambda函数。
请记住,属性更改的处理程序是静态的,因此需要将第一个参数强制转换为CheckBox对象,以引用类中的实例属性和事件。 IsChecked的属性?更改处理程序负责更改表示已检查和未检查状态的字符并触发IsCheckedChanged事件:
namespace Xamarin.FormsBook.Toolkit
{
public partial class CheckBox : ContentView
{
public static readonly BindableProperty TextProperty =
BindableProperty.Create(
"Text",
typeof(string),
typeof(CheckBox),
null,
propertyChanged: (bindable, oldValue, newValue) =>
{
((CheckBox)bindable).textLabel.Text = (string)newValue;
});
public static readonly BindableProperty FontSizeProperty =
BindableProperty.Create(
"FontSize",
typeof(double),
typeof(CheckBox),
Device.GetNamedSize(NamedSize.Default, typeof(Label)),
propertyChanged: (bindable, oldValue, newValue) =>
{
CheckBox checkbox = (CheckBox)bindable;
checkbox.boxLabel.FontSize = (double)newValue;
checkbox.textLabel.FontSize = (double)newValue;
});
public static readonly BindableProperty IsCheckedProperty =
BindableProperty.Create(
"IsChecked",
typeof(bool),
typeof(CheckBox),
false,
propertyChanged: (bindable, oldValue, newValue) =>
{
// Set the graphic.
CheckBox checkbox = (CheckBox)bindable;
checkbox.boxLabel.Text = (bool)newValue ? "\u2611" : "\u2610";
// Fire the event.
EventHandler<bool> eventHandler = checkbox.CheckedChanged;
if (eventHandler != null)
{
eventHandler(checkbox, (bool)newValue);
}
});
public event EventHandler<bool> CheckedChanged;
public CheckBox()
{
InitializeComponent();
}
public string Text
{
set { SetValue(TextProperty, value); }
get { return (string)GetValue(TextProperty); }
}
[TypeConverter(typeof(FontSizeConverter))]
public double FontSize
{
set { SetValue(FontSizeProperty, value); }
get { return (double)GetValue(FontSizeProperty); }
}
public bool IsChecked
{
set { SetValue(IsCheckedProperty, value); }
get { return (bool)GetValue(IsCheckedProperty); }
}
// TapGestureRecognizer handler.
void OnCheckBoxTapped(object sender, EventArgs args)
{
IsChecked = !IsChecked;
}
}
}
注意FontSize属性上的TypeConverter。 这允许在XAML中使用诸如“Small”和“Large”之类的属性值设置属性。
TapGestureRecognizer的Tapped处理程序位于类的底部,只需使用C#逻辑否定运算符来填充IsChecked属性。 切换布尔变量的更短语句使用异或赋值运算符:
IsChecked ^= true;
CheckBoxDemo程序与SwitchDemo程序非常相似,只是标记大大简化,因为CheckBox包含自己的Text属性:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit=
"clr-namespace:Xamarin.FormsBook.Toolkit;assembly=Xamarin.FormsBook.Toolkit"
x:Class="CheckBoxDemo.CheckBoxDemoPage">
<StackLayout Padding="10, 0">
<StackLayout HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<toolkit:CheckBox Text="Italic"
FontSize="Large"
CheckedChanged="OnItalicCheckBoxChanged" />
<toolkit:CheckBox Text="Boldface"
FontSize="Large"
CheckedChanged="OnBoldCheckBoxChanged" />
</StackLayout>
<Label x:Name="label"
Text=
"Just a little passage of some sample text that can be formatted
in italic or boldface by toggling the two custom CheckBox views."
FontSize="Large"
HorizontalTextAlignment="Center"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage>
代码隐藏文件也与早期的程序非常相似:
public partial class CheckBoxDemoPage : ContentPage
{
public CheckBoxDemoPage()
{
InitializeComponent();
}
void OnItalicCheckBoxChanged(object sender, bool isChecked)
{
if (isChecked)
{
label.FontAttributes |= FontAttributes.Italic;
}
else
{
label.FontAttributes &= ~FontAttributes.Italic;
}
}
void OnBoldCheckBoxChanged(object sender, bool isChecked)
{
if (isChecked)
{
label.FontAttributes |= FontAttributes.Bold;
}
else
{
label.FontAttributes &= ~FontAttributes.Bold;
}
}
}
有趣的是,复选框的字符在Android和Windows平台上显示为彩色: