将Abp移植进.NET MAUI项目(三):构建UI层

很开心,终于到了创建页面的时候了!

我们需要两个页面

  • MainPage 主页面
  • MusicItemPage 条目编辑页面

编写主页面

 新建一个MainPageViewModel.cs,作为MainPage的ViewModel层

    public class MainPageViewModel : ViewModelBase
    {
        private readonly IRepository songRepository;

        public MainPageViewModel(IRepository songRepository)
        {
            this.RefreshCommand=new Command(Refresh, (o) => true);
            this.DeleteCommand=new Command(Delete, (o) => true);
            this.songRepository=songRepository;

        }
        private void Delete(object obj)
        {
            songRepository.Delete(obj as Song);
        }
        private async void Refresh(object obj)
        {
            this.IsRefreshing=true;
            var getSongs = this.songRepository.GetAllListAsync();
            await getSongs.ContinueWith(r => IsRefreshing=false);
            var songs = await getSongs;
            this.Songs=new ObservableCollection(songs);
        }

        private ObservableCollection songs;

        public ObservableCollection Songs
        {
            get { return songs; }
            set
            {
                songs = value;
                RaisePropertyChanged();
            }
        }

        private Song currentSong;

        public Song CurrentSong
        {
            get { return currentSong; }
            set
            {
                currentSong = value;
                RaisePropertyChanged();
            }
        }

        private bool _isRefreshing;

        public bool IsRefreshing
        {
            get { return _isRefreshing; }
            set
            {
                _isRefreshing = value;
                RaisePropertyChanged();

            }
        }
        public Command RefreshCommand { get; set; }
        public Command DeleteCommand { get; private set; }
    }

新建一个MainPage页面

将Abp移植进.NET MAUI项目(三):构建UI层_第1张图片

编写Xaml为:

注意这个页面将继承MauiBoilerplate.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;

    public MainPage(MainPageViewModel mainPageViewModel, MusicItemPageViewModel musicItemPageViewModel, MusicItemPage musicItemPage)
    {
        InitializeComponent();
        this.mainPageViewModel=mainPageViewModel;
        this.musicItemPageViewModel=musicItemPageViewModel;
        this.musicItemPage=musicItemPage;
        BindingContext=this.mainPageViewModel;
       
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();
        mainPageViewModel.RefreshCommand.Execute(null);

    }

    private async void SongMoreButton_OnClicked(object sender, EventArgs e)
    {
        var currentsong = (sender as BindableObject).BindingContext as Song;
        string action = await DisplayActionSheet(currentsong.MusicTitle, "取消", null, "修改", "删除");
        if (action=="修改")
        {
            musicItemPageViewModel.CurrentSong  = currentsong;
            await Navigation.PushModalAsync(musicItemPage);
        }
        else if (action=="删除")
        {
            mainPageViewModel.DeleteCommand.Execute(currentsong);
            mainPageViewModel.RefreshCommand.Execute(null);
        }
    }

    private async void AddButton_Clicked(object sender, EventArgs e)
    {
        musicItemPageViewModel.CurrentSong  = new Song();
        await Navigation.PushModalAsync(musicItemPage);
    }
}

此页面将显示一个列表,并在列表条目下可以弹出一个菜单

将Abp移植进.NET MAUI项目(三):构建UI层_第2张图片

 编写条目编辑页面

 新建一个MusicItemPageViewModel.cs,作为MusicItemPage的ViewModel层

 public class MusicItemPageViewModel : ViewModelBase
 {
        private readonly IIocResolver iocResolver;
        private readonly IRepository songRepository;

        public event EventHandler OnFinished;

        public MusicItemPageViewModel(
            IIocResolver iocResolver,
            IRepository songRepository)
        {
            this.CommitCommand=new Command(Commit, (o) => CurrentSong!=null);
            this.iocResolver=iocResolver;
            this.songRepository=songRepository;
            this.PropertyChanged+=MusicItemPageViewModel_PropertyChanged;
        }

        private void MusicItemPageViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName==nameof(CurrentSong))
            {
                CommitCommand.ChangeCanExecute();
            }
        }

        private void Commit(object obj)
        {
            songRepository.InsertOrUpdate(currentSong);       
        }

        private Song currentSong;

        public Song CurrentSong
        {
            get { return currentSong; }
            set
            {
                currentSong = value;
                RaisePropertyChanged();
            }
        }
  }

新建一个MusicItemPage 页面

编写Xaml为:

注意这个页面将继承MauiBoilerplate.ContentPageBase



    
        
            
            
        
        
            
                
                    
                    
                    

                
                
                    
                    
                

            
        
        

 编写CodeBehind为:

注意将它继承ITransientDependency接口

public partial class MusicItemPage : ContentPageBase, ITransientDependency
{
    private readonly MusicItemPageViewModel musicItemPageViewModel;

    public MusicItemPage(MusicItemPageViewModel musicItemPageViewModel)
    {
        InitializeComponent();
        this.musicItemPageViewModel=musicItemPageViewModel;
        this.musicItemPageViewModel.OnValidateErrors+=MusicItemPageViewModel_OnValidateErrors;
        this.musicItemPageViewModel.OnFinished+=MusicItemPageViewModel_OnFinished;
        BindingContext=this.musicItemPageViewModel;
        Unloaded+=MusicItemPage_Unloaded;
    }

    private async void MusicItemPageViewModel_OnFinished(object sender, EventArgs e)
    {
       await this.Navigation.PopModalAsync();
    }

    private void MusicItemPage_Unloaded(object sender, EventArgs e)
    {
        musicItemPageViewModel.CurrentSong = null;
    }

    private async void MusicItemPageViewModel_OnValidateErrors(object sender, List e)
    {
        var content = string.Join(',', e);
        await DisplayAlert("请注意", content, "好的");
    }
}

这个页面提供歌曲条目新增和编辑的交互功能

将Abp移植进.NET MAUI项目(三):构建UI层_第3张图片

[可选]使用Abp校验数据功能

这个部分使用Abp的ValidationConfiguration功能校验表单数据,以展示Abp功能的使用

首先在MusicItemPageViewModel 构造函数中添加对IValidationConfiguration对象的注入

将Abp移植进.NET MAUI项目(三):构建UI层_第4张图片

 添加OnValidateErrors事件,并且在Page中订阅这个事件。此事件将在校验未通过时触发

MusicItemPageViewModel.cs中:

public event EventHandler> OnValidateErrors;

 MusicItemPage.xaml.cs中:

        this.musicItemPageViewModel.OnValidateErrors+=MusicItemPageViewModel_OnValidateErrors;
    private async void MusicItemPageViewModel_OnValidateErrors(object sender, List e)
    {
        var content = string.Join(',', e);
        await DisplayAlert("请注意", content, "好的");
    }

编写校验逻辑代码

MusicItemPageViewModel.cs中:

        protected List GetValidationErrors(Song validatingObject)
        {
            List validationErrors = new List();

            foreach (var validatorType in _configuration.Validators)
            {
                using (var validator = iocResolver.ResolveAsDisposable(validatorType))
                {
                    var validationResults = validator.Object.Validate(validatingObject);
                    validationErrors.AddRange(validationResults);
                }

            }
            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);

            }
            else
            {
                OnValidateErrors?.Invoke(this, validateErrors);
            }
        }

接下来在实体中定义校验规则,校验器将按照这些规则返回校验结果

    public class Song : FullAuditedEntity, IValidatableObject
    {
        [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public override long Id { get; set; }

        [Required]
        [StringLength(6, ErrorMessage = "歌曲名称要在6个字以内")]
        public string MusicTitle { get; set; }

        [Required]
        [StringLength(10, ErrorMessage = "歌曲名称要在10个字以内")]
        public string Artist { get; set; }

        [Required]
        [StringLength(10, ErrorMessage = "歌曲名称要在10个字以内")]
        public string Album { get; set; }

        public TimeSpan Duration { get; set; }
        public DateTime ReleaseDate { get; set; }

        public IEnumerable Validate(ValidationContext validationContext)
        {
            if (ReleaseDate != default && ReleaseDate>DateTime.Now)
            {
                yield return new ValidationResult("ReleaseDate不能大于当天",
                                  new[] { nameof(ReleaseDate) });
            }

        }
    }

运行,新建条目。当我们如下填写的时候,将会弹出提示框

将Abp移植进.NET MAUI项目(三):构建UI层_第5张图片

iOS平台也测试通过 

 

 

 至此我们完成了所有的工作。

结束语

Abp是一个很好用的.Net开发框架,Abp库帮助我们抽象了整个项目以及更多的设计模式应用,其名称Asp Boilerplate,虽然有一个Asp在其中,但其功能不仅仅可以构建AspNet Core应用,

经过我们的探索用Abp构建了跨平台应用,同样它还可以用于Xamarin,Wpf甚至是WinForms这些基于桌面的应用。

欢迎参与讨论和转发。

项目地址

jevonsflash/maui-abp-sample (github.com)

你可能感兴趣的:(.NetCore,.net,c#,xamarin)