您现在的位置是:网站首页> .NET Core
MAUI与Blazor学习经验总结
- .NET Core
- 2024-07-05
- 333人已阅读
MAUI与Blazor学习经验总结
MAUI学习经验总结
MAUI基础组件
MAUI(Multi-platform App UI)提供了丰富的UI组件,用于构建跨平台的应用程序界面。以下是MAUI中常用的UI组件:
Label:
用于显示文本的控件。
支持设置文本内容、字体、颜色、对齐方式等属性。
Button:
表示可点击的按钮控件。
可以设置文本、图标、样式等属性。
提供点击事件用于处理用户交互。
Entry:
用于接受用户输入的单行文本框控件。
可以设置占位符、键盘类型、最大长度等属性。
Editor:
用于接受用户输入的多行文本框控件。
支持设置文本内容、字体、颜色等属性。
CheckBox:
表示复选框控件,用于选择或取消选择某个选项。
可以设置选中状态、文本内容等属性。
RadioButton:
表示单选按钮控件,用于在多个选项中选择一个。
可以设置选中状态、文本内容等属性。
Slider:
表示滑块控件,用于在指定范围内选择一个值。
可以设置最小值、最大值、步长等属性。
Switch:
表示开关控件,用于切换某个选项的开启或关闭状态。
可以设置开启/关闭状态、颜色等属性。
Picker:
表示选择器控件,用于从多个选项中选择一个值。
可以设置选项列表、选中项等属性。
DatePicker:
表示日期选择器控件,用于选择日期。
可以设置日期范围、格式等属性。
TimePicker:
表示时间选择器控件,用于选择时间。
可以设置时间范围、格式等属性。
ListView:
用于显示项目列表的控件。
支持数据绑定、项目模板、选择事件等功能。
CollectionView:
用于显示项目集合的控件,提供更灵活的布局和自定义选项。
支持数据绑定、项目模板、选择事件等功能。
CarouselView:
用于显示可滚动的项目轮播图的控件。
支持自动播放、循环、指示器等功能。
Image:
用于显示图像的控件。
支持本地图像和网络图像的加载和显示。
WebView:
用于在应用程序中嵌入和显示网页内容的控件。
支持导航、加载HTML内容等功能。
除了这些常用的UI组件,MAUI还提供了其他一些专业的控件,如地图控件、图表控件、条形码扫描控件等,用于满足特定的应用场景需求。
MAUI的布局组件
MAUI(Multi-platform App UI)提供了多种布局组件,用于构建响应式和灵活的用户界面。以下是 MAUI 中常用的布局组件:
StackLayout:
以垂直或水平方向堆叠子元素的布局。
子元素按照添加的顺序依次排列。
可以设置间距、对齐方式等属性。
Grid:
将子元素放置在由行和列定义的网格中的布局。
可以灵活地控制行和列的大小、比例、对齐方式等。
支持合并单元格和设置行列间距。
FlexLayout:
基于 CSS Flexbox 布局模型的布局容器。
提供了灵活的布局选项,如对齐、换行、排列方向等。
适用于创建自适应和响应式的界面布局。
AbsoluteLayout:
通过指定子元素的绝对位置和大小来进行布局。
子元素的位置可以使用像素值或相对于容器的比例来指定。
适用于需要精确控制元素位置的场景。
RelativeLayout:
通过相对位置关系来布局子元素。
可以相对于容器或其他子元素来定位。
支持设置锚点、对齐方式、偏移量等。
ScrollView:
提供滚动功能的布局容器。
当子元素的内容超出可见区域时,可以滚动查看。
可以设置滚动方向、滚动条可见性等属性。
Frame:
用于为单个子元素提供边框和背景的装饰性布局。
可以设置边框样式、颜色、阴影等属性。
ContentView:
用于包装单个子元素的简单布局。
可以用作自定义控件的基类或用于分组和样式化。
Border:
为子元素提供边框和背景的装饰性布局。
类似于 Frame,但提供了更灵活的边框设置选项。
除了这些内置的布局组件,MAUI 还支持自定义布局和组合使用多个布局来创建复杂的界面结构。你可以根据具体的界面设计需求选择合适的布局组件,并通过组合和嵌套布局来实现所需的布局效果。
同时,MAUI 还提供了一些布局相关的属性和方法,如 Margin、Padding、Alignment、Spacing 等,用于进一步控制和调整布局的样式和行为。
在运行时加载 XAML
string navigationButtonXAML = "<Button Text=\"Navigate\" />";
Button navigationButton = new Button().LoadFromXaml(navigationButtonXAML);
...
stackLayout.Add(navigationButton);
string pageXAML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<ContentPage xmlns=\"http://schemas.microsoft.com/dotnet/2021/maui\"\nxmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\nx:Class=\"LoadRuntimeXAML.CatalogItemsPage\"\nTitle=\"Catalog Items\">\n</ContentPage>";
ContentPage page = new ContentPage().LoadFromXaml(pageXAML);
await Navigation.PushAsync(page);
访问元素
string pageXAML = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<ContentPage xmlns=\"http://schemas.microsoft.com/dotnet/2021/maui\"\nxmlns:x=\"http://schemas.microsoft.com/winfx/2009/xaml\"\nx:Class=\"LoadRuntimeXAML.CatalogItemsPage\"\nTitle=\"Catalog Items\">\n<StackLayout>\n<Label x:Name=\"monkeyName\"\n />\n</StackLayout>\n</ContentPage>";
ContentPage page = new ContentPage().LoadFromXaml(pageXAML);
Label monkeyLabel = page.FindByName<Label>("monkeyName");
monkeyLabel.Text = "Seated Monkey";
数据绑定基础
数据绑定连接两个对象的属性,即源和目标。 在代码中,以下两个步骤是必需的:
1.目标对象的 BindingContext 属性必须设置为源对象,
2.必须在目标对象上调用 SetBinding 方法(通常与 Binding 类结合使用),将该对象的属性绑定到源对象的属性。
视图与视图绑定
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="XamlSamples.SliderBindingsPage"
Title="Slider Bindings Page">
<StackLayout>
<Label Text="ROTATION"
x:Name="label"
BindingContext="{x:Reference slider}"
Rotation="{Binding Path=Value}"
FontAttributes="Bold"
FontSize="18"
HorizontalOptions="Center"
VerticalOptions="Center" />
<Slider x:Name="slider"
Maximum="360"
VerticalOptions="Center" />
<Label BindingContext="{x:Reference slider}"
Text="{Binding Value, StringFormat='The angle is {0:F0} degrees'}"
FontAttributes="Bold"
FontSize="18"
HorizontalOptions="Center"
VerticalOptions="Center" />
</StackLayout>
</ContentPage>
用代码方式:
InitializeComponent();
label.BindingContext = slider;
label.SetBinding(Label.RotationProperty, "Value");
ListView的一个例子
using System.Reflection;
using System.Text;
namespace XamlSamples
{
public class NamedColor
{
public string Name { get; private set; }
public string FriendlyName { get; private set; }
public Color Color { get; private set; }
// Expose the Color fields as properties
public float Red => Color.Red;
public float Green => Color.Green;
public float Blue => Color.Blue;
public static IEnumerable<NamedColor> All { get; private set; }
static NamedColor()
{
List<NamedColor> all = new List<NamedColor>();
StringBuilder stringBuilder = new StringBuilder();
// Loop through the public static fields of the Color structure.
foreach (FieldInfo fieldInfo in typeof(Colors).GetRuntimeFields())
{
if (fieldInfo.IsPublic &&
fieldInfo.IsStatic &&
fieldInfo.FieldType == typeof(Color))
{
// Convert the name to a friendly name.
string name = fieldInfo.Name;
stringBuilder.Clear();
int index = 0;
foreach (char ch in name)
{
if (index != 0 && Char.IsUpper(ch))
{
stringBuilder.Append(' ');
}
stringBuilder.Append(ch);
index++;
}
// Instantiate a NamedColor object.
NamedColor namedColor = new NamedColor
{
Name = name,
FriendlyName = stringBuilder.ToString(),
Color = (Color)fieldInfo.GetValue(null)
};
// Add it to the collection.
all.Add(namedColor);
}
}
all.TrimExcess();
All = all;
}
}
}
使用 x:Static 标记扩展可以将静态 NamedColor.All 属性设置为 ListView 的 ItemsSource:
XAML
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples"
x:Class="XamlSamples.ListViewDemoPage"
Title="ListView Demo Page">
<ContentPage.Resources>
<x:Double x:Key="boxSize">50</x:Double>
<x:Int32 x:Key="rowHeight">60</x:Int32>
<local:FloatToIntConverter x:Key="intConverter" />
</ContentPage.Resources>
<ListView ItemsSource="{x:Static local:NamedColor.All}"
RowHeight="{StaticResource rowHeight}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="5, 5, 0, 5"
Orientation="Horizontal"
Spacing="15">
<BoxView WidthRequest="{StaticResource boxSize}"
HeightRequest="{StaticResource boxSize}"
Color="{Binding Color}" />
<StackLayout Padding="5, 0, 0, 0"
VerticalOptions="Center">
<Label Text="{Binding FriendlyName}"
FontAttributes="Bold"
FontSize="14" />
<StackLayout Orientation="Horizontal"
Spacing="0">
<Label Text="{Binding Red,
Converter={StaticResource intConverter},
ConverterParameter=255,
StringFormat='R={0:X2}'}" />
<Label Text="{Binding Green,
Converter={StaticResource intConverter},
ConverterParameter=255,
StringFormat=', G={0:X2}'}" />
<Label Text="{Binding Blue,
Converter={StaticResource intConverter},
ConverterParameter=255,
StringFormat=', B={0:X2}'}" />
</StackLayout>
</StackLayout>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
数据绑定和 MVVM
固定简单的绑定
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard"
x:Class="XamlSamples.OneShotDateTimePage"
Title="One-Shot DateTime Page">
<VerticalStackLayout BindingContext="{x:Static sys:DateTime.Now}"
Spacing="25" Padding="30,0"
VerticalOptions="Center" HorizontalOptions="Center">
<Label Text="{Binding Year, StringFormat='The year is {0}'}" />
<Label Text="{Binding StringFormat='The month is {0:MMMM}'}" />
<Label Text="{Binding Day, StringFormat='The day is {0}'}" />
<Label Text="{Binding StringFormat='The time is {0:T}'}" />
</VerticalStackLayout>
</ContentPage>
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace XamlSamples;
class ClockViewModel: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private DateTime _dateTime;
private Timer _timer;
public DateTime DateTime
{
get => _dateTime;
set
{
if (_dateTime != value)
{
_dateTime = value;
OnPropertyChanged(); // reports this property
}
}
}
public ClockViewModel()
{
this.DateTime = DateTime.Now;
// Update the DateTime property every second.
_timer = new Timer(new TimerCallback((s) => this.DateTime = DateTime.Now),
null, TimeSpan.Zero, TimeSpan.FromSeconds(1));
}
~ClockViewModel() =>
_timer.Dispose();
public void OnPropertyChanged([CallerMemberName] string name = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
视图模型通常实现 INotifyPropertyChanged 接口,该接口可让类在其任何一个属性发生更改时引发 PropertyChanged 事件。
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples"
x:Class="XamlSamples.ClockPage"
Title="Clock Page">
<ContentPage.BindingContext>
<local:ClockViewModel />
</ContentPage.BindingContext>
<Label Text="{Binding DateTime, StringFormat='{0:T}'}"
FontSize="18"
HorizontalOptions="Center"
VerticalOptions="Center" />
</ContentPage>
稍微复杂点儿
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace XamlSamples;
class HslViewModel: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private float _hue, _saturation, _luminosity;
private Color _color;
public float Hue
{
get => _hue;
set
{
if (_hue != value)
Color = Color.FromHsla(value, _saturation, _luminosity);
}
}
public float Saturation
{
get => _saturation;
set
{
if (_saturation != value)
Color = Color.FromHsla(_hue, value, _luminosity);
}
}
public float Luminosity
{
get => _luminosity;
set
{
if (_luminosity != value)
Color = Color.FromHsla(_hue, _saturation, value);
}
}
public Color Color
{
get => _color;
set
{
if (_color != value)
{
_color = value;
_hue = _color.GetHue();
_saturation = _color.GetSaturation();
_luminosity = _color.GetLuminosity();
OnPropertyChanged("Hue");
OnPropertyChanged("Saturation");
OnPropertyChanged("Luminosity");
OnPropertyChanged(); // reports this property
}
}
}
public void OnPropertyChanged([CallerMemberName] string name = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
XAML
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples"
x:Class="XamlSamples.HslColorScrollPage"
Title="HSL Color Scroll Page">
<ContentPage.BindingContext>
<local:HslViewModel Color="Aqua" />
</ContentPage.BindingContext>
<VerticalStackLayout Padding="10, 0, 10, 30">
<BoxView Color="{Binding Color}"
HeightRequest="100"
WidthRequest="100"
HorizontalOptions="Center" />
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}"
HorizontalOptions="Center" />
<Slider Value="{Binding Hue}"
Margin="20,0,20,0" />
<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}"
HorizontalOptions="Center" />
<Slider Value="{Binding Saturation}"
Margin="20,0,20,0" />
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}"
HorizontalOptions="Center" />
<Slider Value="{Binding Luminosity}"
Margin="20,0,20,0" />
</VerticalStackLayout>
</ContentPage>
接口ICommand
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Input;
namespace XamlSamples;
class KeypadViewModel: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _inputString = "";
private string _displayText = "";
private char[] _specialChars = { '*', '#' };
public ICommand AddCharCommand { get; private set; }
public ICommand DeleteCharCommand { get; private set; }
public string InputString
{
get => _inputString;
private set
{
if (_inputString != value)
{
_inputString = value;
OnPropertyChanged();
DisplayText = FormatText(_inputString);
// Perhaps the delete button must be enabled/disabled.
((Command)DeleteCharCommand).ChangeCanExecute();
}
}
}
public string DisplayText
{
get => _displayText;
private set
{
if (_displayText != value)
{
_displayText = value;
OnPropertyChanged();
}
}
}
public KeypadViewModel()
{
// Command to add the key to the input string
AddCharCommand = new Command<string>((key) => InputString += key);
// Command to delete a character from the input string when allowed
DeleteCharCommand =
new Command(
// Command will strip a character from the input string
() => InputString = InputString.Substring(0, InputString.Length - 1),
// CanExecute is processed here to return true when there's something to delete
() => InputString.Length > 0
);
}
string FormatText(string str)
{
bool hasNonNumbers = str.IndexOfAny(_specialChars) != -1;
string formatted = str;
// Format the string based on the type of data and the length
if (hasNonNumbers || str.Length < 4 || str.Length > 10)
{
// Special characters exist, or the string is too small or large for special formatting
// Do nothing
}
else if (str.Length < 8)
formatted = string.Format("{0}-{1}", str.Substring(0, 3), str.Substring(3));
else
formatted = string.Format("({0}) {1}-{2}", str.Substring(0, 3), str.Substring(3, 3), str.Substring(6));
return formatted;
}
public void OnPropertyChanged([CallerMemberName] string name = "") =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
XAML
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:XamlSamples"
x:Class="XamlSamples.KeypadPage"
Title="Keypad Page">
<ContentPage.BindingContext>
<local:KeypadViewModel />
</ContentPage.BindingContext>
<Grid HorizontalOptions="Center" VerticalOptions="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<Label Text="{Binding DisplayText}"
Margin="0,0,10,0" FontSize="20" LineBreakMode="HeadTruncation"
VerticalTextAlignment="Center" HorizontalTextAlignment="End"
Grid.ColumnSpan="2" />
<Button Text="⇦" Command="{Binding DeleteCharCommand}" Grid.Column="2"/>
<Button Text="1" Command="{Binding AddCharCommand}" CommandParameter="1" Grid.Row="1" />
<Button Text="2" Command="{Binding AddCharCommand}" CommandParameter="2" Grid.Row="1" Grid.Column="1" />
<Button Text="3" Command="{Binding AddCharCommand}" CommandParameter="3" Grid.Row="1" Grid.Column="2" />
<Button Text="4" Command="{Binding AddCharCommand}" CommandParameter="4" Grid.Row="2" />
<Button Text="5" Command="{Binding AddCharCommand}" CommandParameter="5" Grid.Row="2" Grid.Column="1" />
<Button Text="6" Command="{Binding AddCharCommand}" CommandParameter="6" Grid.Row="2" Grid.Column="2" />
<Button Text="7" Command="{Binding AddCharCommand}" CommandParameter="7" Grid.Row="3" />
<Button Text="8" Command="{Binding AddCharCommand}" CommandParameter="8" Grid.Row="3" Grid.Column="1" />
<Button Text="9" Command="{Binding AddCharCommand}" CommandParameter="9" Grid.Row="3" Grid.Column="2" />
<Button Text="*" Command="{Binding AddCharCommand}" CommandParameter="*" Grid.Row="4" />
<Button Text="0" Command="{Binding AddCharCommand}" CommandParameter="0" Grid.Row="4" Grid.Column="1" />
<Button Text="#" Command="{Binding AddCharCommand}" CommandParameter="#" Grid.Row="4" Grid.Column="2" />
</Grid>
</ContentPage>
Blazor学习经验总结
上一篇:.NET Core开源库收集
下一篇:MAUI界面布局及UI组件总结