第十六章:数据绑定(八)
绑定和自定义视图
在第15章“交互式界面”中,您看到了一个名为CheckBox的自定义视图。此视图定义Text属性,用于设置CheckBox的文本以及FontSize属性。它也可以定义所有其他与文本相关的属性-TextColor,FontAttributes和FontFamily-但它
没有,主要是因为所涉及的工作。每个属性都需要一个BindableProperty定义,一个CLR属性定义和一个属性更改处理程序,它将属性的新设置传递给包含CheckBox视觉效果的Label视图。
通过消除propertychanged处理程序,数据绑定可以帮助简化某些属性的此过程。这是一个名为NewCheckBox的新版CheckBox的代码隐藏文件。与早期的类一样,它是Xamarin.FormsBook.Toolkit库的一部分。该文件已重新组织一点,以便每个BindableProperty定义与其对应的CLR属性定义配对。您可能更喜欢这种属性的源代码组织,或者可能不喜欢。
namespace Xamarin.FormsBook.Toolkit
{
public partial class NewCheckBox : ContentView
{
public event EventHandler<bool> CheckedChanged;
public NewCheckBox()
{
InitializeComponent();
}
// Text property.
public static readonly BindableProperty TextProperty =
BindableProperty.Create(
"Text",
typeof(string),
typeof(NewCheckBox),
null);
public string Text
{
set { SetValue(TextProperty, value); }
get { return (string)GetValue(TextProperty); }
}
// TextColor property.
public static readonly BindableProperty TextColorProperty =
BindableProperty.Create(
"TextColor",
typeof(Color),
typeof(NewCheckBox),
Color.Default);
public Color TextColor
{
set { SetValue(TextColorProperty, value); }
get { return (Color)GetValue(TextColorProperty); }
}
// FontSize property.
public static readonly BindableProperty FontSizeProperty =
BindableProperty.Create(
"FontSize",
typeof(double),
typeof(NewCheckBox),
Device.GetNamedSize(NamedSize.Default, typeof(Label)));
[TypeConverter(typeof(FontSizeConverter))]
public double FontSize
{
set { SetValue(FontSizeProperty, value); }
get { return (double)GetValue(FontSizeProperty); }
}
// FontAttributes property.
public static readonly BindableProperty FontAttributesProperty =
BindableProperty.Create(
"FontAttributes",
typeof(FontAttributes),
typeof(NewCheckBox),
FontAttributes.None);
public FontAttributes FontAttributes
{
set { SetValue(FontAttributesProperty, value); }
get { return (FontAttributes)GetValue(FontAttributesProperty); }
}
// IsChecked property.
public static readonly BindableProperty IsCheckedProperty =
BindableProperty.Create(
"IsChecked",
typeof(bool),
typeof(NewCheckBox),
false,
propertyChanged: (bindable, oldValue, newValue) =>
{
// Fire the event.
NewCheckBox checkbox = (NewCheckBox)bindable;
EventHandler<bool> eventHandler = checkbox.CheckedChanged;
if (eventHandler != null)
{
eventHandler(checkbox, (bool)newValue);
}
});
public bool IsChecked
{
set { SetValue(IsCheckedProperty, value); }
get { return (bool)GetValue(IsCheckedProperty); }
}
// TapGestureRecognizer handler.
void OnCheckBoxTapped(object sender, EventArgs args)
{
IsChecked = !IsChecked;
}
}
}
除了早期的Text和FontSize属性,此代码文件现在还定义了TextColor和FontAttributes属性。 但是,唯一的属性更改处理程序是IsChecked处理程序触发CheckedChanged事件。 其他所有内容都由XAML文件中的数据绑定处理:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:toolkit="clr-namespace:Xamarin.FormsBook.Toolkit"
x:Class="Xamarin.FormsBook.Toolkit.NewCheckBox"
x:Name="checkbox">
<StackLayout Orientation="Horizontal"
BindingContext="{x:Reference checkbox}">
<Label x:Name="boxLabel" Text="☐"
TextColor="{Binding TextColor}"
FontSize="{Binding FontSize}">
<Label.Text>
<Binding Path="IsChecked">
<Binding.Converter>
<toolkit:BoolToStringConverter TrueText="☑"
FalseText="☐" />
</Binding.Converter>
</Binding>
</Label.Text>
</Label>
<Label x:Name="textLabel" Text="{Binding Path=Text}"
TextColor="{Binding TextColor}"
FontSize="{Binding FontSize}"
FontAttributes="{Binding FontAttributes}" />
</StackLayout>
<ContentView.GestureRecognizers>
<TapGestureRecognizer Tapped="OnCheckBoxTapped" />
</ContentView.GestureRecognizers>
</ContentView>
root元素的名称为checkbox,StackLayout将其设置为BindingContext。然后,该StackLayout中的所有数据绑定都可以引用代码隐藏文件定义的属性。显示该框的第一个Label将其TextColor和FontSize属性绑定到基础属性的值,而Text属性则通过绑定来定位
使用BoolToStringConverter根据IsChecked属性显示空框或复选框。第二个Label更直接:Text,TextColor,FontSize和FontAttributes属性都绑定到代码隐藏文件中定义的相应属性。
如果您要创建包含Text元素的多个自定义视图,并且需要定义所有与文本相关的属性,那么您可能希望首先创建一个仅从CodeView派生的代码类(例如,名为CustomViewBase),仅包括那些基于文本的属性定义。然后,您可以从CustomViewBase派生其他类,并且可以使用Text和所有与文本相关的属性。
让我们编写一个名为NewCheckBoxDemo的小程序来演示NewCheckBox视图。与早期的CheckBoxDemo程序一样,这些复选框控制一段文本的粗体和斜体格式。但为了演示新属性,这些复选框被赋予颜色和字体属性,为了演示BoolToObjectConverter,其中一个复选框控制该段落的水平对齐:
<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="NewCheckBoxDemo.NewCheckBoxDemoPage">
<StackLayout Padding="10, 0">
<StackLayout HorizontalOptions="Center"
VerticalOptions="CenterAndExpand">
<StackLayout.Resources>
<ResourceDictionary>
<Style TargetType="toolkit:NewCheckBox">
<Setter Property="FontSize" Value="Large" />
</Style>
</ResourceDictionary>
</StackLayout.Resources>
<toolkit:NewCheckBox Text="Italic"
TextColor="Aqua"
FontSize="Large"
FontAttributes="Italic"
CheckedChanged="OnItalicCheckBoxChanged" />
<toolkit:NewCheckBox Text="Boldface"
FontSize="Large"
TextColor="Green"
FontAttributes="Bold"
CheckedChanged="OnBoldCheckBoxChanged" />
<toolkit:NewCheckBox x:Name="centerCheckBox"
Text="Center Text" />
</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"
VerticalOptions="CenterAndExpand">
<Label.HorizontalTextAlignment>
<Binding Source="{x:Reference centerCheckBox}"
Path="IsChecked">
<Binding.Converter>
<toolkit:BoolToObjectConverter x:TypeArguments="TextAlignment"
TrueObject="Center"
FalseObject="Start" />
</Binding.Converter>
</Binding>
</Label.HorizontalTextAlignment>
</Label>
</StackLayout>
</ContentPage>
注意Binding.Converter标记之间的BoolToObjectConverter。 因为它是泛型类,所以它需要一个x:TypeArguments属性,该属性指示TrueObject和FalseObject属性的类型以及Convert方法的返回值的类型。 TrueObject和FalseObject都设置为TextAlignment枚举的成员,转换器选择一个设置为Label的HorizontalTextAlignment属性,如以下屏幕截图所示:
但是,此程序仍需要一个代码隐藏文件来管理将斜体和粗体属性应用于文本块。 这些方法与早期CheckBoxDemo程序中的方法相同:
public partial class NewCheckBoxDemoPage : ContentPage
{
public NewCheckBoxDemoPage()
{
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;
}
}
}
Xamarin.Forms不支持“多重绑定”,可能允许组合多个绑定源来更改单个绑定目标。 绑定可以做很多事情,但是如果没有一些额外的代码支持,它们就无法做到。
代码仍有作用。