第八章:代码和XAML协调一致(3)

简介:

自定义基于XAML的视图

上一章中的ScaryColorList程序使用Frame,BoxView和Label在StackLayout中列出了一些颜色。即使只有三种颜色,重复标记也开始变得非常不祥。遗憾的是,没有XAML标记复制C#for和while循环,因此您可以选择使用代码生成多个类似的项目,或者在标记中找到更好的方法。
在本书中,您将看到几种在XAML中列出颜色的方法,最终,一种非常干净和优雅的方式来完成这项工作将变得清晰。但这需要更多的步骤来学习Xamarin.Forms。在此之前,我们将研究一些您可能会在类似情况下发现有用的其他方法。
一种策略是创建一个自定义视图,其唯一目的是显示带有名称和彩色框的颜色。当我们在它的时候,让我们也显示颜色的十六进制RGB值。然后,您可以在XAML页面文件中将该自定义视图用于各个颜色。
在XAML中,对这样的自定义视图的引用可能是什么样的?
或者更好的问题是:你想看它怎么样?
如果标记看起来像这样,那么重复一点也不差,并且比在代码中明确定义Color值数组更糟糕:

<StackLayout>
    <MyColorView Color="Red" />
    <MyColorView Color="Green" />
    <MyColorView Color="Blue" />

</StackLayout>

嗯,实际上,它看起来不会那样。 MyColorView显然是一个自定义类,不是Xamarin.Forms API的一部分。 因此,如果没有XML名称空间声明中定义的名称空间前缀,它就不会出现在XAML文件中。
应用此XML前缀后,对于此自定义视图是Xamarin.Forms API的一部分不会有任何混淆,所以让我们给它一个更加尊严的ColorView名称而不是MyColorView。
这个假设的ColorView类是一个相当简单的自定义视图的示例,因为它仅包含使用StackLayout以特定方式排列的现有视图(特别是Label,Frame和BoxView)。 Xamarin.Forms定义了一个专门用于为这种视图排列提供父母的视图,它被称为ContentView。与ContentPage类似,ContentView具有一个Con?tent属性,您可以将其设置为其他视图的可视树。您可以在代码中定义Con?tentView的内容,但在XAML中执行它更有趣。
让我们整理一个名为ColorViewList的解决方案。此解决方案将具有两组XAML和代码隐藏文件,第一个用于名为ColorViewListPage的类,它派生自ContentPage(通常),第二个用于派生自ContentView的名为ColorView的类。
要在Visual Studio中创建ColorView类,请使用与向ColorViewList项目添加新XAML页面时相同的过程:在解决方案资源管理器中右键单击项目名称,然后从上下文菜单中选择“添加”>“新建项”。在Add New Item对话框中,选择左侧的Visual C#> Cross-Platform,然后选择Forms Xaml Page。输入名称ColorView.cs。但是,在您忘记之前,立即进入ColorView.xaml文件并将ContentPage开始和结束标记更改为ContentView。在ColorView.xaml.cs文件中,将基类更改为ContentView。
在Xamarin Studio中,这个过程稍微容易一些。从ColorViewList项目的工具菜单中,选择“添加”>“新建文件”。在“新建文件”对话框中,选择左侧的“表单”和“表单ContentView Xaml”(不是“表单ContentPage Xaml”)。给它一个ColorView的名字。
您还需要像往常一样为ColorViewListPage类创建XAML文件和代码隐藏文件。
ColorView.xaml文件描述了各个颜色项的布局,但没有任何实际颜色值。相反,BoxView和两个Label视图的名称是:

<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ColorViewList.ColorView">
    <Frame OutlineColor="Accent">
        <StackLayout Orientation="Horizontal">
            <BoxView x:Name="boxView"
                     WidthRequest="70"
                     HeightRequest="70" />
            <StackLayout>
                <Label x:Name="colorNameLabel"
                       FontSize="Large"
                       VerticalOptions="CenterAndExpand" />
 
                <Label x:Name="colorValueLabel"
                       VerticalOptions="CenterAndExpand" />
            </StackLayout>
        </StackLayout>
    </Frame>
</ContentView>

在现实生活中,您将有足够的时间来微调视觉效果。最初,您只想在那里获取所有命名视图。
除了视觉效果,此ColorView类还需要一个新属性来设置颜色。必须在代码隐藏文件中定义此属性。首先,为ColorView提供一个名为Color of Color的属性似乎是合理的(因为MyColorView的早期XAML片段似乎暗示)。但ColorView类需要显示颜色名称,并且无法从Color值中获取颜色名称。
相反,定义名为ColorName的类型为string的属性更有意义。然后,代码?后面的文件可以使用反射来获取与该名称对应的Color类的静态字段。
但是等待:Xamarin.Forms包含一个公共ColorTypeConverter类,XAML解析器使用该类将“Red”或“Blue”等文本颜色名称转换为Color值。为什么不利用这个呢?
这是ColorView的代码隐藏文件。它定义了一个带有set访问器的ColorName属性,该属性将colorNameLabel的Text属性设置为颜色名称,然后使用ColorType?Converter将名称转换为Color值。然后使用此Color值将boxView的Color属性和colorValueLabel的Text属性设置为RGB值:

public partial class ColorView : ContentView
{
    string colorName;
    ColorTypeConverter colorTypeConv = new ColorTypeConverter();
    public ColorView()
    {
        InitializeComponent();
    }
    public string ColorName
    {
        set
        {
            // Set the name.
            colorName = value;
            colorNameLabel.Text = value;
            // Get the actual Color and set the other views.
            Color color = (Color)colorTypeConv.ConvertFrom(colorName);
            boxView.Color = color;
            colorValueLabel.Text = String.Format("{0:X2}-{1:X2}-{2:X2}",
                                                 (int)(255 * color.R), 
                                                 (int)(255 * color.G), 
                                                 (int)(255 * color.B));
        }
        get
        {
            return colorName;
        }
    }
}

ColorView类已完成。 现在让我们看一下ColorViewListPage。 ColorViewList?Page.xaml文件必须列出多个ColorView实例,因此它需要一个带有新名称空间前缀的新XML名称空间声明来引用ColorView元素。
ColorView类与ColorViewListPage属于同一个项目。 通常,程序员在这种情况下使用本地的XML名称空间前缀。 新的名称空间声明出现在XAML文件的根元素中(与其他两个一样),格式如下:

xmlns:local="clr-namespace:ColorViewList;assembly=ColorViewList"

在一般情况下,XAML的自定义XML名称空间声明必须指定公共语言运行时(CLR)名称空间(也称为.NET名称空间)和程序集。指定这些的关键字是clr-namespace和assembly。通常,CLR命名空间与组件相同,就像它们在这种情况下一样,但它们不需要。这两部分用分号连接。
请注意,冒号跟在clr-namespace之后,但是在程序集之后有一个等号。这种明显的不一致是有意的:名称空间声明的格式旨在模仿传统名称空间声明中的URI,其中冒号遵循URI方案名称。
您使用相同的语法来引用外部可移植类库中的对象。在这些情况下唯一不同的是项目还需要参考外部PCL。 (您将在第10章“XAML标记扩展”中看到一个考试。)。
本地前缀对于同一程序集中的代码是通用的,在这种情况下,不需要组装部件:

xmlns:local="clr-namespace:ColorViewList"

对于PCL中的XAML文件,如果需要,可以包括装配部件以引用与?装配相同的内容,但不是必需的。 但是,对于SAP中的XAML文件,您不得包含程序集部件以引用本地类,因为没有与SAP关联的程序集。 SAP中的代码实际上是各个平台程序集的一部分,并且这些代码都具有不同的名称。
这是ColorViewListPage类的XAML。 代码隐藏文件除了InitializeComponent调用之外什么都不包含:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:ColorViewList"
             x:Class="ColorViewList.ColorViewListPage">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness"
                    iOS="0, 20, 0, 0" />
    </ContentPage.Padding>
    <ScrollView>
        <StackLayout Padding="6, 0">
            <local:ColorView ColorName="Aqua" /> 
            <local:ColorView ColorName="Black" /> 
            <local:ColorView ColorName="Blue" />
            <local:ColorView ColorName="Fuchsia" />
            <local:ColorView ColorName="Gray" />
            <local:ColorView ColorName="Green" />
            <local:ColorView ColorName="Lime" />
            <local:ColorView ColorName="Maroon" />
            <local:ColorView ColorName="Navy" />
            <local:ColorView ColorName="Olive" />
            <local:ColorView ColorName="Purple" />
            <local:ColorView ColorName="Pink" />
            <local:ColorView ColorName="Red" />
            <local:ColorView ColorName="Silver" />
            <local:ColorView ColorName="Teal" />
            <local:ColorView ColorName="White" />
            <local:ColorView ColorName="Yellow" />
        </StackLayout>
    </ScrollView>
</ContentPage>

这并不像前面的例子所暗示的那样令人厌恶,它演示了如何将视觉效果封装在他们自己的基于XAML的类中。 请注意,StackLayout是ScrollView的子项,因此可以滚动列表:
201807081512110348
但是,ColorViewList项目的一个方面不符合“最佳实践”。它是ColorView中ColorName属性的定义。 这应该实现为BindableProperty对象。 深入研究可绑定对象和可绑定属性是一个高优先级,将在第11章“可绑定基础结构”中进行探讨。

目录
相关文章
|
3月前
|
容器 C# 开发者
XAML语言大揭秘:WPF标记的魅力所在,让你轻松实现界面与逻辑分离,告别复杂代码!
【8月更文挑战第31天】XAML提供了一种直观且易于维护的界面设计方式,使得开发者可以专注于逻辑和业务代码的编写,而无需关心界面细节。通过数据绑定、布局管理和动画效果等特性,XAML可以实现丰富的界面交互和视觉效果。在实际开发过程中,开发者应根据具体需求选择合适的技术方案,以确保应用程序能够满足用户的需求。希望本文的内容能够帮助您在WPF应用程序开发中更好地利用XAML语言。
44 0
|
C#
艾伟_转载:WPF/Silverlight陷阱:XAML自定义控件的嵌套内容无法通过名称访问
为了说明这个问题,假定我们需要实现一个具有特殊功能的按钮控件。编写Xaml文件如下: Button> 对 Code Behind类,唯一的改动是把向导生成的基类从UserControl改成Button: public partial class XamlButton : Button{    ...
1076 0
|
JavaScript Android开发 索引
第八章:代码和XAML协调一致5
点按手势 Xamarin.Forms按钮响应手指点击,但您实际上可以从任何派生自View的类中获取手指点击,包括Label,BoxView和Frame。 这些点击事件不会内置到View类中,但View类会定义名为GestureRecognizers的属性。
1326 0
|
JavaScript Android开发 iOS开发
|
JavaScript API Android开发
|
JavaScript Android开发
|
JavaScript Android开发 iOS开发
|
XML JavaScript C#
第七章:XAML vs. code(3)
属性元素语法这里有一些C#与第4章中的FramedText代码相似。在一个语句中,它实例化一个Frame和一个Label,并将Label设置为Frame的Content属性: new Frame { OutlineColor = Color.
910 0