綁定和自定義視圖
在第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不支援“多重綁定”,可能允許組合多個綁定源來更改單個綁定目标。 綁定可以做很多事情,但是如果沒有一些額外的代碼支援,它們就無法做到。
代碼仍有作用。