如何通过传入类型参数使Xamarin模板可自定义?

时间:2018-07-22 12:58:30

标签: xamarin xamarin.forms

这是我到目前为止提出的方法。但是,似乎不是一个干净的解决方案。

有人对我如何提出一个更好的解决方案有什么建议吗?

<?xml version="1.0" encoding="utf-8"?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             xmlns:local="clr-namespace:Japanese;assembly=Japanese" 
             x:Class="Japanese.Templates.HeaderTemplate" 
             x:Name="this" HorizontalOptions="FillAndExpand" Orientation="Vertical" Spacing="0" Margin="0">
    <StackLayout IsVisible="{Binding HeaderType, Converter={StaticResource HeaderType1BoolConverter}, Source={x:Reference this}  }" >
        <!-- code -->
    </StackLayout>
    <StackLayout IsVisible="{Binding HeaderType, Converter={StaticResource HeaderType2BoolConverter}, Source={x:Reference this}  }" >
        <!-- code -->
    </StackLayout>
</StackLayout>

在我的银行CS中:

using System;
using System.Collections.Generic;
using Xamarin.Forms;

namespace Japanese.Templates
{
    public partial class HeaderTemplate : StackLayout
    {
        public HeaderTemplate()
        {
            InitializeComponent();
        }

   public static readonly BindableProperty HeaderTypeProperty =
        BindableProperty.Create(
            nameof(HeaderType),
            typeof(string),
            typeof(DataViewCellTemplate),
            default(string));

    public string HeaderType
    {
        get { return (string)GetValue(HeaderTypeProperty); }
        set { SetValue(HeaderTypeProperty, value); }
    }

    }
}

转换器代码:

public class HeaderType1BoolConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return object.Equals(value, "1");
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

public class HeaderType2BoolConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return object.Equals(value, "2");
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

在调用代码中:

<template:HeaderTemplate Header="Application" HeaderType="1" />

2 个答案:

答案 0 :(得分:1)

使用triggers是一种选择。

例如:您可以添加属性触发器以检查HeaderType上的值,并相应地更新自定义控件Content中的HeaderView(或布局)。

请注意,在这种情况下,我们是从ContentView而不是StackLayout扩展而来,假设一次只能看到一个布局/控件。

XAML

<ContentView 
    xmlns="http://xamarin.com/schemas/2014/forms" 
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
    xmlns:local="clr-namespace:SampleApp" 
    x:Class="SampleApp.HeaderView">

    <ContentView.Triggers>

        <!-- if header type is 1, use header1 layout -->
        <Trigger TargetType="local:HeaderView" Property="HeaderType" Value="1">
            <Setter Property="Content">
                <Setter.Value>
                    <Label Text="Header1" />
                </Setter.Value>
            </Setter>
        </Trigger>

        <!-- if header type is 2, use header2 layout -->
        <Trigger TargetType="local:HeaderView" Property="HeaderType" Value="2">
            <Setter Property="Content">
                <Setter.Value>
                    <StackLayout>
                        <Label Text="Header2" />
                        <BoxView HeightRequest="1" BackgroundColor="Gray" />
                    </StackLayout>
                </Setter.Value>
            </Setter>
        </Trigger>

        <!-- you can add more layouts here if you need -->

    </ContentView.Triggers>

    <!-- add default content that can be displayed in case of no match -->
    <StackLayout>
        <Label Text="DefaultHeader" />
        <BoxView HeightRequest="1" BackgroundColor="Gray" />
    </StackLayout>    

</ContentView>

隐藏代码

public partial class HeaderView : ContentView
{
    public HeaderView()
    {
        InitializeComponent();

    }

    public static readonly BindableProperty HeaderTypeProperty =
        BindableProperty.Create(
            nameof(HeaderType), typeof(string), typeof(HeaderView),
            defaultValue: default(string));

    public string HeaderType
    {
        get { return (string)GetValue(HeaderTypeProperty); }
        set { SetValue(HeaderTypeProperty, value); }
    }
}

用法

<local:HeaderView HeaderType="1" />

答案 1 :(得分:1)

我相信您正在寻找的是ControlTemplate,这是一个实现。

App.xaml

<Application xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="SimpleTheme.App">
    <Application.Resources>
        <ResourceDictionary>
            <ControlTemplate x:Key="Header1Template">
                <StackLayout>
                    <!-- code -->
                </StackLayout>
            </ControlTemplate>
            <ControlTemplate x:Key="Header2Template">
                <StackLayout>
                    <!-- code -->
                </StackLayout>
            </ControlTemplate>
        </ResourceDictionary>
    </Application.Resources>
</Application>

用法(这将header1设置为默认值,您可以选择二者之一)

<ContentView x:Name="contentView" ControlTemplate="{StaticResource Header1Template}">

现在,有许多方法可以更改标题,方法是将其定义为上面的默认代码,或者通过动作进行操作,该动作可以是按钮单击(如链接上给出的示例),也可以使用propertyChange事件(如果要依赖)选择标题的属性,如:

public int HeaderNumber { get; set; }

protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    base.OnPropertyChanged(propertyName);

    if (propertyName == "HeaderNumber")
    {
        contentView.ControlTemplate = (HeaderNumber == 1) ? Header1Template : Header2Template;
    }
}

请注意,我从未实现过ControlTemplate,但我认为这可以解决您的问题。