.NET-3.Xamarin2.学习与总结


前言

更加高阶的内容深入学习


组件

1.ScrollView

官方文档
ScrollView 是能够滚动其内容的布局。 ScrollView类派生自 Layout 类,默认情况下,它会垂直滚动其内容。 ScrollView只能有一个子级,尽管这可以是其他布局。

2.ListView控件

官方文档
ListView 是用于显示数据列表的视图,特别是需要滚动的长列表。

页眉和页脚
页眉和页脚组件显示在列表的开头和末尾,独立于列表的数据。 页眉和页脚可以绑定到 ListView 的数据源中的单独数据源。

可以对中的 ListView 数据进行分组,以便于导航。 组通常是数据绑定的。 以下屏幕截图显示了具有分组数据的 ListView :
单元
中的 ListView 数据项称为 "单元格"。 每个单元对应于一个数据行。 有一些内置单元可供选择,也可以定义自己的自定义单元。
1.通过请求刷新,用户可以请求 向下移动以刷新内容。
2.上下文操作 允许开发人员指定单个列表项的自定义操作。 例如,你可以在 3.iOS 上实现 "轻扫到操作" 或 "Android 上的长点击操作"。
4.选择 允许开发人员将功能附加到列表项的选择和 deselection 事件。

ItemsSource :
//此属性可接受任何实现 IEnumerable 的集合,用来指定列表中显示的数据
ItemTemplate :
//定义 ItemsSource 中每
//内置单元格一行的数据模板
TextCell //控件用于显示文本,其中包含可选的第二行详细信息文本。
ImageCell// 控件类似于, TextCell 但在文本左侧包含一个图像。
SwitchCell //控件用于显示和捕获开启/关闭或真/假状态。
EntryCell //控件用于显示用户可编辑的文本数据。
事件
ItemSelected //选择新项时激发。
ItemTapped //点击项时激发。
var listView = new ListView();
            listView.ItemsSource = Constants.Items;
            Content = listView;//重点
//一、数据源
1.简单的数据绑定
<ListView>
      <ListView.ItemsSource>
          <x:Array Type="{x:Type x:String}">
            <x:String>mono</x:String>
            <x:String>monodroid</x:String>
          </x:Array>
      </ListView.ItemsSource>
</ListView>
//等效于:
var listView = new ListView();
listView.ItemsSource = new string[]{ "mono","monodroid"}
//2.稍微复杂点的数据绑定
//Employee
public class Employee
{
     public string DisplayName { get; set; }
 }
//MainPage.cs
ObservableCollection<Employee> employees = new ObservableCollection<Employee>() { new Employee() { DisplayName = "zhouyi" } };
employees.Add(new Employee() { DisplayName = "zzl" });
ObservableCollection<string> names = new ObservableCollection<string>();
foreach (Employee employee in employees)
{
    names.Add(employee.DisplayName);
}
listView.ItemsSource = names;
DisplayAlert("Item Selected", e.SelectedItem.ToString(), "Ok");
<StackLayout BackgroundColor="White">
    <Label x:Name="laee" Text="{Binding Source={x:Reference listView },Path=SelectedItem}" TextColor="Red"/>
    <ListView x:Name="listView"
        ItemsSource="{Binding names}"
          
              ItemSelected="listView_ItemSelected">
        <ListView.ItemTemplate>
            <DataTemplate>
                <ViewCell>
                    <StackLayout>
                        <Label Text="{Binding .}" />
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</StackLayout>

//三、定义 ListView 单元格外观
//可通过使用 ViewCell 元素进行自定义。 ViewCell元素可以显示文本和图像,指示真/假状态和接收用户输入
1.TextCell 控件用于显示文本,其中包含可选的第二行详细信息文本。
2.ImageCell 控件类似于, TextCell 但在文本左侧包含一个图像。
3.SwitchCell 控件用于显示和捕获开启/关闭或真/假状态。
4.EntryCell 控件用于显示用户可编辑的文本数据。
5.SwitchCell和 EntryCell 控件更常见地用于的上下文 TableView 中。
//TextCell(Text ,Detail ,TextColor ,DetailColor )
//ImageCell(Text ,Detail,TextColor ,DetailColor,ImageSource  )

//footer、header
<ListView.Header>
    <StackLayout Orientation="Horizontal">
        <Label Text="Header"
TextColor="Olive"
BackgroundColor="Red" />
    </StackLayout>
</ListView.Header>
<ListView.Footer>
    <StackLayout Orientation="Horizontal">
        <Label Text="Footer"
TextColor="Gray"
BackgroundColor="Blue" />
    </StackLayout>
</ListView.Footer>

一、数据绑定

数据绑定将两个对象的属性链接起来,如此,对某一属性的更改将自动反映在另一个属性中。
官方文档

1.基本绑定

Xamarin.Forms 数据绑定连接两个对象之间的一对属性,其中至少有一个通常是用户界面对象。 这两个对象称为“目标”和“源” :

“目标”是设置数据要绑定的对象(和属性)。
“源”是数据绑定引用的对象(和属性)。

//一.使用上下文绑定
//BindingContext 属性指定源对象。
//SetBinding 方法指定目标属性和源属性。
 //1.基本代码绑定
<Label x:Name="label"
        Text="TEXT"
        FontSize="48"
        HorizontalOptions="Center"
        VerticalOptions="CenterAndExpand" />
 <Slider x:Name="slider"
         Maximum="360"
         VerticalOptions="CenterAndExpand" />
label.BindingContext = slider;
label.SetBinding(Label.RotationProperty, "Value");
// label.SetBinding(Label.RotationProperty, new Binding("Value", source: slider));//另一种方法
//2.基本 Xaml 绑定1
<Label Text="TEXT"
       FontSize="80"
       HorizontalOptions="Center"
       VerticalOptions="CenterAndExpand"
       BindingContext="{x:Reference Name=slider}"      
       Rotation="{Binding Path=Value}" 
       //BindingContext="{x:Reference slider}"
       //Rotation="{Binding Value}"//简写/>
<Slider x:Name="slider"
        Maximum="360"
        VerticalOptions="CenterAndExpand" />
//3.基本 Xaml 绑定2
<Label Text="TEXT"
       FontSize="40"
       HorizontalOptions="Center"
       VerticalOptions="CenterAndExpand"
       Scale="{Binding Source={x:Reference slider},
                       Path=Value}" />
       //Scale="{Binding Value, Source={x:Reference slider}}" />第二种
       //<Label.Scale>第三种
        //<Binding Source="{x:Reference slider}"
        //         Path="Value" />
        //</Label.Scale>
<Slider x:Name="slider"
        Minimum="-2"
        Maximum="2"
        VerticalOptions="CenterAndExpand" />
//4.绑定上下文继承
<StackLayout VerticalOptions="FillAndExpand"
             BindingContext="{x:Reference slider}">

    <Label Text="TEXT"
           FontSize="80"
           HorizontalOptions="Center"
           VerticalOptions="EndAndExpand"
           Rotation="{Binding Value}" />

    <BoxView Color="#800000FF"
             WidthRequest="180"
             HeightRequest="40"
             HorizontalOptions="Center"
             VerticalOptions="StartAndExpand"
             Rotation="{Binding Value}" />
</StackLayout>

<Slider x:Name="slider"
        Maximum="360" />
//5.反向绑定
//Label 是数据绑定源,而 Slider 是目标。 绑定引用 Label 的 Opacity 属性,其默认值为 1。
//Slider 从 Label 的初始 Opacity 值初始化为值 1。 
<Label x:Name="label"
       Text="TEXT"
       FontSize="80"
       HorizontalOptions="Center"
       VerticalOptions="CenterAndExpand" />

<Slider x:Name="slider"
        VerticalOptions="CenterAndExpand"
        Value="{Binding Source={x:Reference label},
                        Path=Opacity}" />
//6.StringFormat 属性
<Slider x:Name="slider" />
<Label Text="{Binding Source={x:Reference slider},
                      Path=Value,
                      StringFormat='The slider value is {0:F2}'}" />
                      //StringFormat='The Entry text is &quot;{0}&quot;'
//F2 的格式设置规范导致值在显示时会带两个小数位数。

2.绑定模式

使用 BindingMode 枚举的成员指定绑定模式:

Default
TwoWay –数据在源和目标之间的双向
OneWay –数据从源到目标进行
OneWayToSource –数据从目标到源
OneTime – data 从源到目标进行处理,但仅当 BindingContext 更改

//大多数可绑定属性的默认绑定模式都是 OneWay,但以下属性的默认绑定模式为 TwoWay:
//DatePicker 的 Date 属性
//Editor、Entry、SearchBar 和 EntryCell 的 Text 属性
//ListView 的 IsRefreshing 属性
//MultiPage 的 SelectedItem 属性
//Picker 的 SelectedIndex 和 SelectedItem 属性
//Slider 和 Stepper 的 Value 属性
//Switch 的 IsToggled 属性
//SwitchCell 的 On 属性
//TimePicker 的 Time 属性

二、Xamarin.Forms 触发器

触发器

//1.属性触发器 单个组件
//TargetType - 触发器适用的控件类型。
//Property - 要监视的控件上的属性。
//Value-出现监视属性时的值,这会导致触发器激活。
//Setter - Setter 元素的集合,可进行添加且在满足触发条件时使用。 必须指定要设置的 Property 和 Value。
<Entry Placeholder="enter name">
    <Entry.Triggers>
        <Trigger TargetType="Entry"
                 Property="IsFocused" Value="True">
            <Setter Property="BackgroundColor" Value="Yellow" />
            <!-- multiple Setters elements are allowed -->
        </Trigger>
    </Entry.Triggers>
</Entry>
//2.使用 style 应用触发器
//还可将触发器添加到控件、页面或应用程序 ResourceDictionary 中的 Style 声明。 下面的示例声明隐式 style(即未设置 Key);也就是说,它应用于页面上的所有 Entry 控件。
<ContentPage.Resources>
    <ResourceDictionary>
        <Style TargetType="Entry">
                        <Style.Triggers>
                <Trigger TargetType="Entry"
                         Property="IsFocused" Value="True">
                    <Setter Property="BackgroundColor" Value="Yellow" />
                    <!-- multiple Setters elements are allowed -->
                </Trigger>
            </Style.Triggers>
        </Style>
    </ResourceDictionary>
</ContentPage.Resources>
//3.数据触发器
//当输入为空时,触发器将禁用该按钮。
<Entry x:Name="entry"
       Text=""
       Placeholder="required field" />
<Button x:Name="button" Text="Save"
        FontSize="Large"
        HorizontalOptions="Center">
    <Button.Triggers>
        <DataTrigger TargetType="Button"
                     Binding="{Binding Source={x:Reference entry},
                                       Path=Text.Length}"
                     Value="0">
            <Setter Property="IsEnabled" Value="False" />
            <!-- multiple Setters elements are allowed -->
        </DataTrigger>
    </Button.Triggers>
</Button>
//4.事件触发器
//触发器操作实现应该:
1.实现泛型 TriggerAction<T> 类,并且泛型参数对应于触发器将应用到的控件类型。 可以使用 VisualElement 之类的超类编写适用于多种控件的触发器操作,或指定 Entry 等控件类型。
2.Invoke重写方法-只要满足触发器条件,就会调用此方法。
<Entry Placeholder="Enter a System.Double">
    <Entry.Triggers>
        <EventTrigger Event="TextChanged">
            <local:NumericValidationTriggerAction />
        </EventTrigger>
    </Entry.Triggers>
</Entry>
//local:NumericValidationTriggerAction.cs
public class NumericValidationTriggerAction : TriggerAction<Entry> 
{
	protected override void Invoke (Entry entry)
	{
		double result;
		bool isValid = Double.TryParse (entry.Text, out result);
		entry.TextColor = isValid ? Color.Default : Color.Red;
	}
}
//5.多触发器(我觉得很难)
//触发 Setter 前,所有条件必须为 true。
<Entry x:Name="email"
Text=""
Placeholder="email" />

<Entry x:Name="phone"
Text=""
Placeholder="phone" />

<Button x:Name="button" Text="Save"
        FontSize="Large"
        HorizontalOptions="Center">
    <Button.Triggers>
		<MultiTrigger TargetType="Button"> 
			<MultiTrigger.Conditions>
				<BindingCondition Binding="{Binding Source={x:Reference email},
                                       Path=Text.Length}"
                                   Value="0" />
				<BindingCondition Binding="{Binding Source={x:Reference phone},
                                       Path=Text.Length}"
                                   Value="0" />
			</MultiTrigger.Conditions>
				
            <Setter Property="IsEnabled" Value="False" />
        </MultiTrigger>
    </Button.Triggers>
</Button>
//生成“全部需要”的多触发器
MultiTriggerConverter.cs
public class MultiTriggerConverter : IValueConverter
{
	public object Convert(object value, Type targetType, 
		object parameter, CultureInfo culture)
	{		
		if ((int)value > 0)
			return true;	// data has been entered
		else
			return false;	// input is empty
	}

	public object ConvertBack(object value, Type targetType, 
		object parameter, CultureInfo culture)
	{
		throw new NotSupportedException ();
	}
}
MultiTriggerXaml.xaml
<ContentPage.Resources>
	<ResourceDictionary>
     	<local:MultiTriggerConverter x:Key="dataHasBeenEntered" />
     </ResourceDictionary>
 </ContentPage.Resources>
<Entry x:Name="user"
Text=""
Placeholder="user name" />
<Entry x:Name="pwd"
 	Text=""
Placeholder="password" />
<Button x:Name="loginButton" Text="Login"
        FontSize="Large"
        HorizontalOptions="Center"
        IsEnabled="false">
    
    <Button.Triggers>
		<MultiTrigger TargetType="Button"> 
			<MultiTrigger.Conditions>
				<BindingCondition Binding="{Binding Source={x:Reference user},
                                       Path=Text.Length,
                                       Converter={StaticResource dataHasBeenEntered}}"
                                   Value="true" />
				<BindingCondition Binding="{Binding Source={x:Reference pwd},
                                       Path=Text.Length,
                                       Converter={StaticResource dataHasBeenEntered}}"
                                   Value="true" />
			</MultiTrigger.Conditions>
				
            <Setter Property="IsEnabled" Value="True" />
        </MultiTrigger>
    </Button.Triggers>
</Button>

//6.EnterActions 和 ExitActions
//全局的
<ContentPage.Resources>
    <ResourceDictionary>
        <Style TargetType="Entry">
            <Style.Triggers>
                <Trigger TargetType="Entry"
                         Property="Entry.IsFocused" Value="True">
                    <Trigger.EnterActions>
                        <local:FadeTriggerAction StartsFrom="0" />
                    </Trigger.EnterActions>
                    <Trigger.ExitActions>
                        <local:FadeTriggerAction StartsFrom="1" />
                    </Trigger.ExitActions>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ResourceDictionary>
</ContentPage.Resources>
//单个
<Entry Placeholder="enter job title" Text="">
	<Entry.Triggers>
		<Trigger TargetType="Entry"
                 Property="Entry.IsFocused" Value="True">
            <Trigger.EnterActions>
                <local:FadeTriggerAction StartsFrom="0" />
            </Trigger.EnterActions>

            <Trigger.ExitActions>
                <local:FadeTriggerAction StartsFrom="1" />
            </Trigger.ExitActions>
        </Trigger>
	</Entry.Triggers>
</Entry>
FadeTriggerAction.cs
public class FadeTriggerAction : TriggerAction<VisualElement>
{
    public int StartsFrom { set; get; }

    protected override void Invoke(VisualElement sender)
    {
        sender.Animate("FadeTriggerAction", new Animation((d) =>
        {
            var val = StartsFrom == 1 ? d : 1 - d;
            // so i was aiming for a different color, but then i liked the pink :)
            sender.BackgroundColor = Color.FromRgb(1, val, 1);
        }),
        length: 1000, // milliseconds
        easing: Easing.Linear);
    }
}
//7.比较状态触发器
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="WorkingWithTriggers.CompareStateTriggerDemoPage"
             Title="CompareStateTrigger demo">
    <ContentPage.Resources>
        <Style TargetType="Grid">
            <Setter Property="VisualStateManager.VisualStateGroups">
                <VisualStateGroupList>
                    <VisualStateGroup>
                        <VisualState x:Name="Checked">
                            <VisualState.StateTriggers>
                                <CompareStateTrigger Property="{Binding Source={x:Reference checkBox}, Path=IsChecked}"
                                                     Value="True" />
                            </VisualState.StateTriggers>
                            <VisualState.Setters>
                                <Setter Property="BackgroundColor"
                                        Value="Black" />
                            </VisualState.Setters>
                        </VisualState>
                        <VisualState x:Name="Unchecked">
                            <VisualState.StateTriggers>
                                <CompareStateTrigger Property="{Binding Source={x:Reference checkBox}, Path=IsChecked}"
                                                     Value="False" />
                            </VisualState.StateTriggers>
                            <VisualState.Setters>
                                <Setter Property="BackgroundColor"
                                        Value="White" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateGroupList>
            </Setter>
        </Style>
    </ContentPage.Resources>
    <Grid>
        <Frame BackgroundColor="White"
               CornerRadius="12"
               Margin="24"
               HorizontalOptions="Center"
               VerticalOptions="Center">
            <StackLayout Orientation="Horizontal">
                <CheckBox x:Name="checkBox"
                          VerticalOptions="Center" />
                <Label Text="Check the CheckBox to modify the Grid background color."
                       VerticalOptions="Center" />
            </StackLayout>
        </Frame>
    </Grid>
</ContentPage>

三、MessagingCenter(还是很有意思)

MessagingCenter

发布-订阅模式是一种消息传递模式,在此模式下,发布者可在无需知道任何接收方(称为订阅方)的情况下发送消息。 同样,订阅方可在不了解任何发布方的情况下侦听特定消息。

在这里插入图片描述

//发布方使用 MessagingCenter.Send 方法发送消息,而订阅方使用 
//MessagingCenter.Subscribe 方法侦听消息。 此外,订阅方还可以使用 
//MessagingCenter.Unsubscribe 方法取消消息订阅(如果需要)。

//MainPage.xaml
<StackLayout Margin="20,35,20,20">
    <Label Text="MessagingCenter Demo"
           FontAttributes="Bold"
           HorizontalOptions="Center" />
    <Button Text="Say Hi"
            Clicked="OnSayHiButtonClicked" />
    <Button Text="Say Hi to John"
            Clicked="OnSayHiToJohnButtonClicked" />
    <Button Text="Unsubscribe"
            Clicked="OnUnsubscribeButtonClicked" />
    <ListView ItemsSource="{Binding Greetings}" />
</StackLayout>
//MainPage.cs
 public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        BindingContext = new MainPageViewModel();//这里很是重点。

        // Subscribe to a message (which the ViewModel has also subscribed to) to display an alert
        MessagingCenter.Subscribe<MainPage, string>(this, "Hi", async (sender, arg) =>
        {
            await DisplayAlert("Message received", "arg=" + arg, "OK");
        });
    }

    void OnSayHiButtonClicked(object sender, EventArgs e)
    {
        MessagingCenter.Send<MainPage>(this, "Hi");
    }

    void OnSayHiToJohnButtonClicked(object sender, EventArgs e)
    {
        MessagingCenter.Send<MainPage, string>(this, "Hi", "John");
    }

    async void OnUnsubscribeButtonClicked(object sender, EventArgs e)
    {
        MessagingCenter.Unsubscribe<MainPage, string>(this, "Hi");
        await DisplayAlert("Unsubscribed", "This page has stopped listening, so no more alerts. However, the ViewModel is still receiving messages.", "OK");
    }
}

MainPageViewModel.cs
public class MainPageViewModel
{
    public ObservableCollection<string> Greetings { get; set; }

    public MainPageViewModel()
    {
        Greetings = new ObservableCollection<string>();
        MessagingCenter.Subscribe<MainPage>(this, "Hi", (sender) =>
        {
            Greetings.Add("Hi");
        });
        MessagingCenter.Subscribe<MainPage, string>(this, "Hi", (sender, arg) =>
        {
            Greetings.Add("Hi " + arg);
        });
    }
}

四、样式(统一风格)

官方文档

使用 XAML 样式设置应用样式
传统上, Xamarin.Forms 设置应用的样式是使用 Style 类将属性值集合分组到一个对象中,然后可应用于多个可视元素实例。 这有助于减少重复标记,并允许更轻松地更改应用外观。

使用 设置应用样式级联样式表
Xamarin.Forms 支持使用 CSS 设置级联样式表 (设置) 。 样式表由规则列表组成,每个规则由一个或多个选择器以及声明块组成。

使用 XAML 样式设置应用样式

全局样式<页面级别<控件级别
通过对控件类型进行分组和设置属性来创建自定义控件外观的样式。

  • 显式样式
    显式样式是通过设置 控件的属性有选择地应用于控件的样式。

  • 隐式样式
    隐式样式是指所有相同 的控件使用的样式,无需每个控件都引用该样式。

  • 全局样式
    可以通过将样式添加到应用程序的 ResourceDictionary 来全局使用样式。 这有助于避免跨页面或控件的样式的重复。

  • 样式继承
    样式可以从其他样式继承,以减少重复并实现重复使用。

  • 动态样式
    样式不会对属性更改做出响应,并在应用程序持续时间内保持不变。 但是,应用程序可以使用动态资源在运行时动态响应样式更改。

  • 设备样式
    Xamarin.Forms在类中 包含六个Xamarin.Forms样式,称为设备样式。 所有六种样式只能应用 Label 于实例。

  • 样式类
    Xamarin.Forms 样式类可以将多个样式应用于控件,而无需采用样式继承。

//一、显示样式
//页面级别
<ContentPage.Resources>
	<ResourceDictionary>
     <Style x:Key="labelStyle" TargetType="Label">
         <Setter Property="TextColor" Value="Black"/>
         <Setter Property="FontSize" Value="7"/>
         <Setter Property="FontAttributes" Value="Italic"/>
     </Style>
     </ResourceDictionary>
 </ContentPage.Resources>
<Label Text="Demonstrating an explicit style" Style="{StaticResource labelStyle}" />
//控件级别
<ContentPage.Content>
    <StackLayout Padding="0,20,0,0">
        <StackLayout.Resources>
            <ResourceDictionary>
                <Style x:Key="labelRedStyle" TargetType="Label">
                  <Setter Property="TextColor" Value="Black"/>
                </Style>                 
            </ResourceDictionary>
        </StackLayout.Resources>
        <Label Text="These labels" Style="{StaticResource labelRedStyle}" />
    </StackLayout>
</ContentPage.Content>

//二、隐式样式
//页面级别
<ContentPage.Resources>
    <ResourceDictionary>
        <Style TargetType="Entry">
            <Setter Property="HorizontalOptions" Value="Fill" />
            <Setter Property="VerticalOptions" Value="CenterAndExpand" />
            <Setter Property="BackgroundColor" Value="Yellow" />
            <Setter Property="FontAttributes" Value="Italic" />
            <Setter Property="TextColor" Value="Blue" />
        </Style>
    </ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
    <StackLayout Padding="0,20,0,0">
        <Entry Text="These entries" />
        <Entry Text="are demonstrating" />
        <Entry Text="implicit styles," />
        <Entry Text="implicit style override" BackgroundColor="Lime" TextColor="Red" />   
        <local:CustomEntry Text="not receiving the style" />    
    </StackLayout>//不接受样式
</ContentPage.Content>
//CustomEntry.cs
public class CustomEntry : Entry
{
}
//控件级别
<ContentPage.Content>
    <StackLayout Padding="0,20,0,0">
        <StackLayout.Resources>
            <ResourceDictionary>
                <Style TargetType="Entry">
                    <Setter Property="HorizontalOptions" Value="Fill" />
                </Style>
            </ResourceDictionary>
        </StackLayout.Resources>
        <Entry Text="These entries" />
    </StackLayout>
</ContentPage.Content>
//将样式应用于派生类型
<Style TargetType="Button"
       ApplyToDerivedTypes="True">
    <Setter Property="BackgroundColor"
            Value="Red" />
</Style>
//将此样式置于页面级别ResourceDictionaryButton将导致它应用于页面上的所有实例,以及从 派生的任何控件Button。 
//但是,如果 ApplyToDerivedTypes 属性保持未设置,则样式将仅应用于 Button 实例。
//三、全局样式
//应用程序级别app.xaml
<Application.Resources>
<ResourceDictionary>      
	<Style x:Key="buttonStyle" TargetType="Button">
		<Setter Property="HorizontalOptions" 
                      Value="Center" />
		<Setter Property="VerticalOptions" 
                      Value="CenterAndExpand" />
		<Setter Property="BorderColor"
                      Value="Lime" />
		<Setter Property="CornerRadius" 
                      Value="5" />
		<Setter Property="BorderWidth" 
                      Value="5" />
		<Setter Property="WidthRequest"
                      Value="200" />
		<Setter Property="TextColor" 
                      Value="Teal" />
	</Style>         
          <!-- ContentPage -->
          <Style TargetType="ContentPage"
                 ApplyToDerivedTypes="True">
              <Setter Property="BackgroundColor"
                      Value="WhiteSmoke" />
          </Style>
         
</ResourceDictionary>
</Application.Resources>
//四、样式继承
//遵循继承链
//应用程序级别资源只能继承自其他应用程序级别资源。
//页面级别资源可以继承自应用程序级别资源和其他页面级资源。
//控制级别资源可以从应用程序级别资源、页面级别资源和其他控制级别资源继承。
//属性设置为 BasedOn 实例实现的 Style
<ContentPage.Resources>
    <ResourceDictionary>
        <Style x:Key="baseStyle" TargetType="View">
            <Setter Property="HorizontalOptions"
                    Value="Center" />
            <Setter Property="VerticalOptions"
                    Value="CenterAndExpand" />
        </Style>
        <Style x:Key="labelStyle" TargetType="Label"
               BasedOn="{StaticResource baseStyle}">
            <Setter Property="TextColor" Value="Teal" />
        </Style>
        <Style x:Key="buttonStyle" TargetType="Button"
               BasedOn="{StaticResource baseStyle}">
            <Setter Property="BorderColor" Value="Lime" />
        </Style>
    </ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
    <StackLayout Padding="0,20,0,0">
        <Label Text="These labels"
               Style="{StaticResource labelStyle}" />
        <Button Text="So is the button"
                Style="{StaticResource buttonStyle}" />
    </StackLayout>
</ContentPage.Content>
//遵循继承链
<ContentPage.Resources>
    <ResourceDictionary>
        <Style x:Key="baseStyle" TargetType="View">
          ...
        </Style>
    </ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
    <StackLayout Padding="0,20,0,0">
        <StackLayout.Resources>
            <ResourceDictionary>
                <Style x:Key="labelStyle" TargetType="Label" BasedOn="{StaticResource baseStyle}">
                  ...
                </Style>
                <Style x:Key="buttonStyle" TargetType="Button" BasedOn="{StaticResource baseStyle}">
                  ...
                </Style>
            </ResourceDictionary>
        </StackLayout.Resources>
        ...
    </StackLayout>
</ContentPage.Content>
//五、动态样式
<ContentPage.Resources>
     <ResourceDictionary>
         <Style x:Key="baseStyle" TargetType="View">
           ...
         </Style>
         <Style x:Key="blueSearchBarStyle"
                TargetType="SearchBar"
                BasedOn="{StaticResource baseStyle}">
           ...
         </Style>
         <Style x:Key="greenSearchBarStyle"
                TargetType="SearchBar">
           ...
         </Style>
         ...
     </ResourceDictionary>
 </ContentPage.Resources>
 <ContentPage.Content>
     <StackLayout Padding="0,20,0,0">
         <SearchBar Placeholder="These SearchBar controls"
                    Style="{DynamicResource searchBarStyle}" />
         ...
     </StackLayout>
 </ContentPage.Content>
 DynamicStylesPage .cs
 public partial class DynamicStylesPage : ContentPage
{
    bool originalStyle = true;

    public DynamicStylesPage ()
    {
        InitializeComponent ();
        Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
    }

    void OnButtonClicked (object sender, EventArgs e)
    {
        if (originalStyle) {
            Resources ["searchBarStyle"] = Resources ["greenSearchBarStyle"];
            originalStyle = false;
        } else {
            Resources ["searchBarStyle"] = Resources ["blueSearchBarStyle"];
            originalStyle = true;
        }
    }
}
//动态样式继承
//使用 属性无法从动态样式派生 Style.BasedOn 样式。 相反, Style 类包含 BaseResourceKey 属性,该属性可设置为其值可能会动态更改的字典键。
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.DynamicStylesInheritancePage" Title="Dynamic Inheritance" IconImageSource="xaml.png">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style x:Key="baseStyle" TargetType="View">
              ...
            </Style>
            <Style x:Key="blueSearchBarStyle" TargetType="SearchBar" BasedOn="{StaticResource baseStyle}">
              ...
            </Style>
            <Style x:Key="greenSearchBarStyle" TargetType="SearchBar">
              ...
            </Style>
            <Style x:Key="tealSearchBarStyle" TargetType="SearchBar" BaseResourceKey="searchBarStyle">
              ...
            </Style>
            ...
        </ResourceDictionary>
    </ContentPage.Resources>
    <ContentPage.Content>
        <StackLayout Padding="0,20,0,0">
            <SearchBar Text="These SearchBar controls" Style="{StaticResource tealSearchBarStyle}" />
            ...
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
//六、设备样式
//在 Device 类中包含六种动态样式,称为设备样式。
//BodyStyle
//CaptionStyle
//ListItemDetailTextStyle
//ListItemTextStyle
//SubtitleStyle
//TitleStyle
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="Styles.DeviceStylesPage" Title="Device" IconImageSource="xaml.png">
    <ContentPage.Resources>
        <ResourceDictionary>
            <Style x:Key="myBodyStyle" TargetType="Label"
              BaseResourceKey="BodyStyle">
                <Setter Property="TextColor" Value="Accent" />
            </Style>
        </ResourceDictionary>
    </ContentPage.Resources>
    <ContentPage.Content>
        <StackLayout Padding="0,20,0,0">
            <Label Text="Title style"
              Style="{DynamicResource TitleStyle}" />
            <Label Text="Subtitle text style"
              Style="{DynamicResource SubtitleStyle}" />
            <Label Text="Body style"
              Style="{DynamicResource BodyStyle}" />
            <Label Text="Caption style"
              Style="{DynamicResource CaptionStyle}" />
            <Label Text="List item detail text style"
              Style="{DynamicResource ListItemDetailTextStyle}" />
            <Label Text="List item text style"
              Style="{DynamicResource ListItemTextStyle}" />
            <Label Text="No style" />
            <Label Text="My body style"
              Style="{StaticResource myBodyStyle}" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
//七、样式类
1.创建样式类
<ContentPage ...>
    <ContentPage.Resources>
        <Style TargetType="BoxView"
               Class="Separator">
            <Setter Property="BackgroundColor"
                    Value="#CCCCCC" />
            <Setter Property="HeightRequest"
                    Value="1" />
        </Style>

        <Style TargetType="BoxView"
               Class="Rounded">
            <Setter Property="BackgroundColor"
                    Value="#1FAECE" />
            <Setter Property="HorizontalOptions"
                    Value="Start" />
            <Setter Property="CornerRadius"
                    Value="10" />
        </Style>    

        <Style TargetType="BoxView"
               Class="Circle">
            <Setter Property="BackgroundColor"
                    Value="#1FAECE" />
            <Setter Property="WidthRequest"
                    Value="100" />
            <Setter Property="HeightRequest"
                    Value="100" />
            <Setter Property="HorizontalOptions"
                    Value="Start" />
            <Setter Property="CornerRadius"
                    Value="50" />
        </Style>

        <Style TargetType="VisualElement"
               Class="Rotated"
               ApplyToDerivedTypes="true">
            <Setter Property="Rotation"
                    Value="45" />
        </Style>        
    </ContentPage.Resources>
    <StackLayout Margin="20">
        <BoxView StyleClass="Separator" />       
        <BoxView WidthRequest="100"
                 HeightRequest="100"
                 HorizontalOptions="Center"
                 StyleClass="Rounded, Rotated" />
        <BoxView HorizontalOptions="Center"
                 StyleClass="Circle" />
    </StackLayout>
</ContentPage>

使用 Xamarin.Forms CSS 级联样式表

五、使用堆叠和选项卡导航创建多页 Xamarin.Forms 应用

官方文档

1.使用 NavigationPage 实现堆叠导航

导航堆栈上还必须至少有一个页面。 NavigationPage 类提供了一个构造函数,该函数使用堆栈的初始或根页面参数。 在此代码中,我们将传递 HomePage 类的一个实例作为要显示的初始页面,然后将新的 NavigationPage 设置为应用的初始页面。

//提供的方法,,模式导航的方法(需要实践去理解)
Task PushAsync(Page page, bool animated);
Task PushAsync(Page page); // 'animated' is true
Task<Page> PopAsync(bool animated);
Task<Page> PopAsync(); // 'animated' is true
-------------------------
IReadOnlyList<Page> ModalStack { get; }
Task PushModalAsync(Page page);
Task<Page> PopModalAsync();
IReadOnlyList<Page> NavigationStack { get; }
Task PushAsync(Page page);
Task<Page> PopAsync();
//app.cs根页面
 MainPage = new NavigationPage(new MainPage());
//调用方法,调用模式导航方法
 await this.Navigation.PushAsync(new Page1());
 await this.Navigation.PopAsync();
 await Navigation.PushModalAsync(new EditPage());
 await Navigation.PopModalAsync();
//MainPage()页面
<StackLayout>
    ...
    <Button x:Name="btnSunrise" Text="Sunrise and Sunset" />
    <Button x:Name="btnMoonPhase" Text="Moon Phase" />
    <Button x:Name="btnSpaceInfo" Text="Astronomical Bodies" />
    <Button x:Name="btnAbout" Text="About Contoso Astronomy" />
</StackLayout>
public MainPage()
{
    InitializeComponent();
//初始化添加导航
    btnSunrise.Clicked += (s, e) => Navigation.PushAsync(new SunrisePage());
    btnMoonPhase.Clicked += (s, e) => Navigation.PushAsync(new MoonPhasePage());
    btnSpaceInfo.Clicked += (s, e) => Navigation.PushAsync(new AstronomicalBodiesPage());
    btnAbout.Clicked += (s, e) => Navigation.PushAsync(new AboutPage());
}

//处理设备后退按钮(用处巨大)
//替代该方法可以让我们在页面关闭前完成一些工作。 由我们决定应执行的操作。
protected override bool OnBackButtonPressed()//方法重写
{
    ...
}

2.选项卡导航创建多页

小案例

推荐好看的组件UI

1.第三方控件推荐Xamarin Community Toolkit

许多好用得组件值得一试

2.jsuarezruiz/xamarin-forms-goodlooking-UI

这个仓库集成了许多多好看的UI仓库的总结与介绍。

3.FabriBertani/XFShapeAnimatedTransitions

这个仓库是有关页面切换的动画效果(值得参考,可以当做轮子来使用)

posted @ 2022-05-02 16:02  cactus9  阅读(30)  评论(0编辑  收藏  举报