In the previous post on making fancy layouts with Xamarin Forms we saw how you can design a Dashboard style application that stretches to fill any device size. However one of the challenges of the particular design we chose for Falafel 2 Go was the need to support the concept of an Image Button, where both the icon and the text work as a single control to launch an activity.

Xamarin Forms does provide an ImageCell control, which can be used in a TableView to render both text and image as a single control. However, this control is laid out horizontally with the text positioned on the right side of the image as you would expect for a list of items.

While we could likely acheive a more precise layout with a custom renderer, we found a much more elegnat, and more importantly, reusable option by instead creating a User Control.

XAML User Controls

The concept of User Controls is not new, and exists in many different platforms including Silverlight, XAML for Windows and Windows Phone as well as Web Forms. Basically the idea is to create a small container for a collection of controls that will be reused as a single control throughout the application. The User Control exposes properties allowing you to reuse the control while allowing each instance of the control to have different settings, layout, or behavior.

Because User Controls are so useful (and simple to create) on other platforms, we were pleased and relieved to discover that Xamarin Forms supports them as well. While we weren’t able to find any documentation on the matter, with some experimentation we discovered the solution below. If there are official docs for this, please let me know in the comments so I can link to them!

Creating the Xamarin Forms User Control

Begin by adding a regular Xamarin Forms XAML Control to the project. By default this creates a ContentPage. For our layout, we want the image and text to flow vertically, so it makes sense to use a StackLayout, which is why we named the control StackLayoutButton. We can then change the XAML so that the control is also a StackLayout, as shown in the complete example later in the post.

In addition, the code-behind class by default doesn’t inherit from any base class. Usually you would modify this to be a ContentPage to both match the XAML definition as well as expose the properties and methods of the base control. However, because we’re using a StackLayout, we simply needed to update this to inherit from that control. This is also shown later in the full code-behind snippet.

By changing the class of the control we can proceed to add additional XAML controls to the StackLayout to make up the overall User Control. In this case we’re adding both the Image and Label controls as shown in the complete code below, completing the self-contained StackLayoutButton. Notice that we can define the properties for each control so that they are global to all instances of the button, eliminating the need to set them over and over for each one.

But what if we want to vary the properties on a specific control?

Accessing Child Controls and Properties

Because the individual controls are defined inside the StackLayout, we don’t have direct access to them from the User Control when we add them to the main page. However, we can workaround this by adding get and set properties to the StackLayoutButton which expose either the individual properties of a control, or the entire control itself.

If you review the full code of the StackLayoutButton code-behind below, you see that we’ve created two additional public properties. The TextColor sets or returns the value of the Label property so it can be set at the UserControl level. The other Label control returns the actual Label itself, so that we could potentially access and modify any property of that control.

This is demonstrated in the code-behind for the ActivitesPage control, where we access an instance of the StackLayoutButton by name, and can then access theTextControl property to set the BackgroundColor of that control.

Here’s what the final example page looks like. We’ve combined the two options to change both the Font color and the BackgroundColor using the exposed properties for specific buttons.

At last, here are the complete code samples for the controls, starting with the XAML for the StackLayoutButton:

<?xml version=“1.0” encoding=“utf-8” ?>
<StackLayout xmlns=“http://xamarin.com/schemas/2014/forms”
xmlns:common=“clr-namespace:Falafel2GoV2.Common;assembly=Falafel2GoV2”
xmlns:x=“http://schemas.microsoft.com/winfx/2009/xaml”
x:Class=“Falafel2GoV2.Controls.StackLayoutButton“>
<Image x:Name=“Icon” Source=“{Binding Icon}” />
<Label x:Name=“Text” Text=“{Binding Title}” HorizontalOptions=“Center” LineBreakMode=“NoWrap” Font=“Small” TextColor=“{x:Static common:ColorResources.ListTitle}” />
</StackLayout>

The StackLayoutButton code-behind:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;namespace Falafel2GoV2.Controls
{
public partial class StackLayoutButton : StackLayout
{
public Color TextColor
{
get { return this.Text.TextColor; }
set { this.Text.TextColor = value; }
}public Label TextControl
{
get { return this.Text; }
set { this.Text = value; }
}public StackLayoutButton()
{
InitializeComponent();
}
}
}

The ActivitiesView XAML:

<?xml version=“1.0” encoding=“UTF-8“?>
<ContentPage xmlns=“http://xamarin.com/schemas/2014/forms”
xmlns:x=“http://schemas.microsoft.com/winfx/2009/xaml”
xmlns:common=“clr-namespace:Falafel2GoV2.Common;assembly=Falafel2GoV2”
xmlns:controls=“clr-namespace:Falafel2GoV2.Controls;assembly=Falafel2GoV2”
x:Class=“Falafel2GoV2.Views.ActivitiesPage”
Title=“{Binding ViewName}”
BackgroundImage=“mainBack.png“>
<ContentPage.Content>
<StackLayout Orientation=“Vertical” Padding=“{x:Static common:PaddingResources.MainBody}“>
<Label Text=“{Binding ViewName}” Font=“42” IsVisible=“{Binding IsWindowsPhone}” />
<ActivityIndicator IsRunning=“{Binding IsLoading}” IsVisible=“{Binding IsLoading}” Color=“{x:Static common:ColorResources.ActivityIndicator}” /><Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=“*” />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height=“3*” />
<RowDefinition Height=“4*” />
</Grid.RowDefinitions><Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=“*” />
<ColumnDefinition Width=“*” />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height=“*” />
</Grid.RowDefinitions><controls:StackLayoutButton BindingContext=“{Binding Blog}” TextColor=“Blue” /><controls:StackLayoutButton x:Name=“RedButton”Grid.Column=“1” BindingContext=“{Binding Training}” TextColor=“Red” />
</Grid><

Grid Grid.Row=“1“>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=“*” />
<ColumnDefinition Width=“*” />
<ColumnDefinition Width=“*” />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height=“*” />
<RowDefinition Height=“*” />
</Grid.RowDefinitions><

controls:StackLayoutButton BindingContext=“{Binding Facebook}” />
<controls:StackLayoutButton Grid.Column=“1” BindingContext=“{Binding Twitter}” />
<controls:StackLayoutButton Grid.Column=“2” BindingContext=“{Binding Google}” /><

controls:StackLayoutButton Grid.Row=“1” BindingContext=“{Binding Eventboard}” />
<controls:StackLayoutButton Grid.Row=“1” Grid.Column=“1” BindingContext=“{Binding Website}” />
<controls:StackLayoutButton Grid.Row=“1” Grid.Column=“2” BindingContext=“{Binding Contact}” />
</Grid>
</Grid>
</StackLayout>
</ContentPage.Content>
</ContentPage>

And finally the ActivitiesView code-behind:

using System;
using System.Collections.Generic;
using Falafel2GoV2;
using Falafel2GoV2.Views;
using Xamarin.Forms;
using Falafel2GoV2.ViewModels;
using Falafel2GoV2.Controls;
using Falafel2GoV2.Models;namespace Falafel2GoV2.Views
{
public partial class ActivitiesPage : ContentPage
{private ActivitiesViewModel vm;public ActivitiesPage()
{
InitializeComponent();
vm = new ActivitiesViewModel();
this.BindingContext = vm;RedButton.TextControl.BackgroundColor =Color.Black;
}}
}

Wrapping Up and Next Steps

By creating a User Control we were able to eliminate the need to define several copies of controls, encapsulating the controls into a single container so it can be defined with a single line a code. In addition, because we added properties to the control, we allow each instance of the control to have its own properties, and even behaviors.

The only thing left is to allow the user to Tap this new custom button to launch the activity. We’ll see how easy this is to do in the next post.

Until then, as always, I hope this was helpful!

from:http://blog.falafel.com/creating-reusable-xaml-user-controls-xamarin-forms/

Creating Reusable XAML User Controls with Xamarin Forms的更多相关文章

  1. Xamarin.Forms移动开发系列4 :XAML基础

    摘要 本文介绍Xamarin.Forms创建用户界面的语言:XAML基础部分. 前言 本文介绍Xamarin.Forms定义用户界面的语言:XAML. 本篇篇幅较长,主要讲述XAML语法,以及对其他基 ...

  2. Xamarin.Forms之XAML

    官网参考 XAML基础知识 XAML(eXtensible Application Markup Language)可扩展应用程序标记语言,允许开发者在Xamarin.Forms应用中采用标记而不是代 ...

  3. Xamarin.Forms 开发资源集合(复制)

    复制:https://www.cnblogs.com/mschen/p/10199997.html 收集整理了下 Xamarin.Forms 的学习参考资料,分享给大家,稍后会不断补充: UI样式 S ...

  4. Xamarin.Forms 开发资源集合

    收集整理了下 Xamarin.Forms 的学习参考资料,分享给大家,稍后会不断补充: UI样式 Snppts: Xamarin Forms UI Snippets. Prebuilt Templat ...

  5. Xamarin.Forms介绍

    On May 28, 2014, Xamarin introduced Xamarin.Forms, which allows you to write user-interface code tha ...

  6. Xamarin.Forms 简介

    An Introduction to Xamarin.Forms 来源:http://developer.xamarin.com/guides/cross-platform/xamarin-forms ...

  7. Add AI feature to Xamarin.Forms app

    Now, AI is one of important technologies.Almost all platforms have API sets of AI. Following list is ...

  8. 在 Xamarin.Forms 实现密码输入EntryCell

    在 Xamarin.Forms 中,我们通常使用 TableView 来构建输入表单.Xamarin 为我们提供了 EntryCell 用于输入文本,但是其并不支持密码输入,即密码掩码.这里要对 En ...

  9. Xamarin.Forms 自定义控件(呈现器和效果)

    Xamarin.Forms 使用目标平台的本机控件呈现用户界面,从而让 Xamarin.Forms 应用程序为每个平台保留了相应的界面外观.凭借效果,无需进行自定义呈现器实现,即可自定义每个平台上的本 ...

随机推荐

  1. 过滤掉文本中的javascript标签代码

    2014年1月21日 11:51:19 php代码: $content = preg_replace('#<\s*[script].*>#', '', $a);//有些攻击可以在scrip ...

  2. PHP 5.2、5.3、5.4、5.5、5.6 对比以及功能详解

    php5.2.x php5.3.x php5.4.x php5.5.x php5.6.x 对比详解 截至目前(2014.2), PHP 的最新稳定版本是 PHP5.5, 但有差不多一半的用户仍在使用已 ...

  3. CentOS 7.x 安装 Docker

    安装之前确保之前没有安装过docker为此首先删除存在的docker程序 sudo yum remove docker \ docker-common \ docker-selinux \ docke ...

  4. php 批量导入昨天的数据(别类版的增量备份安案)

    $where = ''; $localogLogin = $this->gamedb_model->query_onerow("select `datetime` from lo ...

  5. 000 在什么位置写js代码

    一:介绍 1.DOM 2.节点分类 节点及其类型: 1). 元素节点 2). 属性节点: 元素的属性, 可以直接通过属性的方式来操作. 3). 文本节点: 是元素节点的子节点, 其内容为文本. 二:J ...

  6. Python学习笔记之爬取网页保存到本地文件

     爬虫的操作步骤: 爬虫三步走 爬虫第一步:使用requests获得数据: (request库需要提前安装,通过pip方式,参考之前的博文) 1.导入requests 2.使用requests.get ...

  7. Python 项目实践三(Web应用程序) 第三篇

    接着上节的继续学习,现在要显示所有主题的页面 有了高效的网页创建方法,就能专注于另外两个网页了:显示全部主题的网页以及显示特定主题中条目的网页.所有主题页面显示用户创建的所有主题,它是第一个需要使用数 ...

  8. Ubuntu 18.04 安装 virtualbox

    1.安装包下载地址 [https://www.virtualbox.org/wiki/Linux_Downloads] 2.进入软件包的文件夹 sudo dpkg -i 安装包的名字.deb [注]如 ...

  9. Java 操纵XML之创建XML文件

    Java 操纵XML之创建XML文件 一.JAVA DOM PARSER DOM interfaces The DOM defines several Java interfaces. Here ar ...

  10. CodeForces 794 G.Replace All

    CodeForces 794 G.Replace All 解题思路 首先如果字符串 \(A, B\) 没有匹配,那么二元组 \((S, T)\) 合法的一个必要条件是存在正整数对 \((x,y)\), ...