将Abp移植进.NET MAUI项目(三):构建UI层
很开心,终于到了创建页面的时候了!
我们需要两个页面
- MainPage 主页面
- MusicItemPage 条目编辑页面
编写主页面
新建一个MainPageViewModel.cs,作为MainPage的ViewModel层
public class MainPageViewModel : ViewModelBase
{
private readonly IRepository<Song, long> songRepository;
<span class="hljs-function"><span class="hljs-keyword">public <span class="hljs-title">MainPageViewModel(<span class="hljs-params">IRepository<Song, <span class="hljs-built_in">long> songRepository)
{
<span class="hljs-keyword">this.RefreshCommand=<span class="hljs-keyword">new Command(Refresh, (o) => <span class="hljs-literal">true);
<span class="hljs-keyword">this.DeleteCommand=<span class="hljs-keyword">new Command(Delete, (o) => <span class="hljs-literal">true);
<span class="hljs-keyword">this.songRepository=songRepository;
}
<span class="hljs-function"><span class="hljs-keyword">private <span class="hljs-keyword">void <span class="hljs-title">Delete(<span class="hljs-params"><span class="hljs-built_in">object obj)
{
songRepository.Delete(obj <span class="hljs-keyword">as Song);
}
<span class="hljs-function"><span class="hljs-keyword">private <span class="hljs-keyword">async <span class="hljs-keyword">void <span class="hljs-title">Refresh(<span class="hljs-params"><span class="hljs-built_in">object obj)
{
<span class="hljs-keyword">this.IsRefreshing=<span class="hljs-literal">true;
<span class="hljs-keyword">var getSongs = <span class="hljs-keyword">this.songRepository.GetAllListAsync();
<span class="hljs-keyword">await getSongs.ContinueWith(r => IsRefreshing=<span class="hljs-literal">false);
<span class="hljs-keyword">var songs = <span class="hljs-keyword">await getSongs;
<span class="hljs-keyword">this.Songs=<span class="hljs-keyword">new ObservableCollection<Song>(songs);
}
<span class="hljs-keyword">private ObservableCollection<Song> songs;
<span class="hljs-keyword">public ObservableCollection<Song> Songs
{
<span class="hljs-keyword">get { <span class="hljs-keyword">return songs; }
<span class="hljs-keyword">set
{
songs = <span class="hljs-keyword">value;
RaisePropertyChanged();
}
}
<span class="hljs-keyword">private Song currentSong;
<span class="hljs-keyword">public Song CurrentSong
{
<span class="hljs-keyword">get { <span class="hljs-keyword">return currentSong; }
<span class="hljs-keyword">set
{
currentSong = <span class="hljs-keyword">value;
RaisePropertyChanged();
}
}
<span class="hljs-keyword">private <span class="hljs-built_in">bool _isRefreshing;
<span class="hljs-keyword">public <span class="hljs-built_in">bool IsRefreshing
{
<span class="hljs-keyword">get { <span class="hljs-keyword">return _isRefreshing; }
<span class="hljs-keyword">set
{
_isRefreshing = <span class="hljs-keyword">value;
RaisePropertyChanged();
}
}
<span class="hljs-keyword">public Command RefreshCommand { <span class="hljs-keyword">get; <span class="hljs-keyword">set; }
<span class="hljs-keyword">public Command DeleteCommand { <span class="hljs-keyword">get; <span class="hljs-keyword">private <span class="hljs-keyword">set; }
}
新建一个MainPage页面
编写Xaml为:
注意这个页面将继承MauiBoilerplate.ContentPageBase
<?xml version="1.0" encoding="utf-8" ?>
<mato:ContentPageBase xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:mato="clr-namespace:MauiBoilerplate;assembly=MauiBoilerplate.Core"
x:Class="MauiBoilerplate.MainPage">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="155"></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<span class="hljs-tag"><<span class="hljs-name">Label <span class="hljs-attr">Text=<span class="hljs-string">"My Music" <span class="hljs-attr">FontSize=<span class="hljs-string">"65"><span class="hljs-tag"></<span class="hljs-name">Label>
<span class="hljs-tag"><<span class="hljs-name">ListView
<span class="hljs-attr">Grid.Row=<span class="hljs-string">"1"
<span class="hljs-attr">ItemsSource=<span class="hljs-string">"{Binding Songs,Mode=TwoWay}"
<span class="hljs-attr">x:Name=<span class="hljs-string">"MainListView"
<span class="hljs-attr">RowHeight=<span class="hljs-string">"74"
<span class="hljs-attr">IsPullToRefreshEnabled=<span class="hljs-string">"True"
<span class="hljs-attr">IsRefreshing=<span class="hljs-string">"{Binding IsRefreshing}"
<span class="hljs-attr">RefreshCommand=<span class="hljs-string">"{Binding RefreshCommand}"
<span class="hljs-attr">SelectedItem=<span class="hljs-string">"{Binding CurrentSong,Mode=TwoWay}">
<span class="hljs-tag"><<span class="hljs-name">ListView.Header>
<span class="hljs-tag"><<span class="hljs-name">Grid <span class="hljs-attr">HeightRequest=<span class="hljs-string">"96">
<span class="hljs-tag"><<span class="hljs-name">Grid.RowDefinitions>
<span class="hljs-tag"><<span class="hljs-name">RowDefinition><span class="hljs-tag"></<span class="hljs-name">RowDefinition>
<span class="hljs-tag"><<span class="hljs-name">RowDefinition><span class="hljs-tag"></<span class="hljs-name">RowDefinition>
<span class="hljs-tag"></<span class="hljs-name">Grid.RowDefinitions>
<span class="hljs-tag"><<span class="hljs-name">Button <span class="hljs-attr">Clicked=<span class="hljs-string">"AddButton_Clicked"
<span class="hljs-attr">CornerRadius=<span class="hljs-string">"100"
<span class="hljs-attr">Text=<span class="hljs-string">""
<span class="hljs-attr">HeightRequest=<span class="hljs-string">"44"
<span class="hljs-attr">WidthRequest=<span class="hljs-string">"200"
<span class="hljs-attr">FontFamily=<span class="hljs-string">"FontAwesome"
><span class="hljs-tag"></<span class="hljs-name">Button>
<span class="hljs-tag"><<span class="hljs-name">StackLayout <span class="hljs-attr">VerticalOptions=<span class="hljs-string">"End"
<span class="hljs-attr">Margin=<span class="hljs-string">"0,0,0,8"
<span class="hljs-attr">Grid.Row=<span class="hljs-string">"1"
<span class="hljs-attr">HorizontalOptions=<span class="hljs-string">"Center"
<span class="hljs-attr">Orientation=<span class="hljs-string">"Horizontal">
<span class="hljs-tag"><<span class="hljs-name">Label <span class="hljs-attr">HorizontalTextAlignment=<span class="hljs-string">"Center"
<span class="hljs-attr">FontSize=<span class="hljs-string">"Small"
<span class="hljs-attr">Text=<span class="hljs-string">"{Binding Songs.Count}"><span class="hljs-tag"></<span class="hljs-name">Label>
<span class="hljs-tag"><<span class="hljs-name">Label <span class="hljs-attr">HorizontalTextAlignment=<span class="hljs-string">"Center"
<span class="hljs-attr">FontSize=<span class="hljs-string">"Small"
<span class="hljs-attr">Text=<span class="hljs-string">"首歌"><span class="hljs-tag"></<span class="hljs-name">Label>
<span class="hljs-tag"></<span class="hljs-name">StackLayout>
<span class="hljs-tag"></<span class="hljs-name">Grid>
<span class="hljs-tag"></<span class="hljs-name">ListView.Header>
<span class="hljs-tag"><<span class="hljs-name">ListView.ItemTemplate>
<span class="hljs-tag"><<span class="hljs-name">DataTemplate>
<span class="hljs-tag"><<span class="hljs-name">ViewCell>
<span class="hljs-tag"><<span class="hljs-name">Grid <span class="hljs-attr">x:Name=<span class="hljs-string">"ModeControlLayout"
<span class="hljs-attr">VerticalOptions=<span class="hljs-string">"CenterAndExpand">
<span class="hljs-tag"><<span class="hljs-name">Grid.ColumnDefinitions>
<span class="hljs-tag"><<span class="hljs-name">ColumnDefinition <span class="hljs-attr">Width=<span class="hljs-string">"*" />
<span class="hljs-tag"><<span class="hljs-name">ColumnDefinition <span class="hljs-attr">Width=<span class="hljs-string">"Auto" />
<span class="hljs-tag"></<span class="hljs-name">Grid.ColumnDefinitions>
<span class="hljs-tag"><<span class="hljs-name">StackLayout <span class="hljs-attr">Grid.Column=<span class="hljs-string">"0"
<span class="hljs-attr">HorizontalOptions=<span class="hljs-string">"Center"
<span class="hljs-attr">VerticalOptions=<span class="hljs-string">"CenterAndExpand">
<span class="hljs-tag"><<span class="hljs-name">Label
<span class="hljs-attr">Text=<span class="hljs-string">"{Binding MusicTitle}"
<span class="hljs-attr">HorizontalOptions=<span class="hljs-string">"FillAndExpand"
<span class="hljs-attr">HorizontalTextAlignment=<span class="hljs-string">"Center"
<span class="hljs-attr">FontSize=<span class="hljs-string">"Body"
/>
<span class="hljs-tag"><<span class="hljs-name">Label
<span class="hljs-attr">Text=<span class="hljs-string">"{Binding Artist}"
<span class="hljs-attr">HorizontalOptions=<span class="hljs-string">"FillAndExpand"
<span class="hljs-attr">HorizontalTextAlignment=<span class="hljs-string">"Center"
<span class="hljs-attr">FontSize=<span class="hljs-string">"Body"
/>
<span class="hljs-tag"></<span class="hljs-name">StackLayout>
<span class="hljs-tag"><<span class="hljs-name">Button
<span class="hljs-attr">x:Name=<span class="hljs-string">"MoreButton"
<span class="hljs-attr">HeightRequest=<span class="hljs-string">"44"
<span class="hljs-attr">WidthRequest=<span class="hljs-string">"44"
<span class="hljs-attr">Margin=<span class="hljs-string">"10"
<span class="hljs-attr">Text=<span class="hljs-string">""
<span class="hljs-attr">Clicked=<span class="hljs-string">"SongMoreButton_OnClicked"
<span class="hljs-attr">FontFamily=<span class="hljs-string">"FontAwesome"
<span class="hljs-attr">Grid.Column=<span class="hljs-string">"1"
<span class="hljs-attr">CornerRadius=<span class="hljs-string">"100"
<span class="hljs-attr">HorizontalOptions=<span class="hljs-string">"Center" />
<span class="hljs-tag"></<span class="hljs-name">Grid>
<span class="hljs-tag"></<span class="hljs-name">ViewCell>
<span class="hljs-tag"></<span class="hljs-name">DataTemplate>
<span class="hljs-tag"></<span class="hljs-name">ListView.ItemTemplate>
<span class="hljs-tag"></<span class="hljs-name">ListView>
<span class="hljs-tag"></<span class="hljs-name">Grid>
</mato:ContentPageBase>
编写CodeBehind为:
注意将它继承ITransientDependency接口
这个页面之前提到过,已经通过IocManager.Resolve(typeof(MainPage))解析出实例并赋值给App.MainPage了。
public partial class MainPage : ContentPageBase, ITransientDependency
{
private readonly MainPageViewModel mainPageViewModel;
private readonly MusicItemPageViewModel musicItemPageViewModel;
private readonly MusicItemPage musicItemPage;
<span class="hljs-function"><span class="hljs-keyword">public <span class="hljs-title">MainPage(<span class="hljs-params">MainPageViewModel mainPageViewModel, MusicItemPageViewModel musicItemPageViewModel, MusicItemPage musicItemPage)
{
InitializeComponent();
<span class="hljs-keyword">this.mainPageViewModel=mainPageViewModel;
<span class="hljs-keyword">this.musicItemPageViewModel=musicItemPageViewModel;
<span class="hljs-keyword">this.musicItemPage=musicItemPage;
BindingContext=<span class="hljs-keyword">this.mainPageViewModel;
}
<span class="hljs-function"><span class="hljs-keyword">protected <span class="hljs-keyword">override <span class="hljs-keyword">void <span class="hljs-title">OnAppearing()
{
<span class="hljs-keyword">base.OnAppearing();
mainPageViewModel.RefreshCommand.Execute(<span class="hljs-literal">null);
}
<span class="hljs-function"><span class="hljs-keyword">private <span class="hljs-keyword">async <span class="hljs-keyword">void <span class="hljs-title">SongMoreButton_OnClicked(<span class="hljs-params"><span class="hljs-built_in">object sender, EventArgs e)
{
<span class="hljs-keyword">var currentsong = (sender <span class="hljs-keyword">as BindableObject).BindingContext <span class="hljs-keyword">as Song;
<span class="hljs-built_in">string action = <span class="hljs-keyword">await DisplayActionSheet(currentsong.MusicTitle, <span class="hljs-string">"取消", <span class="hljs-literal">null, <span class="hljs-string">"修改", <span class="hljs-string">"删除");
<span class="hljs-keyword">if (action==<span class="hljs-string">"修改")
{
musicItemPageViewModel.CurrentSong = currentsong;
<span class="hljs-keyword">await Navigation.PushModalAsync(musicItemPage);
}
<span class="hljs-keyword">else <span class="hljs-keyword">if (action==<span class="hljs-string">"删除")
{
mainPageViewModel.DeleteCommand.Execute(currentsong);
mainPageViewModel.RefreshCommand.Execute(<span class="hljs-literal">null);
}
}
<span class="hljs-function"><span class="hljs-keyword">private <span class="hljs-keyword">async <span class="hljs-keyword">void <span class="hljs-title">AddButton_Clicked(<span class="hljs-params"><span class="hljs-built_in">object sender, EventArgs e)
{
musicItemPageViewModel.CurrentSong = <span class="hljs-keyword">new Song();
<span class="hljs-keyword">await Navigation.PushModalAsync(musicItemPage);
}
}
此页面将显示一个列表,并在列表条目下可以弹出一个菜单
编写条目编辑页面
新建一个MusicItemPageViewModel.cs,作为MusicItemPage的ViewModel层
public class MusicItemPageViewModel : ViewModelBase
{
private readonly IIocResolver iocResolver;
private readonly IRepository<Song, long> songRepository;
<span class="hljs-keyword">public <span class="hljs-keyword">event EventHandler OnFinished;
<span class="hljs-function"><span class="hljs-keyword">public <span class="hljs-title">MusicItemPageViewModel(<span class="hljs-params">
IIocResolver iocResolver,
IRepository<Song, <span class="hljs-built_in">long> songRepository)
{
<span class="hljs-keyword">this.CommitCommand=<span class="hljs-keyword">new Command(Commit, (o) => CurrentSong!=<span class="hljs-literal">null);
<span class="hljs-keyword">this.iocResolver=iocResolver;
<span class="hljs-keyword">this.songRepository=songRepository;
<span class="hljs-keyword">this.PropertyChanged+=MusicItemPageViewModel_PropertyChanged;
}
<span class="hljs-function"><span class="hljs-keyword">private <span class="hljs-keyword">void <span class="hljs-title">MusicItemPageViewModel_PropertyChanged(<span class="hljs-params"><span class="hljs-built_in">object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
<span class="hljs-keyword">if (e.PropertyName==<span class="hljs-keyword">nameof(CurrentSong))
{
CommitCommand.ChangeCanExecute();
}
}
<span class="hljs-function"><span class="hljs-keyword">private <span class="hljs-keyword">void <span class="hljs-title">Commit(<span class="hljs-params"><span class="hljs-built_in">object obj)
{
songRepository.InsertOrUpdate(currentSong);
}
<span class="hljs-keyword">private Song currentSong;
<span class="hljs-keyword">public Song CurrentSong
{
<span class="hljs-keyword">get { <span class="hljs-keyword">return currentSong; }
<span class="hljs-keyword">set
{
currentSong = <span class="hljs-keyword">value;
RaisePropertyChanged();
}
}
}
新建一个MusicItemPage 页面
编写Xaml为:
注意这个页面将继承MauiBoilerplate.ContentPageBase
<?xml version="1.0" encoding="utf-8" ?>
<mato:ContentPageBase xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:mato="clr-namespace:MauiBoilerplate;assembly=MauiBoilerplate.Core"
x:Class="MauiBoilerplate.MusicItemPage">
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition Height="155"></RowDefinition>
</Grid.RowDefinitions>
<TableView Intent="Form">
<TableRoot>
<TableSection Title="基础">
<EntryCell Label="标题" Text="{Binding CurrentSong.MusicTitle, Mode=TwoWay}"/>
<EntryCell Label="艺术家" Text="{Binding CurrentSong.Artist, Mode=TwoWay}"/>
<EntryCell Label="专辑" Text="{Binding CurrentSong.Album, Mode=TwoWay}"/>
<span class="hljs-tag"></<span class="hljs-name">TableSection>
<span class="hljs-tag"><<span class="hljs-name">TableSection <span class="hljs-attr">Title=<span class="hljs-string">"其他">
<span class="hljs-tag"><<span class="hljs-name">EntryCell <span class="hljs-attr">Label=<span class="hljs-string">"时长" <span class="hljs-attr">Text=<span class="hljs-string">"{Binding CurrentSong.Duration}"/>
<span class="hljs-tag"><<span class="hljs-name">EntryCell <span class="hljs-attr">Label=<span class="hljs-string">"发布日期" <span class="hljs-attr">Text=<span class="hljs-string">"{Binding CurrentSong.ReleaseDate}"/>
<span class="hljs-tag"></<span class="hljs-name">TableSection>
<span class="hljs-tag"></<span class="hljs-name">TableRoot>
<span class="hljs-tag"></<span class="hljs-name">TableView>
<span class="hljs-tag"><<span class="hljs-name">Button <span class="hljs-attr">x:Name=<span class="hljs-string">"CommitButton"
<span class="hljs-attr">Grid.Row=<span class="hljs-string">"1"
<span class="hljs-attr">CornerRadius=<span class="hljs-string">"100"
<span class="hljs-attr">HeightRequest=<span class="hljs-string">"44"
<span class="hljs-attr">WidthRequest=<span class="hljs-string">"200"
<span class="hljs-attr">Text=<span class="hljs-string">""
<span class="hljs-attr">Command=<span class="hljs-string">"{Binding CommitCommand}"
<span class="hljs-attr">FontFamily=<span class="hljs-string">"FontAwesome"
<span class="hljs-attr">HorizontalOptions=<span class="hljs-string">"Center" />
<span class="hljs-tag"></<span class="hljs-name">Grid>
</mato:ContentPageBase>
编写CodeBehind为:
注意将它继承ITransientDependency接口
public partial class MusicItemPage : ContentPageBase, ITransientDependency
{
private readonly MusicItemPageViewModel musicItemPageViewModel;
<span class="hljs-function"><span class="hljs-keyword">public <span class="hljs-title">MusicItemPage(<span class="hljs-params">MusicItemPageViewModel musicItemPageViewModel)
{
InitializeComponent();
<span class="hljs-keyword">this.musicItemPageViewModel=musicItemPageViewModel;
<span class="hljs-keyword">this.musicItemPageViewModel.OnValidateErrors+=MusicItemPageViewModel_OnValidateErrors;
<span class="hljs-keyword">this.musicItemPageViewModel.OnFinished+=MusicItemPageViewModel_OnFinished;
BindingContext=<span class="hljs-keyword">this.musicItemPageViewModel;
Unloaded+=MusicItemPage_Unloaded;
}
<span class="hljs-function"><span class="hljs-keyword">private <span class="hljs-keyword">async <span class="hljs-keyword">void <span class="hljs-title">MusicItemPageViewModel_OnFinished(<span class="hljs-params"><span class="hljs-built_in">object sender, EventArgs e)
{
<span class="hljs-keyword">await <span class="hljs-keyword">this.Navigation.PopModalAsync();
}
<span class="hljs-function"><span class="hljs-keyword">private <span class="hljs-keyword">void <span class="hljs-title">MusicItemPage_Unloaded(<span class="hljs-params"><span class="hljs-built_in">object sender, EventArgs e)
{
musicItemPageViewModel.CurrentSong = <span class="hljs-literal">null;
}
<span class="hljs-function"><span class="hljs-keyword">private <span class="hljs-keyword">async <span class="hljs-keyword">void <span class="hljs-title">MusicItemPageViewModel_OnValidateErrors(<span class="hljs-params"><span class="hljs-built_in">object sender, List<System.ComponentModel.DataAnnotations.ValidationResult> e)
{
<span class="hljs-keyword">var content = <span class="hljs-built_in">string.Join(<span class="hljs-string">',', e);
<span class="hljs-keyword">await DisplayAlert(<span class="hljs-string">"请注意", content, <span class="hljs-string">"好的");
}
}
这个页面提供歌曲条目新增和编辑的交互功能
[可选]使用Abp校验数据功能
这个部分使用Abp的ValidationConfiguration功能校验表单数据,以展示Abp功能的使用
首先在MusicItemPageViewModel 构造函数中添加对IValidationConfiguration对象的注入
添加OnValidateErrors事件,并且在Page中订阅这个事件。此事件将在校验未通过时触发
MusicItemPageViewModel.cs中:
public event EventHandler<List<ValidationResult>> OnValidateErrors;
MusicItemPage.xaml.cs中:
this.musicItemPageViewModel.OnValidateErrors+=MusicItemPageViewModel_OnValidateErrors;
private async void MusicItemPageViewModel_OnValidateErrors(object sender, List<System.ComponentModel.DataAnnotations.ValidationResult> e)
{
var content = string.Join(',', e);
await DisplayAlert("请注意", content, "好的");
}
编写校验逻辑代码
MusicItemPageViewModel.cs中:
protected List<ValidationResult> GetValidationErrors(Song validatingObject)
{
List<ValidationResult> validationErrors = new List<ValidationResult>();
<span class="hljs-keyword">foreach (<span class="hljs-keyword">var validatorType <span class="hljs-keyword">in _configuration.Validators)
{
<span class="hljs-keyword">using (<span class="hljs-keyword">var validator = iocResolver.ResolveAsDisposable<IMethodParameterValidator>(validatorType))
{
<span class="hljs-keyword">var validationResults = validator.Object.Validate(validatingObject);
validationErrors.AddRange(validationResults);
}
}
<span class="hljs-keyword">return validationErrors;
}
Commit提交方法,改造如下:
当GetValidationErrors返回的校验错误列表中有内容时,将OnValidateErrors事件Invoke
private void Commit(object obj)
{
var validateErrors = GetValidationErrors(this.CurrentSong);
if (validateErrors.Count==0)
{
songRepository.InsertOrUpdate(currentSong);
this.OnFinished?.Invoke(this, EventArgs.Empty);
}
<span class="hljs-keyword">else
{
OnValidateErrors?.Invoke(<span class="hljs-keyword">this, validateErrors);
}
}</span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre>
接下来在实体中定义校验规则,校验器将按照这些规则返回校验结果
public class Song : FullAuditedEntity<long>, IValidatableObject
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public override long Id { get; set; }
[<span class="hljs-meta">Required]
[<span class="hljs-meta">StringLength(6, ErrorMessage = <span class="hljs-string">"歌曲名称要在6个字以内")]
<span class="hljs-keyword">public <span class="hljs-built_in">string MusicTitle { <span class="hljs-keyword">get; <span class="hljs-keyword">set; }
[<span class="hljs-meta">Required]
[<span class="hljs-meta">StringLength(10, ErrorMessage = <span class="hljs-string">"歌曲名称要在10个字以内")]
<span class="hljs-keyword">public <span class="hljs-built_in">string Artist { <span class="hljs-keyword">get; <span class="hljs-keyword">set; }
[<span class="hljs-meta">Required]
[<span class="hljs-meta">StringLength(10, ErrorMessage = <span class="hljs-string">"歌曲名称要在10个字以内")]
<span class="hljs-keyword">public <span class="hljs-built_in">string Album { <span class="hljs-keyword">get; <span class="hljs-keyword">set; }
<span class="hljs-keyword">public TimeSpan Duration { <span class="hljs-keyword">get; <span class="hljs-keyword">set; }
<span class="hljs-keyword">public DateTime ReleaseDate { <span class="hljs-keyword">get; <span class="hljs-keyword">set; }
<span class="hljs-function"><span class="hljs-keyword">public IEnumerable<ValidationResult> <span class="hljs-title">Validate(<span class="hljs-params">ValidationContext validationContext)
{
<span class="hljs-keyword">if (ReleaseDate != <span class="hljs-literal">default && ReleaseDate>DateTime.Now)
{
<span class="hljs-function"><span class="hljs-keyword">yield <span class="hljs-keyword">return <span class="hljs-keyword">new <span class="hljs-title">ValidationResult(<span class="hljs-params"><span class="hljs-string">"ReleaseDate不能大于当天",
<span class="hljs-keyword">new[] { <span class="hljs-keyword">nameof(ReleaseDate) });
}
}
}
运行,新建条目。当我们如下填写的时候,将会弹出提示框
iOS平台也测试通过
至此我们完成了所有的工作。
结束语
Abp是一个很好用的.Net开发框架,Abp库帮助我们抽象了整个项目以及更多的设计模式应用,其名称Asp Boilerplate,虽然有一个Asp在其中,但其功能不仅仅可以构建AspNet Core应用,
经过我们的探索用Abp构建了跨平台应用,同样它还可以用于Xamarin,Wpf甚至是WinForms这些基于桌面的应用。
欢迎参与讨论和转发。
项目地址
jevonsflash/maui-abp-sample (github.com)
将Abp移植进.NET MAUI项目(三):构建UI层