.NET-3.Xamarin学习与总结


前言

Xamarin官方文档


一、Xamarin初识?

1、Xamarin可以做什么

  • Xamarin.Android Xamarin.iOS Xamarin.Mac

向 .NET 开发人员公开了完整的 Android SDK 、iOS SDK、macOS SDK

  • Xamarin.Forms

一个跨平台的UI 框架,通过 Xamarin.Forms,开发人员可从跨平台共享代码,生成 Android、iOS 和 Windows 应用程序。

  • Xamarin.Essentials

提供了系统功能的调用,适用于Android、iOS 或 UWP 应用程序的跨平台 API,不管如何创建用户界面,都可以通过共享代码进行访问

2、项目知识

XAML文档:用来定义界面类(UI),每个Xaml文件必须绑定2个C#文件 (类名.xaml 类名.xaml.cs 类名.xaml.g.cs )

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" //引入Xamarin.Forms命名空间          
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"//引入Xaml规范命名空间
x:Class="App3.MainPage">//定义类名
</ContentPage>

二、组件

在这里插入图片描述

在这里插入图片描述

1.View类的属性(通用的属性)

BackgroundColor ://元素的填充背景的颜色
HeightRequest , WidthRequest ://元素的高度或宽度(Height,Width为只读属性)
MinimumHeightRequest, MinimumWidthRequest : //元素的最小高度或宽度
X,Y :// 元素的当前 X ,Y位置,只读属性
HorizontalOptions,VerticalOptions: //元素的水平或垂直布局方式
IsEnabled ://是否启用此元素
IsFocused://当前是否获得输入焦点
IsVisible://此元素是否可见
Margin://视图的边距
AnchorX,AnchorY://旋转或者缩放的中心点
RotationX,RotationY,Rotation://元素围绕 X ,Y,Z轴的旋转角度
ScaleX,ScaleY,Scale://应用于 X ,Y,XY方向的缩放值
Opacity://元素的不透明度值

2.与Text属性有关的属性:Label,Button,Entry

Text://显示的文本
TextTransform ://转换文本
	None //指示不转换文本。
	Default //指示将使用平台的默认行为。 这是 TextTransform 属性的默认值。
	Lowercase //指示文本将转换为小写。
	Uppercase //指示文本将转换为大写。
CharacterSpacing ://字符间距离
TextColor://自定义文本颜色
FontSize://字体大小
FontAttributes://字体是粗体、斜体还是两者皆否
	Bold//字体为粗体。Italic字体为斜体。None字体无格式。
FontFamily://设置字体
//### 1.Label控件
TextDecorations ://将下划线和删除线文本修饰
                 None	     Underline     Strikethrough
LineBreakMode :	HeadTruncation //– 截断文本的开头,并显示结束。
			CharacterWrap//– 将文本换行到字符边界处的新行。
			MiddleTruncation//– 显示文本的开头和结尾,中间用省略号替换。
			NoWrap //– 不会自动换行,只显示一行中可容纳的最多文本。
			TailTruncation //– 显示文本的开头,截断结束
FormattedText://显示具有多种字体和颜色的文本,FormattedText属性的类型为 FormattedString ,它包含一个或多个 Span 实例。
Span 的属性:
BackgroundColor //–跨距背景的颜色。
CharacterSpacing//,属于 double 类型,是 Span 文本字符之间的间距。
FontAttributes //Italic–范围中文本的字体特性。
FontFamily //–范围内的文本的字体所属的字体系列。
FontSize// –范围中文本的字体大小。
LineHeight// -要应用于范围默认行高的乘数。 
Text// –范围的文本。
TextColor// –范围中文本的颜色。
TextDecorations //-要应用于范围中的文本的修饰。
//案例Label 
<Label Text="Welcome to Xamarin.Forms!"
TextColor="Blue"
FontAttributes="Italic"
FontSize="22"
TextDecorations="Underline"
HorizontalOptions="Center" />
 <Label TextColor="Gray"
FontSize="Medium">
     <Label.FormattedText>
         <FormattedString>
             <Span Text="This sentence contains " />
             <Span Text="words that are emphasized, "
           FontAttributes="Italic" />
             <Span Text="and underlined."
           TextDecorations="Underline" />
         </FormattedString>
     </Label.FormattedText>
 </Label>
//### 2.Button控件
Clicked事件://当手指点击时触发事件
Pressed事件://当手指按下时触发事件
Released事件://当手指释放时触发事件
BorderColor://边框颜色
BorderWidth://边框的宽度
CornerRadius ://圆角半径
<Button Text="Click me"
      Clicked="Button_Clicked" />
      <Button Text="Click me"
      Clicked="Button_Clicked"
      TextColor="Blue"
      BackgroundColor="Aqua"
      BorderColor="Red"
      BorderWidth="5"
      CornerRadius="5"
      WidthRequest="150"
      HeightRequest="75" />
private void Button_Clicked(object sender, EventArgs e)
{  
    ((Button)sender).Text = "这是点击";
}
//3.Entry控件、Editor控件
TextChanged://当项中的文本更改时触发事件
Placeholder://当输入框没有输入内容时,显示的占位符文本
PlaceholderColor://控制占位符文本颜色
IsReadOnly ://禁止文本输入
IsPassword :///内容将显示为黑色圆圈
CursorPosition://下一个字符插入属性中存储的字符串的位置
SelectionLength ://选定文本的长度
Keyboard ://与用户交互时显示的键盘
	Chat// – 用于短信和表情符号有用的地方。		Default – 默认键盘。
	Email// – 输入电子邮件地址时使用。			Numeric – 输入数字时使用。
	Plain //– 输入文本时使用				Telephone – 输入电话号码时使用。
	Text// – 输入文本时使用。				Url – 用于输入文件路径和 Web 地址。
//案例:Entry 
 <Entry Placeholder="Enter text"
       TextChanged="OnEntryTextChanged"
       Completed="OnEntryCompleted" />
 <Entry Placeholder="Enter password"
  MaxLength="15"
  IsSpellCheckEnabled="false"
  IsTextPredictionEnabled="false"
  IsPassword="true" />
 <Editor Placeholder="Enter multi-line text here"
        HeightRequest="200"
        TextChanged="OnEntryTextChanged"
        Completed="OnEntryCompleted" />
void OnEntryTextChanged(object sender, TextChangedEventArgs e)
{
    string oldText = e.OldTextValue;
    string newText = e.NewTextValue;
    Console.WriteLine(oldText + newText);
}
void OnEntryCompleted(object sender, EventArgs e)
{
    string text = ((Entry)sender).Text;
    Console.WriteLine(text);    
}

3.Image

Source://用于设置要显示的图像,是一个ImageSource对象
可以从 本地文件、 嵌入资源、 下载或从流中加载图像
ImageSource //类使用静态方法获取实例:
FromFile //-需要可在每个平台上解析的文件名或文件路径。
FromUri //-需要 Uri 对象,例如。 new Uri("http://server.com/image.jpg") .
FromResource //-需要资源标识符到应用程序或 .NET Standard 库项目中嵌入的图像文件,其中包含生成操作: EmbeddedResource。
FromStream //-需要提供图像数据的流。

Aspect://图像是否拉伸、裁剪
Fill//-拉伸 ,填满整个区域,可能会导致图像扭曲,显示完整图像
AspectFill //剪辑(不拉伸)图像,使其填充显示区域,同时保持比例,无扭曲,图像可能显示不完整
AspectFit //-拉伸,将整个图像适应显示区域,同时保持比例,无扭曲,显示完整图像

------------------------
//显示图像的其他控件
Button //具有一个 ImageSource 属性,该属性可设置为要在上显示的位图图像 Button
ImageButton// 具有 Source 可设置为要在中显示的图像的属性 ImageButton 。
ToolbarItem //具有一个 IconImageSource 属性,该属性可设置为从文件、嵌入资源、URI 或流加载的图像。
ImageCell //具有一个 ImageSource 属性,该属性可设置为从文件、嵌入资源、URI 或流中检索的图像。
MenuItem //具有一个 IconImageSource 属性,可设置为要在中显示的图像
FlyoutItem //具有一个 Icon 属性,可设置为要在中显示的图像
Tab  //具有一个 Icon 属性,可设置为要在中显示的图像
//案例
<Image Source="https://images2018.cnblogs.com/blog/1038566/201806/1038566-20180622142650682-1207554536.png"
               HeightRequest="300" />
<ImageButton Source="XamarinLogo.png"
                    HorizontalOptions="Center"
                    VerticalOptions="CenterAndExpand" />

4.ListView控件

ItemsSource :
//此属性可接受任何实现 IEnumerable 的集合,用来指定列表中显示的数据
ItemTemplate :
//定义 ItemsSource 中每
//内置单元格一行的数据模板
TextCell //控件用于显示文本,其中包含可选的第二行详细信息文本。
ImageCell// 控件类似于, TextCell 但在文本左侧包含一个图像。
SwitchCell //控件用于显示和捕获开启/关闭或真/假状态。
EntryCell //控件用于显示用户可编辑的文本数据。
事件
ItemSelected //选择新项时激发。
ItemTapped //点击项时激发。

5.Shell控件

Shell 包含三个主要层次结构对象:

  1. FlyoutItem:表示飞出项;每个 FlyoutItem 对象都是 Shell 对象的子对象。
  2. Tab:显示为底部选项卡导航; 每个 Tab 对象都是 FlyoutItem 对象子对象。
  3. ShellContent:显示为顶部选项卡 ;每个 ShellContent 对象都是 Tab 对象的子对象;ShellContent 的内容属性是ContentPage 对象。
Shell 的菜单项:MenuItem控件
Shell的页头:Shell.FlyoutHeader
Shell的页脚:Shell. FlyoutFooter
Shell禁止飞出页面:TabBar

6.CollectionView

参考官网的案例

<CollectionView>
   <CollectionView.ItemsSource>
       <x:Array Type="{x:Type x:String}">
           <x:String>Baboon</x:String>
           <x:String>Capuchin Monkey</x:String>
           <x:String>Blue Monkey</x:String>
           <x:String>Squirrel Monkey</x:String>
           <x:String>Golden Lion Tamarin</x:String>
           <x:String>Howler Monkey</x:String>
           <x:String>Japanese Macaque</x:String>
       </x:Array>
   </CollectionView.ItemsSource>
</CollectionView>

7.弹出警报

 <Button Text="Display alert"
                Clicked="OnDisplayAlertButtonClicked" />
 <Button Text="Display alert question"
          Clicked="OnDisplayAlertQuestionButtonClicked" />
 <Button Text="Display action sheet"
        Clicked="OnDisplayActionSheetButtonClicked" />
async void OnDisplayAlertButtonClicked(object sender, EventArgs e)
{
    await DisplayAlert("Alert", "This is an alert.", "OK");
}
async void OnDisplayAlertQuestionButtonClicked(object sender, EventArgs e)
{
    bool response = await DisplayAlert("Save?", "Would you like to save your data?", "Yes", "No");
    Console.WriteLine("Save data: " + response);
}
async void OnDisplayActionSheetButtonClicked(object sender, EventArgs e)
{
    string action = await DisplayActionSheet("Send to?", "Cancel", null, "Email", "Twitter", "Facebook");
    Console.WriteLine("Action: " + action);
}

8.手势识别器(GestureRecognizer)

GestureRecognizer 类支持对 View 实例使用点击、收缩、平移、轻扫和拖放手势
在这里插入图片描述

1. TapGestureRecognizer
 Tapped 事件    Command属性

2. SwipeGestureRecognizer 
Direction属性:Left,Right,Up,Down
Swiped事件:参数SwipedEventArgs ,Direction属性(SwipeDirection.Left, Right,Up,Down )
Command属性

3. PinchGestureRecognizer
PinchUpdated 事件 
参数PinchGestureUpdatedEventArgs:
Status属性:动作状态(GestureStatus.Running,Started,Completed) ,
Scale属性:自上次接收到更新后的用户缩放手势的相对大小
ScaleOrigin属性:缩放手势的已更新的原点
4. PanGestureRecognizer
PanUpdated  事件 
参数PanUpdatedEventArgs :
StatusType属性:动作状态(GestureStatus.Running,Started,Completed) 
TotalX属性:获取手势开始后 X 方向的总体更改
TotalY属性:获取手势开始后 Y 方向的总体更改

5. DragGestureRecognizer 
此类定义了以下属性:
CanDrag:类型为 bool,指明手势识别器附加到的元素能否为拖动源。 此属性的默认值为 true。
DragStartingCommand:类型为 ICommand,在第一次识别拖动手势时执行。
DragStartingCommandParameter,属于 object 类型,是传递给 DragStartingCommand 的参数。
DropCompletedCommand:类型为 ICommand,在放置拖动源时执行。
DropCompletedCommandParameter,属于 object 类型,是传递给 DropCompletedCommand 的参数。

9.ActivityIndicator、ProgressBar

//ActivityIndicator控件定义以下属性:
1.Color定义的显示颜色 ActivityIndicator 的值。
2.IsRunning 一个 bool 值,该值指示是否 ActivityIndicator 应显示、动画显示或隐藏。 如果值为 false , ActivityIndicator 则不可见。
<ActivityIndicator IsRunning="true" Color="Orange" />
//控件 ProgressBar 定义两个属性:
1.Progress 是一 float 个值,该值将当前进度表示为 0 到 1 的值。 Progress 小于 0 的值将固定为 0,大于 1 的值将固定为 1。
2.ProgressColor 是 Color 一个 ,它影响表示当前进度的内部条颜色。
<ProgressBar Progress="0.5" ProgressColor ="black"/>
await progressBar.ProgressTo(0.75, 500, Easing.Linear);

10.Check,DatePicker,Slider,Stepper

DatePicker,
Stepper
switch
TimePicker

//CheckBox 是可以选中或空的按钮类型。 选中复选框后,它将被视为已启用。 如果复选框为空,则将其视为关闭
//1.CheckBox 定义一个 bool 名为 IsChecked 的属性,指示是否 CheckBox 选中。默认绑定模式为 BindingMode.TwoWay
//2.定义一个 CheckedChanged 事件,该事件在属性更改时
<CheckBox IsChecked="True" CheckedChanged="OnCheckBoxCheckedChanged"
Color="Red"/>
<CheckBox x:Name="checkBox" />
<Label Text="Lorem ipsum dolor sit amet, elit rutrum, enim hendrerit augue vitae praesent sed non, lorem aenean quis praesent pede.">
    <Label.Triggers>
        <DataTrigger TargetType="Label"
             Binding="{Binding Source={x:Reference checkBox}, Path=IsChecked}"
             Value="true">
            <Setter Property="FontAttributes"
            Value="Italic, Bold" />
            <Setter Property="FontSize"
            Value="Large" />
        </DataTrigger>
    </Label.Triggers>
</Label>
//复选框可视状态
<CheckBox >
  <VisualStateManager.VisualStateGroups>
      <VisualStateGroup x:Name="CommonStates">
          <VisualState x:Name="Normal">
              <VisualState.Setters>
                  <Setter Property="Color"
                  Value="Red" />
              </VisualState.Setters>
          </VisualState>

          <VisualState x:Name="IsChecked">
              <VisualState.Setters>
                  <Setter Property="Color"
                  Value="Green" />
              </VisualState.Setters>
          </VisualState>
      </VisualStateGroup>
  </VisualStateManager.VisualStateGroups>
</CheckBox>

//DatePicker调用平台的日期选取器控件
//MinimumDate 类型的 DateTime,默认为 1900 年的第一天。
//MaximumDate 类型的 DateTime,默认为 2100 年的最后一天。
//Date 类型 DateTime为 的所选日期,默认为值 DateTime.Today。
//Format类型为 stringFormatstring .NET 格式设置字符串,默认为"D",即长日期模式。
//TextColor 类型 Color为 的颜色,用于显示所选日期,默认为 Color.Default。
//FontAttributes 类型的 FontAttributes,默认为 FontAtributes.None。
//FontFamily 类型的 string,默认为 null。
//FontSize 类型的 double,默认为 -1.0。
//CharacterSpacing,属于 double 类型,是 DatePicker 文本字符之间的间距。

//slider 滑块
//Minimum 是范围的最小值,默认值为 0。
//Maximum 是范围的最大值,默认值为 1。
//Value 是滑块的值,该值介于 和 MinimumMaximum 之间,默认值为 0。
//MinimumTrackColor 是滚动块左侧的条形颜色。
//MaximumTrackColor 是滚动块右边的条形颜色。
//ThumbColor 是滚动块颜色。
//ThumbImageSource 是用于 thumb 的图像,类型为 ImageSource。

//Stepper
//Increment 是按 更改所选值的数量,默认值为 1。
//Minimum 是范围的最小值,默认值为 0。
//Maximum 是范围的最大值,默认值为 100。
//Value 是 stepper 的值,该值介于 和 MinimumMaximum 之间,默认值为 0。
//定义一个 ValueChanged 事件

//switch
//IsToggled boolean指示是否IsToggled的 Switch 值。
//OnColor是一个 Color ,它会影响在切换或OnColor状态下呈现的 Switch 方式。
//ThumbColorColor是交换机拇指的。

11.RadioButton

单选按钮

//Content,类型为 object,用于 string 定义 要 View 由 显示的 RadioButton或 。
//IsChecked,类型为 bool,用于定义 RadioButton 是否选中 。 此属性使用绑定 TwoWay ,并且 具有默认值 false。
//GroupName,类型为 string,它定义指定 RadioButton 哪些控件互斥的名称。 此属性的默认值为 null。
//Value,类型为 object,用于定义与 关联的可选唯一值 RadioButton。
//BorderColor,类型为 Color,用于定义边框笔划颜色。
//BorderWidth,类型 double为 ,用于定义边框 RadioButton 的宽度。
//CharacterSpacing,类型为 double,用于定义任何显示文本的字符之间的间距。
//CornerRadius,类型为 int,用于定义 的角半径 RadioButton。
//FontAttributes,类型为 FontAttributes,它确定文本样式。
//FontFamily,类型为 string,用于定义字体系列。
//FontSize,类型为 double,用于定义字号。
//TextColor,类型为 Color,用于定义任何显示文本的颜色。
//TextTransform,类型为 TextTransform,用于定义任何显示文本的大小写
<StackLayout>
    <Label Text="What's your favorite animal?" />
    <RadioButton Content="Cat" />
    <RadioButton Content="Dog" />
    <RadioButton Content="Elephant" />
    <RadioButton Content="Monkey"
                 IsChecked="true" />
</StackLayout>
<StackLayout>
    <Label Text="What's your favorite animal?" />
    <RadioButton Value="Cat">
        <RadioButton.Content>
            <Image Source="cat.png" />
        </RadioButton.Content>
    </RadioButton>
    <RadioButton Value="Dog">
        <RadioButton.Content>
            <Image Source="dog.png" />
        </RadioButton.Content>
    </RadioButton>
    <RadioButton Value="Elephant">
        <RadioButton.Content>
            <Image Source="elephant.png" />
        </RadioButton.Content>
    </RadioButton>
    <RadioButton Value="Monkey">
        <RadioButton.Content>
            <Image Source="monkey.png" />
        </RadioButton.Content>
    </RadioButton>
</StackLayout>
<StackLayout RadioButtonGroup.GroupName="colors">
    <Label Text="What's your favorite color?" />
    <RadioButton Content="Red" />
    <RadioButton Content="Green" />
    <RadioButton Content="Blue" />
    <RadioButton Content="Other" />
</StackLayout>
<Label Text="What's your favorite color?" />
<RadioButton Content="Red"
             GroupName="colors" />
<RadioButton Content="Green"
             GroupName="colors" />
<RadioButton Content="Blue"
             GroupName="colors1" />
<RadioButton Content="Other"
             GroupName="colors1" />

12.SearchBar

官方文档

//SearchButtonPressed 当用户单击 "搜索" 按钮或按 "enter" 键时调用。
//TextChanged 只要更改了查询框中的文本,就会调用。
<SearchBar Placeholder="Search items..."
           CancelButtonColor="Orange"
           PlaceholderColor="Orange"
           TextColor="Orange"
           TextTransform="Lowercase"
           HorizontalTextAlignment="Center"
           FontSize="Medium"
           FontAttributes="Italic" />

13.SwipeView

官方文档

<SwipeView>
    <SwipeView.LeftItems>
        <SwipeItems>
            <SwipeItem Text="Favorite"
                       IconImageSource="favorite.png"
                       BackgroundColor="LightGreen"
                       Invoked="OnFavoriteSwipeItemInvoked" />
            <SwipeItem Text="Delete"
                       IconImageSource="delete.png"
                       BackgroundColor="LightPink"
                       Invoked="OnDeleteSwipeItemInvoked" />
        </SwipeItems>
    </SwipeView.LeftItems>
    <!-- Content -->
    <Grid HeightRequest="60"
          WidthRequest="300"
          BackgroundColor="LightGray">
        <Label Text="Swipe right"
               HorizontalOptions="Center"
               VerticalOptions="Center" />
    </Grid>
</SwipeView>
//======================
<SwipeView>
    <SwipeView.LeftItems>
        <SwipeItems>
            <SwipeItem Text="Favorite"
                       IconImageSource="favorite.png"
                       BackgroundColor="LightGreen"
                       Invoked="OnFavoriteSwipeItemInvoked" />
            <SwipeItem Text="Delete"
                       IconImageSource="delete.png"
                       BackgroundColor="LightPink"
                       Invoked="OnDeleteSwipeItemInvoked" />
        </SwipeItems>
    </SwipeView.LeftItems>
    <!-- Content -->
</SwipeView>

三、 布局

  • 具有单一内容的布局:ContentView Frame ScrollView ContentPresenter
  • 具有多个子元素的布局:StackLayout Grid AbsoluteLayout RelativeLayout FlexLayout

在这里插入图片描述
页面(Page):下面这些类都是继承至Page类

//ContentPage:是最简单且最常见的页面类型。 将 Content 属性设置为一个 View 对象。
//NavigationPage:使用基于堆栈的体系结构管理其他页面中的导航。 在应用程序中使用页面导航时,主页的实例应传递给NavigationPage对象的构造函数。
//FlyoutPage :管理两个页面。 将 Flyout 属性设置为通常显示列表或菜单的页面。 将 Detail 属性设置为一个页面。
//TabbedPage:允许使用选项卡在子页间导航。 将 Children 属性设置为页的集合
//CarouselPage:允许通过手指轻扫在子页面之间导航。 将 Children 属性设置为页的集合。
//TemplatedPage:使用控件模板显示全屏内容,是的基类 ContentPage 。
//Shell:提供大多数应用程序需要的基本 UI 功能,让你能够专注于处理应用程序的核心工作负载
<StackLayout Margin="20,35,20,20">
        <StackLayout Margin="20,35,20,25" Orientation="Horizontal">
            <Label Text="The StackLayout has its Margin property set, to control the rendering position of the StackLayout." />
            <Label Text="The Padding property can be set to specify the distance between the StackLayout and its children." />
            <Label Text="The Spacing property can be set to specify the distance between views in the StackLayout." />
        </StackLayout>
        <Label Text="The Grid has its Margin property set, to control the rendering position of the Grid." />
        <Grid Margin="20,35,20,20">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0.5*" />
                <ColumnDefinition Width="0.5*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="50" />
                <RowDefinition Height="50" />
            </Grid.RowDefinitions>
            <Label Text="Column 0, Row 0" />
            <Label Grid.Column="1"
           Text="Column 1, Row 0" />
            <Label Grid.Row="1"
           Text="Column 0, Row 1" />
            <Label Grid.Column="1"
           Grid.Row="1"
           Text="Column 1, Row 1" />
        </Grid>
        <Grid >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0.5*" />
                <ColumnDefinition Width="0.5*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="50" />
                <RowDefinition Height="30" />
                <RowDefinition Height="30" />
            </Grid.RowDefinitions>
            <Label Grid.ColumnSpan="2"
           Text="This text uses the ColumnSpan poperty to span both columns." />
            <Label Grid.Row="1"
           Grid.RowSpan="2"
           Text="This text uses the RowSpan property to span two rows." />
        </Grid>
    </StackLayout>

四、数据绑定

什么叫数据绑定?
数据绑定将两个对象的属性链接起来,某一属性的更改将自动反映在另一个属性中
传统做法:基于事件驱动的模型
基于数据驱动的模型:MVVM(Model-View-ViewModel)
数据绑定:将两个对象的属性链接起来。
1.指定绑定源:在绑定上下文BindingContext中设置
2.设置绑定属性:在绑定目标的属性中设置
绑定模式
使用 BindingMode 枚举的成员指定绑定模式:
Default TwoWay – 数据在源和目标之间双向传输
OneWay – 数据从源到目标单向传输 OneWayToSource – 数据从目标到源单向传输
OneTime – 只有在 BindingContext 更改时,数据才从源到目标单向传输

在这里插入图片描述
在这里插入图片描述

Xamarin中实现数据绑定的类
BindableObject 类提供数据绑定的功能:
实现绑定源功能:
(1)实现了INotifyPropertyChanged(属于System.ComponentModel命名空间)接口
接口中定义了:public event PropertyChangedEventHandler PropertyChanged;
PropertyChanged事件就负责通知绑定目标
(2) 当属性的值改变时,就要触发PropertyChanged事件,所以,属性的set段中就要调用事件的处理函数PropertyChanged?. Invoke(this, new PropertyChangedEventArgs(propertyName));

在这里插入图片描述

五、应用生命周期

  • 生命周期方法 : OnStart ,OnSleep 和 OnResume 。
  • 页面导航事件 : PageDisappearing /PageAppearing。
  • 模式导航事件 : ModalPushedModalPopping 、和 ModalPopped 。
//OnStart - 在启动应用程序时调用它。
//OnSleep - 每当应用程序转入后台时调用它。
//OnResume - 应用程序发送到后台后恢复时调用
//PageAppearing - 页面即将在屏幕上显示时引发。
//PageDisappearing - 页面即将从屏幕上消失时引发。
//ModalPushing - 按模式推送页面时将引发它。
//ModalPushed - 按模式推送页面后将引发它。
//ModalPopping - 按模式弹出页面时将引发它。
//ModalPopped - 按模式弹出页面后将引发它。
protected override void OnStart()//应用程序启动时调用 OnStart 方法。
{
    Console.WriteLine("OnStart");
}
protected override void OnSleep()//应用程序转到后台时调用 OnSleep 方法。
{
    Console.WriteLine("OnSleep");
}
protected override void OnResume()//应用程序从后台恢复时调用 OnResume 方法。
{
    Console.WriteLine("OnResume");
}

六、模板

1.使用母版-详细信息导航显示 Xamarin.Forms 中的关系

从 GitHub 克隆或下载练习存储库
官方文档

  1. 对于母版视图,在拆分视图或者弹出式视图之间进行选择
  2. 使用弹出式抽屉导航在页面之间进行切换
  3. 使用母版 - 详细信息拆分视图显示集合

什么是抽屉导航?
抽屉导航是使用滑出式抽屉来承载页面菜单的导航模式。
什么是母版-详细信息导航?

“母版-详细信息导航”是一种使用两个视图显示同质数据集合的方式。 母版视图显示整个集合的概览。 “详细信息”视图显示单个项的扩展视图。 当用户从该列表中选择某项时,右侧会显示关于所选项的详细信息。

//什么是 MasterDetailPage?
1.MasterDetailPage 是一个 Xamarin.Forms 页面,它显示一个母版页和一个详细信息页面,并协调它们之间的同步。 Xamarin.Forms 在抽屉导航和母版-详细信息导航中使用这一相同的类。
2. MasterDetailPage 具有两个属性,分别是 Master 和 Detail,它们承载每个模式的两个逻辑部分。 这些属性可以保存 Page 派生的类型。 在大多数应用中,你将使用派生自 ContentPage 的类型用于母版页和详细信息页面。
//MasterBehavior 以及拆分式和弹出式
//split 表示始终显示母版视图。
//popover 表示在滑出式抽屉中显示母版视图。
var md = new MasterDetailPage();
md.MasterBehavior = MasterBehavior.Popover;

//前面的代码在母版页上分配了标题 (Title)。 Xamarin.Forms 需要标题,否则会在运行时引发异常。
<ContentPage Title="Menu">
   <StackLayout>
      <Button Text="Sessions" />
      <Button Text="Speakers" />
      <Button Text="Activities" />
      <Button Text="Rooms" />
      <Button Text="Map" />
   </StackLayout>
</ContentPage>

练习 - 使用 Xamarin.Forms 定义抽屉导航 UI

//分配母版页和详细信息页
//母版页
public enum PageType
{
    Sunrise,
    MoonPhase,
    Earth,
    Moon,
    Sun,
    About,
}
 <StackLayout Margin="10">
        <Label Text="Main Menu" FontSize="Medium" HorizontalTextAlignment="Center" />
        <BoxView BackgroundColor="Gray" HeightRequest="1" />
        <Button x:Name="btnSunrise" Text="Sunrise and Sunset" />
        <Button x:Name="btnMoonPhase" Text="Moon Phase" />
        <BoxView BackgroundColor="Gray" HeightRequest="1" />
        <Button x:Name="btnEarth" Text="Earth Data" />
        <Button x:Name="btnSun" Text="Sun Data" />
        <Button x:Name="btnMoon" Text="Moon Data" />
        <BoxView BackgroundColor="Gray" HeightRequest="1" />
        <Button x:Name="btnAbout" Text="About Contoso Astronomy" />
</StackLayout>
public partial class AstronomyMasterPage : ContentPage
    {
        public event EventHandler<PageType> PageSelected;

        public AstronomyMasterPage()
        {
            InitializeComponent();
            btnMoonPhase.Clicked += (s, e) => PageSelected?.Invoke(this, PageType.MoonPhase);
            btnSunrise.Clicked += (s, e) => PageSelected?.Invoke(this, PageType.Sunrise);
            btnAbout.Clicked += (s, e) => PageSelected?.Invoke(this, PageType.About);
            btnEarth.Clicked += (s, e) => PageSelected?.Invoke(this, PageType.Earth);
            btnMoon.Clicked += (s, e) => PageSelected?.Invoke(this, PageType.Moon);
            btnSun.Clicked += (s, e) => PageSelected?.Invoke(this, PageType.Sun);
        }
    }
//详细信息页
 public class AstronomyMasterDetailPage : MasterDetailPage
 public AstronomyMasterDetailPage()
{
    var master = new AstronomyMasterPage();

    if (Device.RuntimePlatform == Device.iOS)
    {
        master.IconImageSource = ImageSource.FromFile("nav-menu-icon.png");
    }

    this.Master = master;

    this.MasterBehavior = MasterBehavior.Popover;

    master.PageSelected += MasterPageSelected;

    PresentDetailPage(PageType.Sunrise);
}

void MasterPageSelected(object sender, PageType e)
{
    PresentDetailPage(e);
}

void PresentDetailPage(PageType pageType)
{
    Page page;

    switch (pageType)
    {
        case PageType.Sunrise:
            page = new SunrisePage();
            break;
        case PageType.MoonPhase:
            page = new MoonPhasePage();
            break;
        case PageType.Earth:
            page = new AstronomicalBodyPage(SolarSystemData.Earth);
            break;
        case PageType.Moon:
            page = new AstronomicalBodyPage(SolarSystemData.Moon);
            break;
        case PageType.Sun:
            page = new AstronomicalBodyPage(SolarSystemData.Sun);
            break;
        case PageType.About:
        default:
            page = new AboutPage();
            break;
    }
    Detail = new NavigationPage(page);
    try
    {
        IsPresented = false;
    }
    catch { }   
}
///AstronomicalBody
public class AstronomicalBody
{
    public string Name { get; set; }
    public string Mass { get; set; }
    public string Circumference { get; set; }
    public string Age { get; set; }
    public string EmojiIcon { get; set; }
}
//SolarSystemData
 public static class SolarSystemData
{
    public static AstronomicalBody Sun = new AstronomicalBody()
    {
        Name = "The Sun (Sol)",
        Mass = "1.9855*10^30 kg",
        Circumference = "4,379,000 km",
        Age = "4.57 billion years",
        EmojiIcon = "☀️",
    };

    public static AstronomicalBody Earth = new AstronomicalBody()
    {
        Name = "Earth",
        Mass = "5.97237*10^24 kg",
        Circumference = "40,075 km",
        Age = "4.54 billion years",
        EmojiIcon = "🌎",
    };

    public static AstronomicalBody Moon = new AstronomicalBody()
    {
        Name = "Moon",
        Mass = "7.342*10^22 kg",
        Circumference = "10,921 km",
        Age = "4.53 billion years",
        EmojiIcon = "🌕",
    };

    public static AstronomicalBody HalleysComet = new AstronomicalBody()
    {
        Name = "Halley's Comet",
        Mass = "22 * 10^14 kg",
        Circumference = "11 km",
        Age = "4.6 billion years",
        EmojiIcon = "☄",
    };
}
//app将 MainPage 分配更改为 AstronomyMasterDetailPage 的实例
public App()
{
    InitializeComponent();
    MainPage = new AstronomyMasterDetailPage();
}
//SunrisePage
//MoonPhasePage
//AstronomicalBodyPage(SolarSystemData.Earth)

2.使用 Xamarin.Forms 创建无障碍应用

官方文档
练习 - 启用系统的屏幕阅读器

//IsInAccessibleTree 是布尔值,可告知操作系统元素是否应可供访问并对屏幕阅读器可见。
//Name 是屏幕阅读器用于公告元素的简短的描述性文本字符串
<ActivityIndicator AutomationProperties.IsInAccessibleTree="true"
                   AutomationProperties.Name="Progress indicator" />
//HelpText 是元素的较长说明。 可将它视为元素的工具提示。
<Button Text="Toggle"
        AutomationProperties.IsInAccessibleTree="true"
        AutomationProperties.HelpText="Toggles the activity indicator" />
//LabeledBy 允许其他元素为当前元素定义辅助功能文本。
<Label x:Name="label" Text="Enter your name: " />
<Entry AutomationProperties.IsInAccessibleTree="true"
       AutomationProperties.LabeledBy="{x:Reference label}" />

在这里插入图片描述

3.使用 Xamarin.Forms 呈现器创建自定义控件

了解呈现器
在这里插入图片描述
在这里插入图片描述

4.自定义 Xamarin.Forms ListView

官方文档请在克隆或下载的练习存储库

  • 为 ListView 创建自定义单元格布局
  • 在单个 ListView 中使用多个单元格布局
  • 将单元格分组为多个部分

5.使用共享资源和样式设计一致的 Xamarin.Forms XAML 页

官方文档GitHub 克隆或下载练习存储库

  • 使用资源和样式创建一致的 UI
  • 对用户的辅助功能选项应用内置样式
  1. 什么是 ResourceDictionary?
    ResourceDictionary 是一个 Xamarin.Forms 库类,可进行自定义以用于 UI 资源。 它是一个字典,因此它存储了键/值对。 键的类型仅限于 String,而值可以是任何对象。
  1. 使用 StaticResource 应用资源
    StaticResource 是一个标记扩展,用于在资源字典中查找资源。 提供资源的键后,标记扩展会返回相应的值。
  1. OnPlatform 作为资源
    在各个平台之间,通常需要简单调整应用的 UI。 要定义特定于平台的值,标准方法是使用 OnPlatform 对象。
  1. 使用并更新动态资源
    你希望实现能够使用户在运行时更改应用外观的颜色主题。 StaticResource 只在字典中执行一次查找,因此无法动态地更新 UI。
    可将用户首选项存储在 Web 服务器上,并在应用程序启动时加载它们。 如果在字典中找不到键,则 StaticResource 会引发异常。
    还有另外一个优点。 如果 DynamicResource 在字典中找不到键,它将使属性保持为未设置状态。 与 StaticResource 不同,缺失键不是错误,也不会引发异常。
<Label TextColor="Blue" FontSize="14">
<Button TextColor="Blue" FontSize="14">
//可以将文本颜色定义为资源,而不是重复它。 该定义类似于此 XAML
<Color x:Key="PageControlTextColor">Blue</Color>
<Page.Resources>
    <Color x:Key="PageControlTextColor">Blue</Color>
</Page.Resources>
//使用 StaticResource 应用资源
<Page.Resources>
    <Color x:Key="PageControlTextColor">Blue</Color>
</Page.Resources>
...
<Label TextColor="{StaticResource PageControlTextColor}" ... />
//OnPlatform 作为资源
<Page.Resources>
    <OnPlatform x:Key="textColor"
                x:TypeArguments="Color"
                iOS="Silver"
                Android="Green" />
</Page.Resources>
...
<Label TextColor="{StaticResource textColor}" ... />

<Page.Resources>
    <ResourceDictionary>
        <Color x:Key="bgColor">#c0c0c0</Color>
        <Color x:Key="fgColor">#606060</Color>
    </ResourceDictionary>
</Page.Resources>
<Grid x:Name ="LayoutRoot" BackgroundColor="{StaticResource bgColor}" Padding="10">
<Label x:Name="tipOutput" Text="0.00" TextColor="{StaticResource fgColor}" FontSize="22" Grid.Row="1" Grid.Column="1" />

//什么是 DynamicResource?
<ContentPage ...>
    <Page.Resources>
        <Color x:Key="PanelBackgroundColor">Blue</Color>
    </Page.Resources>
    <StackLayout BackgroundColor="{DynamicResource PanelBackgroundColor}">
    ...
    </StackLayout>
</ContentPage>

6.使用 SQLite 在 Xamarin.Forms 应用中存储本地数据

官方文档克隆或下载练习存储库

在 Xamarin.Forms 中,有三种常用的数据本地存储选项:
首选项:以键-值对的形式存储数据
文件系统:通过文件系统访问直接在设备上存储松散文件
数据库:在完整的关系数据库中存储数据

  1. 何时使用首选项
    使用“首选项”可方便地处理简单的数据集合。 它们通常用于让用户能够配置应用程序。 例如,回到社交媒体应用程序示例,假设希望用户能够选择应用程序的配色方案。 由于此选择是一小段数据,可将用户的选择以键-值对的形式存储在“首选项”中。

  2. 何时使用文件系统
    移动设备有一个真实的文件系统,它包含由文件夹和文件构成的分层目录结构。 拥有 XML、二进制文件或文本文件等松散文件时,使用文件系统会很方便。 例如,假设想要在设备本地存储日志文件。 可创建一个文本文件,将其保存到文件系统,并在事件发生时将日志写入其中。

  3. 何时使用数据库
    如果拥有数据关系或想要随时间推移筛选数据,使用本地数据库是个不错的想法。 例如,在社交媒体示例中,每个帖子都包含与帖子相关的数据,例如时间戳和内容。
    然而,每个帖子也与发布该帖子的用户有关系。 最好在数据库中表示这种关系,以防止帖子之间的数据重复,同时可提高搜索数据的效率。

  4. 什么是应用沙盒?
    处理 XML 等松散文件或 SQLite 等本地数据库文件时,需要找到存储它们的正确位置。 应用沙盒是应用程序可以使用的专有区域。 在默认情况下,除操作系统本身外,其他任何应用程序都无法访问此区域。

//在 Android 上访问应用沙盒,
string path = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
//使用 Xamarin.Essentials 访问库文件夹
var libFolder = FileSystem.AppDataDirectory;

跨生命周期状态更改保留数据

//1.App.xaml.cs
public partial class App : Application
{
    const string displayText = "displayText";

    public string DisplayText { get; set; }

    public App()
    {
        InitializeComponent();

        MainPage = new MainPage();
    }

    protected override void OnStart()
    {
        Console.WriteLine("OnStart");

        if (Properties.ContainsKey(displayText))
        {
            DisplayText = (string)Properties[displayText];
        }
    }

    protected override void OnSleep()
    {
        Console.WriteLine("OnSleep");
        Properties[displayText] = DisplayText;
    }

    protected override void OnResume()
    {
        Console.WriteLine("OnResume");
    }
}

//MainPage.xaml
<StackLayout Margin="20,35,20,20">
    <Entry x:Name="entry"
           Placeholder="Enter text here"
           Completed="OnEntryCompleted" />
</StackLayout>
protected override void OnAppearing()
{
    base.OnAppearing();

    entry.Text = (Application.Current as App).DisplayText;
}

void OnEntryCompleted(object sender, EventArgs e)
{
    (Application.Current as App).DisplayText = entry.Text;
}

练习 - 使用 SQLite 在本地存储数据

//定义 SQLite.NET 实体
//1.将名为“Models”的新文件夹添加到“People”.NET 标准库中。
//2.在“Models”文件夹中,创建名为“Person”的新类。 确保将其标记为“公开”。
//3.使用 [Table] 属性批注“Person”类,并将名称指定为“people”。
//4.将“Id”属性指定为主键。 使用 [PrimaryKey] 和 [AutoIncrement] 属性对其进行批注。
//5.向“Name”属性添加注释,以向数据添加一些约束。 将其 [MaxLength] 指定为 250。 指定列中的每个值都应为 [Unique]。
using SQLite;
namespace People.Models
{
   Table("people")]
   public class Person
   {
      [PrimaryKey, AutoIncrement]
      public int Id { get; set; }

      [MaxLength(250), Unique]
      public string Name { get; set; }
   }
}

//添加存储库类PersonRepository.cs
//1.连接到数据库
//2.向数据库中插入行
//3.异步使用 SQLite
private SQLiteConnection conn;
public string StatusMessage { get; set; }
...
public PersonRepository(string dbPath)
{
   conn = new SQLiteConnection(dbPath);
   conn.CreateTable<Person>();
   //var conn = new SQLiteAsyncConnection(dbPath);
	//await conn.CreateTableAsync<User>();
}

 public void AddNewPerson(string name)
 {
      int result = 0;
      try
      {
          //basic validation to ensure a name was entered
          if (string.IsNullOrEmpty(name))
              throw new Exception("Valid name required");

          result = conn.Insert(new Person { Name = name });

          StatusMessage = string.Format("{0} record(s) added [Name: {1})", result, name);
      }
      catch (Exception ex)
      {
          StatusMessage = string.Format("Failed to add {0}. Error: {1}", name, ex.Message);
      }
 }
public List<Person> GetAllPeople()
{
    try
    {
        return conn.Table<Person>().ToList();
    }
    catch (Exception ex)
    {
        StatusMessage = string.Format("Failed to retrieve data. {0}", ex.Message);
    }

    return new List<Person>();
}
=====
//public async Task AddNewPersonAsync(string name)
//{
//    int result = 0;
//    try
//    {
//        //basic validation to ensure a name was entered
//        if (string.IsNullOrEmpty(name))
//            throw new Exception("Valid name required");

//        result = await conn.InsertAsync(new Person { Name = name });

//        StatusMessage = string.Format("{0} record(s) added [Name: {1})", result, name);
//    }
//    catch (Exception ex)
//    {
//        StatusMessage = string.Format("Failed to add {0}. Error: {1}", name, ex.Message);
//    }
//}

//public async Task<List<Person>> GetAllPeopleAsync()
//{
//    try
//    {
//        return await conn.Table<Person>().ToListAsync();
//    }
//    catch (Exception ex)
//    {
//        StatusMessage = string.Format("Failed to retrieve data. {0}", ex.Message);
//    }

//    return new List<Person>();
//}
//UI界面
<?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:local="clr-namespace:People"
             xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
             ios:Page.UseSafeArea="true"
             x:Class="People.MainPage">

    <Grid Padding="5" RowSpacing="1" ColumnSpacing="1" BackgroundColor="Default">

        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Entry x:Name="newPerson"
           Placeholder="Enter name" />

        <Button Text="Add Person"
            Grid.Row="1"
            Clicked="OnNewButtonClicked" />

        <Label x:Name="statusMessage"
           Grid.Row="2" />

        <Button Text="Get All People"
            Grid.Row="3"
            Clicked="OnGetButtonClicked" />

        <ListView x:Name="peopleList"
              Grid.Row="4">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell Height="30">
                        <StackLayout Padding="5">
                            <Label Text="{Binding Name}" />
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</ContentPage>

 public void OnNewButtonClicked(object sender, EventArgs args)
 {
     statusMessage.Text = "";
     App.PersonRepo.AddNewPerson(newPerson.Text);
     statusMessage.Text = App.PersonRepo.StatusMessage;
 }

 public void OnGetButtonClicked(object sender, EventArgs args)
 {
     statusMessage.Text = "";
     List<Person> people = App.PersonRepo.GetAllPeople();
     peopleList.ItemsSource = people;
 }

//入口函数
string dbPath => FileAccessHelper.GetLocalFilePath("people.db3");
public static PersonRepository PersonRepo { get; private set; }
public App()
{
     InitializeComponent();
     PersonRepo = new PersonRepository(dbPath);
     MainPage = new People.MainPage();
 }
//文件访问帮助类
using Xamarin.Essentials;
public class FileAccessHelper
{
    public static string GetLocalFilePath(string filename)
    {
        return System.IO.Path.Combine(FileSystem.AppDataDirectory, filename);
    }
}

练习 - 使用 SQLite 在本地存储数据2

//在“NuGet 包管理器”中,选择“浏览”选项卡,搜索“sqlite-net-pcl”NuGet 包
//1.Person.cs 
using SQLite;
namespace LocalDatabaseTutorial
{
    public class Person
    {
        [PrimaryKey, AutoIncrement]
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
    }
}
//2. Database.cs 
using System.Collections.Generic;
using System.Threading.Tasks;
using SQLite;

namespace LocalDatabaseTutorial
{
    public class Database
    {
        readonly SQLiteAsyncConnection _database;

        public Database(string dbPath)
        {
            _database = new SQLiteAsyncConnection(dbPath);
            _database.CreateTableAsync<Person>().Wait();
        }

        public Task<List<Person>> GetPeopleAsync()
        {
            return _database.Table<Person>().ToListAsync();
        }

        public Task<int> SavePersonAsync(Person person)
        {
            return _database.InsertAsync(person);
        }
    }
}
//3.在“App.xaml.cs”中
static Database database;
public static Database Database
{
    get
    {
        if (database == null)
        {
            database = new Database(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "people.db3"));
        }
        return database;
    }
}

//4. MainPage.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"
             x:Class="LocalDatabaseTutorial.MainPage">
    <StackLayout Margin="20,35,20,20">
        <Entry x:Name="nameEntry"
               Placeholder="Enter name" />
        <Entry x:Name="ageEntry"
               Placeholder="Enter age" />
        <Button Text="Add to Database"
                Clicked="OnButtonClicked" />
        <CollectionView x:Name="collectionView">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <StackLayout>
                        <Label Text="{Binding Name}"
                               FontSize="Medium" />
                        <Label Text="{Binding Age}"
                               TextColor="Silver"
                               FontSize="Small" />
                    </StackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </StackLayout>
</ContentPage>
//OnAppearing 方法覆盖的执行是在布局 ContentPage 后但在其变得可见之前进行的。
protected override async void OnAppearing()
{
    base.OnAppearing();
    collectionView.ItemsSource = await App.Database.GetPeopleAsync();
}

async void OnButtonClicked(object sender, EventArgs e)
{
    if (!string.IsNullOrWhiteSpace(nameEntry.Text) && !string.IsNullOrWhiteSpace(ageEntry.Text))
    {
        await App.Database.SavePersonAsync(new Person
        {
            Name = nameEntry.Text,
            Age = int.Parse(ageEntry.Text)
        });

        nameEntry.Text = ageEntry.Text = string.Empty;
        collectionView.ItemsSource = await App.Database.GetPeopleAsync();
    }
}

七、其他模块

1. 持久性

Properties 字典会自动保存到设备中。 当应用程序从后台返回,甚或在其重启后,添加到字典中的数据将可用。

Xamarin.Forms 1.4 在 Application 类上引入了其他方法 (SavePropertiesAsync()),可调用该方法来主动保存 Properties 字典。 这是为了让用户能够在重要更新后保存属性,而不用冒因崩溃或被 OS 终止而无法将这些属性序列化的风险。

2.使用命令接口ButtonDemo

1.页面的跳转,基础设置

//app.xaml
MainPage = new NavigationPage(new MainPage());
//MainPage.xaml
 xmlns:local="clr-namespace:student.Page"
<Button Text="页面的跳转" 
                Command="{Binding NavigateCommand}"
                CommandParameter="{x:Type local:Page1}"/>
 public ICommand NavigateCommand { private set; get; }
 NavigateCommand = new Command<Type>(async (Type pageType) =>
{
     Xamarin.Forms.Page page = (Xamarin.Forms.Page)Activator.CreateInstance(pageType);
     await Navigation.PushAsync(page);
 });
 BindingContext = this;

2.BasicButtonClickPage.xaml

<StackLayout>   
        <Label x:Name="label"
               Text="Click the Button below"
               FontSize="Large"
               VerticalOptions="CenterAndExpand" 
               HorizontalOptions="Center" />
        <Button Text="Click to Rotate Text!"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                Clicked="OnButtonClicked" /        
</StackLayout>
async void OnButtonClicked(object sender, EventArgs args)
{
    await label.RelRotateTo(360, 1000);
}

3.CodeButtonClickPage.cs

public CodeButtonClickPage ()
{
    Title = "Code Button Click";
    Label label = new Label
    {
        Text = "Click the Button below",
        FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
        VerticalOptions = LayoutOptions.CenterAndExpand,
        HorizontalOptions = LayoutOptions.Center
    };
    Button button = new Button
    {
        Text = "Click to Rotate Text!",
        VerticalOptions = LayoutOptions.CenterAndExpand,
        HorizontalOptions = LayoutOptions.Center
    };
    button.Clicked += async (sender, args) => await label.RelRotateTo(360, 1000);

    Content = new StackLayout
    {
        Children =
        {
            label,
            button
        }
    };
}

4.BasicButtonCommandPage.xaml

 xmlns:local="clr-namespace:ButtonDemos"
<ContentPage.BindingContext>
    <local:CommandDemoViewModel />
</ContentPage.BindingContext>
<StackLayout>
    <Label Text="{Binding Number, StringFormat='Value is now {0}'}"
           FontSize="Large"
           VerticalOptions="CenterAndExpand" 
           HorizontalOptions="Center" />

    <Button Text="Multiply by 2"
            VerticalOptions="CenterAndExpand"
            HorizontalOptions="Center"
            Command="{Binding MultiplyBy2Command}" />

    <Button Text="Divide by 2"
            VerticalOptions="CenterAndExpand"
            HorizontalOptions="Center"
            Command="{Binding DivideBy2Command}" />
</StackLayout>
//CommandDemoViewModel.cs
class CommandDemoViewModel : INotifyPropertyChanged
{
    double number = 1;
    public event PropertyChangedEventHandler PropertyChanged;
    public CommandDemoViewModel()
    {
        MultiplyBy2Command = new Command(() => Number *= 2);
        DivideBy2Command = new Command(() => Number /= 2);
    }
    public double Number
    {
        set
        {
            if (number != value)
            {
                number = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Number"));
            }
        }
        get { return number;}
    }
    public ICommand MultiplyBy2Command { private set; get; }
    public ICommand DivideBy2Command { private set; get; }
}

5.PressAndReleaseButtonPage.xaml

<StackLayout>
    <Label x:Name="label"
           Text="Press and hold the Button below"
           FontSize="Large"
           VerticalOptions="CenterAndExpand" 
           HorizontalOptions="Center" />
    <Button Text="Press to Rotate Text!"
            VerticalOptions="CenterAndExpand"
            HorizontalOptions="Center"
            Pressed="OnButtonPressed"
            Released="OnButtonReleased" />
</StackLayout>
namespace ButtonDemos
{
	public partial class PressAndReleaseButtonPage : ContentPage
	{
        bool animationInProgress = false;
        Stopwatch stopwatch = new Stopwatch();
		public PressAndReleaseButtonPage ()
		{
			InitializeComponent ();
		}
        void OnButtonPressed(object sender, EventArgs args)
        {
            stopwatch.Start();
            animationInProgress = true;
           Device.StartTimer(TimeSpan.FromMilliseconds(16), () =>
            {
                label.Rotation = 360 * (stopwatch.Elapsed.TotalSeconds % 1);

                return animationInProgress;
            });
        }
        void OnButtonReleased(object sender, EventArgs args)
        {
            animationInProgress = false;
            stopwatch.Stop();
        }
    }
}

6.ButtonAppearancePage.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:local="clr-namespace:ButtonDemos"
             x:Class="ButtonDemos.ButtonAppearancePage"
             Title="Button Appearance">
    <StackLayout>
        <Button x:Name="button"
                Text="Button"
                VerticalOptions="CenterAndExpand"
                HorizontalOptions="Center"
                TextColor="{Binding Source={x:Reference textColorPicker},
                                    Path=SelectedItem.Color}"
                BackgroundColor="{Binding Source={x:Reference backgroundColorPicker},
                                          Path=SelectedItem.Color}"
                BorderColor="{Binding Source={x:Reference borderColorPicker},
                                      Path=SelectedItem.Color}" />

        <StackLayout BindingContext="{x:Reference button}"
                     Padding="10">
            
            <Slider x:Name="fontSizeSlider"
                    Maximum="48"
                    Minimum="1"
                    Value="{Binding FontSize}" />

            <Label Text="{Binding Source={x:Reference fontSizeSlider},
                                  Path=Value,
                                  StringFormat='FontSize = {0:F0}'}"
                   HorizontalTextAlignment="Center" />

            <Slider x:Name="borderWidthSlider"
                    Minimum="-1"
                    Maximum="12"
                    Value="{Binding BorderWidth}" />
            
            <Label Text="{Binding Source={x:Reference borderWidthSlider}, 
                                  Path=Value,
                                  StringFormat='BorderWidth = {0:F0}'}"
                   HorizontalTextAlignment="Center" />

            <Slider x:Name="cornerRadiusSlider"
                    Minimum="-1"
                    Maximum="24"
                    Value="{Binding CornerRadius}" />

            <Label Text="{Binding Source={x:Reference cornerRadiusSlider}, 
                                  Path=Value,
                                  StringFormat='CornerRadius = {0:F0}'}"
                   HorizontalTextAlignment="Center" />

            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>

                <Grid.Resources>
                    <Style TargetType="Label">
                        <Setter Property="VerticalOptions" Value="Center" />
                    </Style>
                </Grid.Resources>

                <Label Text="Text Color:"
                       Grid.Row="0" Grid.Column="0" />

                <Picker x:Name="textColorPicker"
                        ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
                        ItemDisplayBinding="{Binding FriendlyName}"
                        SelectedIndex="0"
                        Grid.Row="0" Grid.Column="1" />

                <Label Text="Background Color:"
                       Grid.Row="1" Grid.Column="0" />

                <Picker x:Name="backgroundColorPicker"
                        ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
                        ItemDisplayBinding="{Binding FriendlyName}"
                        SelectedIndex="0"
                        Grid.Row="1" Grid.Column="1" />

                <Label Text="Border Color:"
                       Grid.Row="2" Grid.Column="0" />

                <Picker x:Name="borderColorPicker"
                        ItemsSource="{Binding Source={x:Static local:NamedColor.All}}"
                        ItemDisplayBinding="{Binding FriendlyName}"
                        SelectedIndex="0"
                        Grid.Row="2" Grid.Column="1" />
            </Grid>
        </StackLayout>
    </StackLayout>
</ContentPage>

//NamedColor.cs
namespace ButtonDemos
{
    public class NamedColor 
    {
        static StringBuilder stringBuilder = new StringBuilder();

        // Instance members.
        private NamedColor()
        {
        }

        public string Name { private set; get; }

        public string FriendlyName { private set; get; }

        public Color Color { private set; get; }

        public string RgbDisplay { private set; get; }

        // Static members.
        static NamedColor()
        {
            List<NamedColor> all = new List<NamedColor>();

            // Loop through the public static properties of the Color structure.
            foreach (PropertyInfo propInfo in typeof(Color).GetRuntimeProperties())
            {
                if (propInfo.GetMethod.IsPublic &&
                    propInfo.GetMethod.IsStatic &&
                    propInfo.PropertyType == typeof(Color))
                {
                    all.Add(CreateNamedColor(propInfo.Name, (Color)propInfo.GetValue(null)));
                }
            }

            // Loop through the public static fields of the Color structure.
            foreach (FieldInfo fieldInfo in typeof(Color).GetRuntimeFields())
            {
                if (fieldInfo.IsPublic &&
                    fieldInfo.IsStatic &&
                    fieldInfo.FieldType == typeof (Color))
                {
                    all.Add(CreateNamedColor(fieldInfo.Name, (Color)fieldInfo.GetValue(null)));
                }
            }
            all.TrimExcess();
            All = all;
        }

        public static IList<NamedColor> All { private set; get; }

        static NamedColor CreateNamedColor(string name, Color color)
        {
            // Convert the name to a friendly name.
            stringBuilder.Clear();
            int index = 0;

            foreach (char ch in name)
            {
                if (index != 0 && Char.IsUpper(ch))
                {
                    stringBuilder.Append(' ');
                }
                stringBuilder.Append(ch);
                index++;
            }

            NamedColor namedColor = new NamedColor
            {
                Name = name,
                FriendlyName = stringBuilder.ToString(),
                Color = color,
                RgbDisplay = String.Format("{0:X2}-{1:X2}-{2:X2}",
                                           (int)(255 * color.R),
                                           (int)(255 * color.G),
                                           (int)(255 * color.B))
            };

            return namedColor;
        }
    }
}

7.ImageButtonDemoPage.xaml

<FlexLayout Direction="Column"
           JustifyContent="SpaceEvenly"
           AlignItems="Center">
   
   <FlexLayout.Resources>
       <Style TargetType="Button">
           <Setter Property="ImageSource">
               <OnPlatform x:TypeArguments="ImageSource">
                   <On Platform="iOS, Android" Value="MonkeyFace.png" />
                   <On Platform="UWP" Value="Assets/MonkeyFace.png" />
               </OnPlatform>
           </Setter>
       </Style>
   </FlexLayout.Resources>

   <Button>
       <Button.ImageSource>
           <OnPlatform x:TypeArguments="ImageSource">
               <On Platform="iOS, Android" Value="MonkeyFace.png" />
               <On Platform="UWP" Value="Assets/MonkeyFace.png" />
           </OnPlatform>
       </Button.ImageSource>
   </Button>

   <Button Text="Default" />

   <Button Text="Left - 10"
           ContentLayout="Left, 10" />

   <Button Text="Top - 10"
           ContentLayout="Top, 10" />

   <Button Text="Right - 20"
           ContentLayout="Right, 20" />

   <Button Text="Bottom - 20" 
           ContentLayout="Bottom, 20" />
</FlexLayout>

总结

这是基本。
posted @ 2022-04-12 07:14  cactus9  阅读(57)  评论(0编辑  收藏  举报