Communitytoolkit社区工具给我们开发带来了极大的方便,堪称魔法,非常好用,可以极大的提升企业和个人的开发效率,标注方法[ObservableProperty]、[RelayCommand]和一个方法SetProperty,下面举个例子演示一下。
写一个枚举 Microsoft.Maui.Graphics空间下类Colors的命名颜色,共148个公共静态字段,建一个maui程序名为NamedColorsDemoApp,先在文件夹/Models下建一个模型,NamedColor.cs,文件内容:
namespace NamedColorsDemoApp.Models
{
internal class NamedColor
{
public string Name { get; set; }
public Color Color { get; set; }
}
}
在程序内Nuget二个包
然后在文件夹/ViewModels 下创建NamedColorsViewModel.cs文件,文件头内容:
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NamedColorsDemoApp.Models;
using System.Collections.ObjectModel;
using System.Reflection;
这个类要派生自ObservableObject,且要设成分部类。
partial class NamedColorsViewModel : ObservableObject
{
}
创建一个私有的字段 private NamedColor namedColor,再创建一个列表字段allColors,这个带标注方法[ObservableProperty]
private NamedColor namedColor;
[ObservableProperty]
private static ObservableCollection<NamedColorsViewModel> allColors;
再创建二个可绑定的属性,使用SetProperty,这个太方便了。
public string Name
{
get => namedColor.Name;
set => SetProperty(namedColor.Name, value, namedColor, (n, v) => n.Name = v);
}
public Color Color
{
get => namedColor.Color;
set => SetProperty(namedColor.Color, value, namedColor, (n, v) => n.Color = v);
}
SetProperty第一个参数是要更新的值,第二个参数是新值,第三个参数是模型,传一个实例,第四个参数是回调动作,用lambda表达式很方便,注意lambda表达式不能捕获外部变量,像我这样起名应该是不会了,外部变量用单词,lambda用字母。
建一个IAsyncEnumerable<NamedColor> AsyncEnumerableAllColors()方法反射命名颜色
private static async IAsyncEnumerable<NamedColor> AsyncEnumerableAllColors()
{
foreach (FieldInfo fieldInfo in typeof(Colors).GetRuntimeFields())
{
if ((fieldInfo.FieldType == typeof(Color)) && fieldInfo.IsPublic &&
fieldInfo.IsStatic)
{
yield return new NamedColor { Color = (Color)fieldInfo.GetValue(null),
Name = fieldInfo.Name };
await Task.Delay(10);
}
}
}
再建一个带标注方法 [RelayCommand]
private async Task InitCollection()
[RelayCommand]
private async Task InitCollection()
{
AllColors.Clear();
await foreach (NamedColor named in AsyncEnumerableAllColors())
{
AllColors.Add(new NamedColorsViewModel() { Name = named.Name, Color =
named.Color });
}
}
完整代码内容
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using NamedColorsDemoApp.Models;
using System.Collections.ObjectModel;
using System.Reflection;
namespace NamedColorsDemoApp.ViewModels
{
partial class NamedColorsViewModel : ObservableObject
{
private NamedColor namedColor;
[ObservableProperty]
private static ObservableCollection<NamedColorsViewModel> allColors;
public string Name
{
get => namedColor.Name;
set => SetProperty(namedColor.Name, value, namedColor, (n, v) => n.Name = v);
}
public Color Color
{
get => namedColor.Color;
set => SetProperty(namedColor.Color, value, namedColor, (n, v) => n.Color =
v);
}
public NamedColorsViewModel()
{
namedColor = new NamedColor();
}
static NamedColorsViewModel()
{
allColors = new ObservableCollection<NamedColorsViewModel>();
}
private static async IAsyncEnumerable<NamedColor> AsyncEnumerableAllColors()
{
foreach (FieldInfo fieldInfo in typeof(Colors).GetRuntimeFields())
{
if ((fieldInfo.FieldType == typeof(Color)) && fieldInfo.IsPublic &&
fieldInfo.IsStatic)
{
yield return new NamedColor { Color =
(Color)fieldInfo.GetValue(null), Name = fieldInfo.Name };
await Task.Delay(10);
}
}
}
[RelayCommand]
private async Task InitCollection()
{
AllColors.Clear();
await foreach (NamedColor named in AsyncEnumerableAllColors())
{
AllColors.Add(new NamedColorsViewModel() { Name = named.Name, Color =
named.Color });
}
}
}
}
在文件夹Views下视图文件NamedColorsPage.xaml,在这个文件内引用这些
xmlns:viewmodels="clr-namespace:NamedColorsDemoApp.ViewModels"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
在这个页面上添加行为,目的是把Appearing事件绑定到InitCollectionCommand上,注意这个命令在viewmodel里是没有的,标注方法自动加上的,非常有意思,省力。
<ContentPage.Behaviors>
<toolkit:EventToCommandBehavior EventName="Appearing" Command="{Binding
InitCollectionCommand}"/>
</ContentPage.Behaviors>
完整的页面内容,CollectionView.ItemsSource绑定的AllColors也是标注方法自动生成的。
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:viewmodels="clr-namespace:NamedColorsDemoApp.ViewModels"
xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
x:Class="NamedColorsDemoApp.Views.NamedColorsPage"
Title="命名颜色">
<ContentPage.Behaviors>
<toolkit:EventToCommandBehavior EventName="Appearing" Command="{Binding
InitCollectionCommand}"/>
</ContentPage.Behaviors>
<ContentPage.Resources>
<toolkit:ColorToHexRgbStringConverter x:Key="colorToRgbConverter"/>
<toolkit:ColorToCmykStringConverter x:Key="colorToCMYKConverter"/>
</ContentPage.Resources>
<ContentPage.BindingContext>
<viewmodels:NamedColorsViewModel/>
</ContentPage.BindingContext>
<Grid RowDefinitions="Auto,*" Margin="5" RowSpacing="5">
<Label Text="{Binding AllColors.Count,StringFormat='命名颜色数:{0}'}" Padding="5"
BackgroundColor="DarkCyan" TextColor="White"/>
<Border StrokeThickness="8" StrokeShape="RoundRectangle 20,20,0,40" Stroke="
{Binding Color}" Padding="12" Grid.Row="1" BindingContext="{Binding
Source={x:Reference colorsCollection},Path=SelectedItem}">
<CollectionView Grid.Row="1" ItemsSource="{Binding AllColors}"
SelectionMode="Single" x:Name="colorsCollection" BindingContext="{Binding
Source={RelativeSource AncestorLevel=1,AncestorType={x:Type ContentPage}
},Path=BindingContext}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid RowDefinitions="*,*,*" ColumnDefinitions="Auto,*"
RowSpacing="5" ColumnSpacing="5">
<BoxView Color="{Binding Color}" WidthRequest="50"
HeightRequest="50" Grid.RowSpan="3"/>
<Label Text="{Binding Name}" FontAttributes="Bold"
VerticalOptions="Center" Grid.Column="1"/>
<Label Text="{Binding Color,Converter={x:StaticResource
colorToRgbConverter},StringFormat='RGB={0}'}"
VerticalOptions="Center" Grid.Row="1" Grid.Column="1"/>
<Label Text="{Binding Color,Converter={x:StaticResource
colorToCMYKConverter}}" VerticalOptions="End" Grid.Row="2"
Grid.Column="1"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Border>
</Grid>
</ContentPage>
Android下运行
Windows下运行