.NET Multi-platform App UI (.NET MAUI) Button 显示文本,并响应点击或单击指示应用执行任务。 Button 通常显示一个指示命令的短文本字符串,但它也可以显示位图图像或文本和图像的组合。 当用手指按下或用鼠标单击 Button 时,它会启动该命令。
Button 定义以下属性:
-
BorderColor,类型为Color,描述按钮的边框颜色。 -
BorderWidth,类型的double定义按钮边框的宽度。 -
CharacterSpacing,类型为double,用于定义按钮文本的字符间距。 -
Command定义了在点击按钮时要执行的命令,其类型为 ICommand。 -
CommandParameter是类型为object的传递给Command的参数。 -
ContentLayout,类型的ButtonContentLayout定义一个对象,该对象控制按钮图像的位置以及按钮图像与文本之间的间距。 -
CornerRadius类型的int描述按钮边框的圆角半径。 -
FontAttributes,FontAttributes类型确定文本样式。 -
bool类型的FontAutoScalingEnabled定义按钮文本是否会反映操作系统中设置的缩放首选项。 此属性的默认值为true。 -
FontFamily类型的string定义了字体系列。 -
FontSize,类型为double,定义字号。 - ImageSource,类型为 ImageSource,指定显示为按钮内容的位图图像。
-
LineBreakMode,类型为LineBreakMode,决定在无法容纳一行时应如何处理文本。 -
Padding,Thickness类型,确定按钮的内边距。 -
Text定义了类型为string的按钮内容文本。 -
TextColor的类型 Color 描述按钮文本的颜色。 -
TextTransform的类型TextTransform定义了按钮文本的大小写。
这些属性由 BindableProperty 对象提供支持,表示它们可以是数据绑定的目标,并可以设置样式。
注意
虽然 Button 定义了一个 ImageSource 属性,该属性允许你在 Button 上面显示图像,但该属性适合在当 Button 文本旁边显示小图标时使用。
此外,Button 还定义 Clicked、Pressed 与 Released 事件。 当用手指点击 Clicked 或者从按钮表面释放鼠标指针时,将引发 Button 事件。 当手指按下 Pressed 或者当指针位于 Button 上方的同时按下鼠标按钮时,将引发 Button 事件。 释放手指或鼠标按钮时,将引发 Released 事件。 通常,Clicked 事件还与 Released 事件同时引发,但如果手指或鼠标指针在从 Button 表面移开后释放,则可能不会发生 Clicked 事件。
重要
Button 必须将其 IsEnabled 属性设置为 true 后才能够对点击做出响应。
创建按钮
若要创建按钮,请创建 Button 对象并处理其 Clicked 事件。
以下 XAML 示例展示了如何创建 Button:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ButtonDemos.BasicButtonClickPage"
Title="Basic Button Click">
<StackLayout>
<Button Text="Click to Rotate Text!"
VerticalOptions="Center"
HorizontalOptions="Center"
Clicked="OnButtonClicked" />
<Label x:Name="label"
Text="Click the Button above"
FontSize="18"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ContentPage>
Text 属性指定在 Button 中显示的文本。
Clicked 事件设置为名为 OnButtonClicked 的事件处理程序。 此处理程序位于后台代码文件中。
public partial class BasicButtonClickPage : ContentPage
{
public BasicButtonClickPage ()
{
InitializeComponent ();
}
async void OnButtonClicked(object sender, EventArgs args)
{
await label.RelRotateTo(360, 1000);
}
}
public partial class BasicButtonClickPage : ContentPage
{
public BasicButtonClickPage ()
{
InitializeComponent ();
}
async void OnButtonClicked(object sender, EventArgs args)
{
await label.RelRotateToAsync(360, 1000);
}
}
在此示例中,点击 Button 时,将执行 OnButtonClicked 方法。
sender 参数是负责此事件的 Button 对象。 可以使用此参数访问 Button 对象,或区分共享同一 Button 事件的多个 Clicked 对象。
Clicked 处理程序调用一个动画函数,该函数以 1000 毫秒为单位旋转 Label 360 度:
创建 Button 的等效 C# 代码为:
Button button = new Button
{
Text = "Click to Rotate Text!",
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center
};
button.Clicked += async (sender, args) => await label.RelRotateTo(360, 1000);
Button button = new Button
{
Text = "Click to Rotate Text!",
VerticalOptions = LayoutOptions.Center,
HorizontalOptions = LayoutOptions.Center
};
button.Clicked += async (sender, args) => await label.RelRotateToAsync(360, 1000);
使用命令接口
应用无需处理 Clicked 事件即可响应 Button 点击。
Button 执行称作命令或发布命令接口的替代通知机制。 这包含两个属性:
-
Command类型的 ICommand(在System.Windows.Input命名空间中定义的接口) -
CommandParameter类型的Object属性
此方法特别适用于数据绑定,尤其是在实现 Model-View-ViewModel (MVVM) 模式时。 在 MVVM 应用程序中,viewmodel 定义 ICommand 类型的属性,这些属性随后通过数据绑定连接到 Button 对象。 .NET MAUI 还定义了实现 Command 接口的 Command<T> 和 ICommand 类,并帮助视图模型定义 ICommand 类型的属性。 有关每个命令的详细信息,请参阅命令。
下面的示例展示了一个非常简单的视图模型类,该类定义了一个名为 double 的 Number 类型属性,以及名为 ICommand 和 MultiplyBy2Command 的两个 DivideBy2Command 类型属性:
public class CommandDemoViewModel : INotifyPropertyChanged
{
double number = 1;
public event PropertyChangedEventHandler PropertyChanged;
public ICommand MultiplyBy2Command { get; private set; }
public ICommand DivideBy2Command { get; private set; }
public CommandDemoViewModel()
{
MultiplyBy2Command = new Command(() => Number *= 2);
DivideBy2Command = new Command(() => Number /= 2);
}
public double Number
{
get
{
return number;
}
set
{
if (number != value)
{
number = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Number"));
}
}
}
}
在本例中,两个 ICommand 属性是在类的构造函数中用两个 Command 类的对象初始化的。
Command 构造函数包含一个小函数(称为 execute 构造函数参数),可将 Number 属性的值加倍或减半。
以下 XAML 示例使用了 CommandDemoViewModel 类:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:ButtonDemos"
x:Class="ButtonDemos.BasicButtonCommandPage"
Title="Basic Button Command"
x:DataType="local:CommandDemoViewModel">
<ContentPage.BindingContext>
<local:CommandDemoViewModel />
</ContentPage.BindingContext>
<StackLayout>
<Label Text="{Binding Number, StringFormat='Value is now {0}'}"
FontSize="18"
VerticalOptions="Center"
HorizontalOptions="Center" />
<Button Text="Multiply by 2"
VerticalOptions="Center"
HorizontalOptions="Center"
Command="{Binding MultiplyBy2Command}" />
<Button Text="Divide by 2"
VerticalOptions="Center"
HorizontalOptions="Center"
Command="{Binding DivideBy2Command}" />
</StackLayout>
</ContentPage>
在本例中,Label 元素和两个 Button 对象包含与 CommandDemoViewModel 类中三个属性的绑定。 点击两个 Button 对象时,将执行命令,数字的值也随之改变。 与 Clicked 处理程序相比,这种方法的优势在于,涉及该页面功能的所有逻辑都位于视图模型中,而不是代码隐藏文件中,从而更好地将用户界面与业务逻辑分离。
Command 对象还可以控制 Button 对象的启用和禁用。 例如,假设你想将数值范围限制在 210 和 2-10 之间。 可以将另一个函数添加到构造函数(称为 canExecute 参数),如果应启用 true 则返回 Button :
public class CommandDemoViewModel : INotifyPropertyChanged
{
···
public CommandDemoViewModel()
{
MultiplyBy2Command = new Command(
execute: () =>
{
Number *= 2;
((Command)MultiplyBy2Command).ChangeCanExecute();
((Command)DivideBy2Command).ChangeCanExecute();
},
canExecute: () => Number < Math.Pow(2, 10));
DivideBy2Command = new Command(
execute: () =>
{
Number /= 2;
((Command)MultiplyBy2Command).ChangeCanExecute();
((Command)DivideBy2Command).ChangeCanExecute();
},
canExecute: () => Number > Math.Pow(2, -10));
}
···
}
在本例中,需要调用 ChangeCanExecute 的 Command 方法,以便 Command 方法能够调用 canExecute 方法,并确定 Button 是否应该禁用。 随着此代码更改,当数字达到限制时,Button 将被禁用。
也可以将两个或多个 Button 元素绑定到同一 ICommand 属性。 可以使用 Button 的 CommandParameter 属性来区分 Button 元素。 在这种情况下,需要使用通用 Command<T> 类。 然后,CommandParameter 对象将作为参数传递给 execute 和 canExecute 方法。 更多信息,请参阅 命令。
按下并松开按钮
当手指按下 Pressed 或者当指针位于 Button 上方的同时按下鼠标按钮时,将引发 Button 事件。 释放手指或鼠标按钮时,将引发 Released 事件。 通常,Clicked 事件还与 Released 事件同时引发,但如果手指或鼠标指针在从 Button 表面移开后释放,则可能不会发生 Clicked 事件。
下面的 XAML 示例显示了附加了 Pressed 和 Released 事件处理程序的 Label 和 Button:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="ButtonDemos.PressAndReleaseButtonPage"
Title="Press and Release Button">
<StackLayout>
<Button Text="Press to Rotate Text!"
VerticalOptions="Center"
HorizontalOptions="Center"
Pressed="OnButtonPressed"
Released="OnButtonReleased" />
<Label x:Name="label"
Text="Press and hold the Button above"
FontSize="18"
VerticalOptions="Center"
HorizontalOptions="Center" />
</StackLayout>
</ContentPage>
当 Label 事件发生时,代码隐藏文件会对 Pressed 进行动画处理,但当 Released 事件发生时,会暂停旋转:
public partial class PressAndReleaseButtonPage : ContentPage
{
IDispatcherTimer timer;
Stopwatch stopwatch = new Stopwatch();
public PressAndReleaseButtonPage()
{
InitializeComponent();
timer = Dispatcher.CreateTimer();
timer.Interval = TimeSpan.FromMilliseconds(16);
timer.Tick += (s, e) =>
{
label.Rotation = 360 * (stopwatch.Elapsed.TotalSeconds % 1);
};
}
void OnButtonPressed(object sender, EventArgs args)
{
stopwatch.Start();
timer.Start();
}
void OnButtonReleased(object sender, EventArgs args)
{
stopwatch.Stop();
timer.Stop();
}
}
结果是,Label仅在手指与Button接触时旋转,手指松开时停止旋转。
按钮可视状态
Button 有一个 PressedVisualState,在按下时可用于启动 Button 的视觉变化(前提是该功能已启用)。
下面的 XAML 示例显示了如何为 Pressed 状态定义可视化状态:
<Button Text="Click me!"
...>
<VisualStateManager.VisualStateGroups>
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal">
<VisualState.Setters>
<Setter Property="Scale"
Value="1" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="Pressed">
<VisualState.Setters>
<Setter Property="Scale"
Value="0.8" />
</VisualState.Setters>
</VisualState>
<VisualState x:Name="PointerOver" />
</VisualStateGroup>
</VisualStateGroupList>
</VisualStateManager.VisualStateGroups>
</Button>
在此示例中,PressedVisualState 指定在按下 Button 时,其 Scale 属性将从默认值 1 更改为 0.8。
Normal
VisualState 指定在 Button 处于正常状态时,其 Scale 属性将设置为 1。 因此,总体效果是,按下 Button 时,它被重新缩放为稍小的尺寸,而松开 Button 时,它被重新缩放为默认尺寸。
重要
若要使 Button 返回其 Normal 状态,VisualStateGroup 必须也定义 PointerOver 状态。 如果您使用 .NET MAUI 应用项目模板创建的样式 ResourceDictionary,那么您已经拥有一个隐式 PointerOver 样式,该样式定义了 Button 状态。
关于视觉状态的详细信息,请参阅视觉状态。
在按钮中使用位图
Button 类定义了一个 ImageSource 属性,通过该属性,你可以在 Button 上单独或结合文本显示一个小的位图图像。 你还可以指定文本和图像的排列方式。 该 ImageSource 属性的类型为 ImageSource,这意味着可以从文件、嵌入的资源、URI 或流加载位图。
无法将位图缩放以适应 Button。 最佳大小通常在 32 到 64 个独立于设备的单位之间,具体取决于你想要多大的位图。
你可以使用 Text 的 ImageSource 属性指定 Button 和 ContentLayout 属性在 Button 上的排列方式。 该属性的类型为 ButtonContentLayout,其构造函数有两个参数:
-
ImagePosition枚举的成员:Left、Top、Right或Bottom,表示位图相对于文本的显示方式。 - 文本和位图之间间距的
double值。
在 XAML 中,你可以创建 Button 并设置 ContentLayout 属性,方法是只指定枚举成员或间距,或以逗号分隔的任意顺序指定两者:
<Button Text="Button text"
ImageSource="button.png"
ContentLayout="Right, 20" />
等效 C# 代码如下:
Button button = new Button
{
Text = "Button text",
ImageSource = new FileImageSource
{
File = "button.png"
},
ContentLayout = new Button.ButtonContentLayout(Button.ButtonContentLayout.ImagePosition.Right, 20)
};
注意
Button如果包含文本和图像,则可能无法容纳按钮内的所有内容,因此应手动调整图像大小以实现所需的布局。
禁用按钮
有时,应用会进入一个状态,此时Button 单击不是有效操作。 在这种情况下,可以通过将 Button 的 IsEnabled 属性设置为 false 来对其进行禁用。