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

C#开源生态全景:工具、框架与最佳实践 C#作为.NET生态的核心语言,其开源生态已覆盖从基础工具到企业级框架的全场景。开源项目通过模块化设计、跨平台支持等特性,显著提升开发效率。在云原生与微服务领域,Dapr等框架提供分布式运行时支持;ML.NET等库则降低机器学习门槛。开发者可基于NuGet生态快速集成Masuit.Tools等实用组件,或采用ABP Framework构建现代化应用架构。本文系统梳理C#开源技术栈,涵盖工业自动化、金融科技等垂直领域解决方案,为技术选型提供实践参考。 阅读详情

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

我们需要两个页面

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

编写主页面

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

    public class MainPageViewModel : ViewModelBase
    {
        private readonly IRepository<Song, long> songRepository;

        public MainPageViewModel(IRepository<Song, long> 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<Song>(songs);
        }

        private ObservableCollection<Song> songs;

        public ObservableCollection<Song> 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页面

编写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>

        <Label Text="My Music" FontSize="65"></Label>
        <ListView 
                Grid.Row="1"
                ItemsSource="{Binding Songs,Mode=TwoWay}"
                x:Name="MainListView"
                RowHeight="74" 
                IsPullToRefreshEnabled="True"
                IsRefreshing="{Binding IsRefreshing}"
                RefreshCommand="{Binding RefreshCommand}"
                SelectedItem="{Binding CurrentSong,Mode=TwoWay}">
            <ListView.Header>
                <Grid HeightRequest="96">
                    <Grid.RowDefinitions>
                        <RowDefinition></RowDefinition>
                        <RowDefinition></RowDefinition>
                    </Grid.RowDefinitions>


                    <Button Clicked="AddButton_Clicked"
                            CornerRadius="100"
                            Text=""
                            HeightRequest="44"
                            WidthRequest="200"
                            FontFamily="FontAwesome"
                                ></Button>


                    <StackLayout VerticalOptions="End"
                                 Margin="0,0,0,8"
                                 Grid.Row="1"
                                 HorizontalOptions="Center"
                                 Orientation="Horizontal">
                        <Label HorizontalTextAlignment="Center"
                            FontSize="Small" 
                            Text="{Binding Songs.Count}"></Label>
                        <Label  HorizontalTextAlignment="Center"
                            FontSize="Small" 
                            Text="首歌"></Label>

                    </StackLayout>
                </Grid>
            </ListView.Header>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid x:Name="ModeControlLayout" 
                              VerticalOptions="CenterAndExpand">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition Width="Auto" />
                            </Grid.ColumnDefinitions>


                            <StackLayout Grid.Column="0" 
                                             HorizontalOptions="Center" 
                                             VerticalOptions="CenterAndExpand">
                                <Label 
                                    Text="{Binding MusicTitle}"                                    
                                    HorizontalOptions="FillAndExpand" 
                                    HorizontalTextAlignment="Center" 
                                    FontSize="Body" 
                                    />
                                <Label
                                    Text="{Binding Artist}" 
                                    HorizontalOptions="FillAndExpand" 
                                    HorizontalTextAlignment="Center" 
                                    FontSize="Body" 
                                    />
                            </StackLayout>
                            <Button 
                                x:Name="MoreButton"
                                HeightRequest="44" 
                                WidthRequest="44" 
                                Margin="10"
                                Text=""
                                Clicked="SongMoreButton_OnClicked"
                                FontFamily="FontAwesome"
                                Grid.Column="1" 
                                CornerRadius="100"
                                HorizontalOptions="Center" />

                        </Grid>

                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </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;

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

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

 编写条目编辑页面

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

 public class MusicItemPageViewModel : ViewModelBase
 {
        private readonly IIocResolver iocResolver;
        private readonly IRepository<Song, long> songRepository;

        public event EventHandler OnFinished;

        public MusicItemPageViewModel(
            IIocResolver iocResolver,
            IRepository<Song, long> 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

<?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}"/>

                </TableSection>
                <TableSection Title="其他">
                    <EntryCell  Label="时长"  Text="{Binding CurrentSong.Duration}"/>
                    <EntryCell  Label="发布日期"  Text="{Binding CurrentSong.ReleaseDate}"/>
                </TableSection>

            </TableRoot>
        </TableView>
        <Button x:Name="CommitButton"
                Grid.Row="1"
                CornerRadius="100"
                HeightRequest="44"
                WidthRequest="200"
                Text=""
                Command="{Binding CommitCommand}"
                FontFamily="FontAwesome"             
                HorizontalOptions="Center" />
    </Grid>
</mato: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<System.ComponentModel.DataAnnotations.ValidationResult> e)
    {
        var content = string.Join(',', e);
        await DisplayAlert("请注意", content, "好的");
    }
}

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

[可选]使用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>();

            foreach (var validatorType in _configuration.Validators)
            {
                using (var validator = iocResolver.ResolveAsDisposable<IMethodParameterValidator>(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<long>, 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<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (ReleaseDate != default && ReleaseDate>DateTime.Now)
            {
                yield return new ValidationResult("ReleaseDate不能大于当天",
                                  new[] { nameof(ReleaseDate) });
            }

        }
    }

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

iOS平台也测试通过 

 

 

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

结束语

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

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

欢迎参与讨论和转发。

项目地址

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

B-Tree数据存储 SQLITE数据存储1. B-Tree的优势  在SQLite中数据库、表、索引都是通过B-Tree和B+Tree的形式进行存储的。如果采用传统的二叉树查找树、红黑树的查找深度一般为log2(N) \log{_2}(N)(其中N表示的是整个树的关键字的数目),在数据库中如果存储的资源过多,就会导致查找一个数据过程中出现较多的磁盘I/O操作,而过多的磁盘操作就会导致整个查找的效率较低,而基于二叉树的一 阅读详情

相关推荐

智能座舱架构与芯片- (9) 音频篇 上

从A2B收发器衍生出来的简化产品具备各种级别的功能,例如端点从节点(不支持TDM)、简化型主节点(支持较短的电缆和更少的从节点数量),以及简化型端点从节点(支持较短电缆和更少的PDM输入)。例如,AVB中的talker和listener是不同的设备,它们的参考时钟源可能并不相同。传统的车载收音机通过天线接收无线电信号,然后由调谐模块(Tuner)进行信号调谐,信道过滤,信道均衡,多路改善,信号解调等,转为数字信号后再交给DSP进行立体声解码,噪声抑制,弱信号处理,最后从车载音响系统进行播放。

joanna_xiao的博客 4907

将Abp移植进.NET MAUI项目(一):搭建项目

去年12月份做了MAUI混合开发框架的调研,想起来文章里给自己挖了个坑,要教大家如何把Abp移植进Maui项目,今天来填坑。 熟悉Abp的同学都知道,Abp 是一套强大的应用程序设计时框架(俗称脚手架),新版本的Abp vNext为微服务和网络优化的更多,然而本地开发经典Abp已经够用,而且官方没有停止维护,因此使用这个框架 MAUI则是跨平台的应用程序抽象层,强大的运行时框架 + 强大的设计时框架 , 我说这是宇宙最强大跨平台开发框架,不为过吧?😁 搭建MAUI项目 请注意:本文发布时,MAUI处

jevonsflash的专栏 2111

UE5.5使用ControlRig实现MetaHumanNPC看向玩家

本文介绍了在虚幻引擎中实现NPC自然看向玩家的技术方案。通过MetaHuman的ControlRig系统,采用面部动画曲线+全身动画Montage的表演方式,结合ControlRig驱动CTRL_lookat控制器实现视线追踪。

平常心 1302

MAUI 通用权限框架(ABP)

简介众所周知, MAUI目前发布正式版本了, 那么对应, MAUI对应的ABP框架也应该马上出现, 这点也恰巧在我的预料之中, 所以在去年年底就开始着手Xamarin.Forms的ABP框架迭代。到目前为止,针对Xamarin.Forms 以及 WPF版本的 ABP框架已经在之前的文章当中给大家介绍过。那么本次主要来介绍MAUI框架中的ABP实现。参考以往的文章:Xam...

dotNET跨平台 3484

SAP 物料的分割评估

SAP 物料的分割评估 前言 本文主要讲解SAP中物料的分割评估,通过分割评估来区分出同一物料不同来源下的核算方式。例如:同一物料分为自产或者采购,或者同一物料分为进口或者国内采购等。 一、概述 分割评估一般用于以下场景: 1、物料分为内部采购和外部采购; 2、物料分属于进口或者国内采购; 3、物料分属于不同的批次; 4、物料分为自制或者采购。 由于物料的来源不同可能导致物料的价格或者性质不同,需要用不同价格来区分出 二、配置步骤 1.激活分割评估 ...

五谷散熊 6792

Cartographer全局重定位优化:无初始位姿约束的2万平工厂秒级定位实践

本文深入解析了Cartographer在2万平工业场景中的全局重定位优化实践,通过分支定界优化、子图动态加载和多传感器融合等关键技术,实现了无初始位姿约束下的秒级重定位。特别针对大场景下的快速重定位需求,优化后的系统在RK3588平台上表现出色,定位耗时从47秒降至1.8秒,成功率提升至91%,为工业自动化提供了高效解决方案。

rose2的博客 969

采用abp框架进行maui开发,启动页面时如何新增后台服务

采用ABP框架进行.NET MAUI开发,利用ABP框架强大功能,如IoC容器、配置管理、工作单元特性、模块化特性等,来构建您的跨平台应用程序。新增后台服务有二个方式,一种是新增一个类工作,在这类里可建设多个线程,不间断的运行,或是设置定时运行。另一种方式是建一个后台服务工作者,可对这个服务提供接口服务,提供HTTP接口给别人访问

zzlyx99的专栏 1082

告别手动复制粘贴:3种高效合并Excel表格的方法对比(含代码)

本文对比了VBA、Power Query和Python三种高效合并Excel表格的方法,并提供了可直接运行的代码。针对不同数据量、更新频率和技术背景,详细分析了各方案的优缺点与适用场景,帮助读者告别低效的手动操作,实现自动化数据整合。

weixin_29057237的博客 441

.NET MAUI实战 Navigation

1.概要用过WPF的小伙伴一般都用过Prism,Prism里面的导航概念在MAUI中也有类似的概念,在MAUI中是直接集成在框架中我们不需要安装任何其他的nuget包。直接使用Navigation对象即可,通常在移动平台中使用的更多,桌面程序中。我们先来看看微软官方是如何定义的,如下面代码所示。public interface INavigation { IReadOnly...

dotNET跨平台 797

K8s(二十一):在 Kubernetes 集群中部署 MySQL8.0 高可用集群(1主2从)

🔴 K8s(二十一):在 Kubernetes 集群中部署 MySQL8.0 高可用集群(1主2从)

✨ 欢迎来到【Seal ^_^ 的优快云博客】!✨ 3万+

数学建模之0—1规划(Python)

目录 1、概述 (1)知识框架 (2)线性整数规划模型 (3)分支定界法 2、案例 (1)案例1​ (2)案例2 3、遗传算法—sko-GA包实现 (1)代码 (2)结果 4、PuLp实现 (1)代码 (2)结果 5、致谢 1、概述 (1)知识框架 (2)线性整数规划模型 (3)分支定界法 2、案例 (1)案例1 (2)案例2 3、遗传算法—sko-GA包...

weixin_46039719的博客 4112

探索高效开发新星:Maui-ABP,一个全面的.NET框架

探索高效开发新星:Maui-ABP,一个全面的.NET框架 项目简介 是一个基于 .NET Maui 和 ABP Framework 的开源项目,旨在为开发者提供一套完整的、跨平台的应用程序开发解决方案。它将微软的最新UI框架与强大的应用构建平台相结合,为移动、桌面和Web应用程序的开发提供了统一的平台。 技术分析 .NET Maui .NET Maui是微软推出的跨平台移动和桌面开发工具,支持创...

gitblog_00062的博客 712

购物车智能检测系统:YOLO26 + PyQt5 毕设实现

YOLO26 + PyQt5 完成购物车商品检测系统:标注数据集(OpenImages 筛选 + 自制 500 张),训练 100 epoch 得到 mAP50 约 0.89,集成商品定价后输出总价。建议先用 OpenImages 预训练权重在自制数据上调优(冻住 backbone 前 50 epoch),等 loss 稳定后再解冻全量训练。

m0_64661770的博客 56

WPF 通用权限开发框架 (ABP)

前言对于大部分.NET 开发者来说, 都比较熟悉目前流行的ABP框架, 基于开源的ABP框架, 可以自己进行二次开发, 无需重新开发一些基础功能,例如: 用户角色管理、权限、组织、多租户等等。但是对于ABP框架来说, 提供给.NET开发者的可选项非常少, 目前也仅仅是提供了基于Web的解决方案, 对于桌面端以及移动设备上的解决方案, 可以说是"敷衍了事"。哪怕是商业版的A...

dotNET跨平台 5951

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

.NET周刊【10月第3期 2024-10-20】

作者首先讨论了.NET线程池中cpuUtilization字段的获取过程,并详细阐述了.NET6以前和以后的线程池实现,包括win32threadpool.cpp和PortableThreadPool.cs。通过实战演示,文章展示了如何通过编程实现查询语句、修改操作和数据订阅,并指出了使用内存订阅的局限性,建议在生产环境中使用持久化方案,如Redis。支持Linux和Windows部署,提供详细的安装指引,包括下载源码、安装.NET SDK和Node.js、编译前后端,以及安装和启动Nginx等步骤。

weixin_55010563的博客 446

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Xamarin.Forms 5.0 项目实战发布!

活动介绍本次活动主要是 .NET Xamarin.Forms 移动端项目开发实战教程, 与以往相同, 本次的收入(其它部分会另行说明) 将用于社区公益活动, 不限于:公益性质的个人/组织机构捐赠开源社区个人/项目捐赠内部投票活动本次的活动费用为:399元, 相对于去年组织的WPF公益实战视频而言, 这次的内容除了是针对Xamarin.Forms以外, 整体的内容几乎是针对...

dotNET跨平台 601

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

将Abp移植进.NET MAUI项目

前言写在.NET MAUI官宣正式发布之际,热烈庆祝MAUI正式发布!去年12月份做了MAUI混合开发框架的调研,想起来文章里给自己挖了个坑,要教大家如何把Abp移植进Maui项目。熟悉Abp的同学都知道,Abp 是一套强大的应用程序设计时框架(俗称脚手架),新版本的Abp vNext为微服务和网络优化的更多,然而本地开发经典Abp已经够用,而且官方没有停止维护,因此使用...

dotNET跨平台 656

[MAUI 项目实战] 音乐播放器(一):概述与架构

为什么想起来这个项目了呢? 这是一个Windows Phone 8的老项目,2014年用作为兴趣写了个叫“番茄播放器”的App,顺便提高编程技能。 这个项目的架构历经多次迁移,从WP8到UWP再到Xamarin.Forms。去年底随着MAUI的正式发布,又尝试把它迁移到MAUI上来。

jevonsflash的专栏 5828

【.NET MAUI开发避坑指南】:导航栈内存泄漏的9大诱因与优化方案

解决.NET MAUI导航卡顿与内存泄漏难题,深入剖析导航栈管理的9大常见错误及优化策略。涵盖页面入栈出栈控制、事件解绑、生命周期协调等关键方法,提升应用性能与用户体验,值得收藏。

IterLoom的博客 1035

揭秘Grayskull的高效算法:嵌入式设备上的ORB特征提取与匹配

Grayskull是一款轻量级无依赖的计算机视觉库,专为嵌入式系统、无人机和机器人设计。其核心优势在于**ORB特征提取与匹配算法**的高效实现,让资源受限设备也能拥有强大的视觉处理能力。 ## 为什么ORB算法是嵌入式设备的理想选择? 传统视觉算法往往需要大量计算资源,而Grayskull的ORB实现通过三大优化实现了效率突破: - **FAST角点检测**:比SIFT快100倍的特征点提取

gitblog_01072的博客 494

abp viewmodel的写法

我的写法 public class QuotaCreateOrEditViewModel { public QuotaDto LoanQuota { get; set; } public bool IsEditMode => LoanQuota.Id.HasValue; } 老程序员的写法 [AutoMapFrom...

weixin_30371469的博客 165

MAUI 中使用 DI 及 MVVM

MAUI中MVVM原生实现和使用CommunityToolkit.Mvvm组件以及DI的使用。

视觉软件 1355

【MAUI】页面事件

在 .NET Multi-platform App UI (MAUI) 中,页面事件是用于处理页面生命周期和用户交互的重要机制。这些事件可以帮助你在页面的不同阶段执行特定的操作,例如加载数据、处理用户输入、保存状态等。

欢迎指错||纠正||建议||水评+点赞&&评论&&关注&&转发 1245

MAUI 框架入门学习05 MVVM数据模型理解

什么是MVVM模式? MVVM就是Model-View-ViewModel的缩写,它其实就是一种设计思想。

build2024 1907

[MAUI 项目实战] 音乐播放器(三):界面交互

UI设计的本质是对于产品的理解在界面中多种形式的映射,当需求和定位不同时,对相同的功能表达出了不同的界面和交互方式。作为播放器,界面可以是千差万别的。《番茄播放器》的iOS平台上我开发了传统版本,和基于手势播放的版本。它们界面不同,但用的同一个播放内核。作为播放内核项目,在MatoMusic.Core的工作已经结束。本系列博文重点还是在播放器思路的解读,关于MAUI动画交互,我打算有时间另外写博客(这里给自己挖个坑)。

jevonsflash的专栏 2014
上一篇: 将Abp移植进.NET MAUI项目(二):配置与基类编写
下一篇: [学习笔记]使用Docker+Jenkin自动化流水线发布.Net应用
林晓lx
林晓lx 2017年优快云移动跨平台大赛优秀奖获得者 2017年优快云移动跨平台大赛优秀奖获得者
博客等级 码龄15年 3761粉丝 123原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林晓lx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值