[MAUI]在.NET MAUI中实现可拖拽排序列表

.NET MAUI第三方UI组件库实战:maui-ui-components-skills深度解析与应用指南 在跨平台应用开发领域,UI组件库是提升开发效率与界面一致性的关键技术。其核心原理在于通过封装可复用的视觉元素与交互逻辑,为开发者提供标准化构建模块。从技术价值看,优秀的组件库能显著降低界面开发复杂度,确保多平台体验统一,并促进团队协作规范。在实际应用场景中,开发者常面临官方控件功能不足、定制成本高等痛点,这正是第三方增强库的用武之地。本文聚焦的maui-ui-components-skills库,正是针对.NET MAUI框架的**补位与增强**方案,通过**自定义控件**与**附加行为**等混合架构,为输 阅读详情


.NET MAUI 中提供了拖放(drag-drop)手势识别器,允许用户通过拖动手势来移动控件。在这篇文章中,我们将学习如何使用拖放手势识别器来实现可拖拽排序列表。在本例中,列表中显示不同大小的磁贴(Tile)并且可以拖拽排序。

在这里插入图片描述

使用.NET MAU实现跨平台支持,本项目可运行于Android、iOS平台。

创建可拖放控件

新建.NET MAUI项目,命名Tile

当手指触碰可拖拽区域超过一定时长(不同平台下时长不一定相同,如在Android中是1s)时,将触发拖动手势。
手指离开屏幕时,将触发放置手势。

启用拖动

为页面视图控件创建拖动手势识别器(DragGestureRecognizer), 它定义了以下属性:

属性类型描述
CanDragbool指明手势识别器附加到的控件能否为拖动源。 此属性的默认值为 true。
CanDragbool指明手势识别器附加到的控件能否为拖动源。 此属性的默认值为 true。
DragStartingCommandICommand在第一次识别拖动手势时执行。
DragStartingCommandParameterobject是传递给 DragStartingCommand 的参数。
DropCompletedCommandICommand在放置拖动源时执行。
DropCompletedCommandParameterobject是传递给 DropCompletedCommand 的参数。

启用放置

为页面视图控件创建放置手势识别器(DropGestureRecognizer), 它定义了以下属性:

属性类型描述
AllowDropbool指明手势识别器附加到的元素能否为放置目标。 此属性的默认值为 true。
DragOverCommandICommand在拖动源被拖动到放置目标上时执行。
DragOverCommandParameterobject是传递给 DragOverCommand 的参数。
DragLeaveCommandICommand在拖动源被拖至放置目标上时执行。
DragLeaveCommandParameterobject是传递给 DragLeaveCommand 的参数。
DropCommandICommand在拖动源被放置到放置目标上时执行。
DropCommandParameterobject是传递给 DropCommand 的参数。

创建可拖拽控件的绑定类,实现IDraggableItem接口,定义拖动相关的属性和命令。

public interface IDraggableItem
{
    bool IsBeingDraggedOver { get; set; }
    bool IsBeingDragged { get; set; }
    Command Dragged { get; set; }
    Command DraggedOver { get; set; }
    Command DragLeave { get; set; }
    Command Dropped { get; set; }
    object DraggedItem { get; set; }
    object DropPlaceHolderItem { get; set; }
}

Dragged: 拖拽开始时触发的命令。
DraggedOver: 拖拽控件悬停在当前控件上方时触发的命令。
DragLeave: 拖拽控件离开当前控件时触发的命令。
Dropped: 拖拽控件放置在当前控件上方时触发的命令。

IsBeingDragged 为true时,通知当前控件正在被拖拽。
IsBeingDraggedOver 为true时,通知当前控件正在有拖拽控件悬停在其上方。

DraggedItem: 正在拖拽的控件。
DropPlaceHolderItem: 悬停在其上方时的控件,即当前控件的占位控件。

此时可拖拽控件为磁贴片段(TileSegement), 创建一个类用于描述磁贴可显示的属性,如标题、描述、图标、颜色等。

public class TileSegment 
{
    public string Title { get; set; }
    public string Type { get; set; }
    public string Desc { get; set; }
    public string Icon { get; set; }
    public Color Color { get; set; }
}

创建绑定服务类

创建可拖拽控件的绑定服务类TileSegmentService,继承ObservableObject,并实现IDraggableItem接口。

public class TileSegmentService : ObservableObject, ITileSegmentService
{
    ...
}

拖拽(Drag)

拖拽开始时,将IsBeingDragged设置为true,通知当前控件正在被拖拽,同时将DraggedItem设置为当前控件。

private void OnDragged(object item)
{
    IsBeingDragged=true;
    DraggedItem=item;
}

拖拽悬停,经过(DragOver)

拖拽控件悬停在当前控件上方时,将IsBeingDraggedOver设置为true,通知当前控件正在有拖拽控件悬停在其上方,同时在服务列表中寻找当前正在被拖拽的服务,将DropPlaceHolderItem设置为当前控件。

private void OnDraggedOver(object item)
{
    if (!IsBeingDragged && item!=null)
    {
        IsBeingDraggedOver=true;

        var itemToMove = Container.TileSegments.First(i => i.IsBeingDragged);
        if (itemToMove.DraggedItem!=null)
        {
            DropPlaceHolderItem=itemToMove.DraggedItem;

        }
    }

}

离开控件上方时,IsBeingDraggedOver设置为false

private void OnDragLeave(object item)
{
    IsBeingDraggedOver = false;
}

释放(Drop)

拖拽完成时,获取当前正在被拖拽的控件,将其从服务列表中移除,然后将其插入到当前控件的位置,通知当前控件拖拽完成。

private void OnDropped(object item)
{
    var itemToMove = Container.TileSegments.First(i => i.IsBeingDragged);

    if (itemToMove == null ||  itemToMove == this)
        return;


    Container.TileSegments.Remove(itemToMove);

    var insertAtIndex = Container.TileSegments.IndexOf(this);

    Container.TileSegments.Insert(insertAtIndex, itemToMove);
    itemToMove.IsBeingDragged = false;
    IsBeingDraggedOver = false;
    DraggedItem=null;

}

完整的TileSegmentService代码如下:

public class TileSegmentService : ObservableObject, ITileSegmentService
{

    public TileSegmentService(
        TileSegment tileSegment)
    {
        Remove = new Command(RemoveAction);
        TileSegment = tileSegment;

        Dragged = new Command(OnDragged);
        DraggedOver = new Command(OnDraggedOver);
        DragLeave = new Command(OnDragLeave);
        Dropped = new Command(i => OnDropped(i));

    }

    private void OnDragged(object item)
    {
        IsBeingDragged=true;
    }

    private void OnDraggedOver(object item)
    {
        if (!IsBeingDragged && item!=null)
        {
            IsBeingDraggedOver=true;

            var itemToMove = Container.TileSegments.First(i => i.IsBeingDragged);
            if (itemToMove.DraggedItem!=null)
            {
                DropPlaceHolderItem=itemToMove.DraggedItem;

            }
        }

    }


    private object _draggedItem;

    public object DraggedItem
    {
        get { return _draggedItem; }
        set
        {
            _draggedItem = value;
            OnPropertyChanged();
        }
    }

    private object _dropPlaceHolderItem;

    public object DropPlaceHolderItem
    {
        get { return _dropPlaceHolderItem; }
        set
        {
            _dropPlaceHolderItem = value;
            OnPropertyChanged();
        }
    }

    private void OnDragLeave(object item)
    {

        IsBeingDraggedOver = false;
        DraggedItem = null;

    }

    private void OnDropped(object item)
    {
        var itemToMove = Container.TileSegments.First(i => i.IsBeingDragged);

        if (itemToMove == null ||  itemToMove == this)
            return;


        Container.TileSegments.Remove(itemToMove);

        var insertAtIndex = Container.TileSegments.IndexOf(this);

        Container.TileSegments.Insert(insertAtIndex, itemToMove);
        itemToMove.IsBeingDragged = false;
        IsBeingDraggedOver = false;
        DraggedItem=null;

    }

    private async void RemoveAction(object obj)
    {
        if (Container is ITileSegmentServiceContainer)
        {
            (Container as ITileSegmentServiceContainer).RemoveSegment.Execute(this);
        }
    }


    public IReadOnlyTileSegmentServiceContainer Container { get; set; }


    private TileSegment tileSegment;

    public TileSegment TileSegment
    {
        get { return tileSegment; }
        set
        {
            tileSegment = value;
            OnPropertyChanged();

        }
    }


    private bool _isBeingDragged;
    public bool IsBeingDragged
    {
        get { return _isBeingDragged; }
        set
        {
            _isBeingDragged = value;
            OnPropertyChanged();

        }
    }

    private bool _isBeingDraggedOver;
    public bool IsBeingDraggedOver
    {
        get { return _isBeingDraggedOver; }
        set
        {
            _isBeingDraggedOver = value;
            OnPropertyChanged();

        }
    }

    public Command Remove { get; set; }


    public Command Dragged { get; set; }

    public Command DraggedOver { get; set; }

    public Command DragLeave { get; set; }

    public Command Dropped { get; set; }
}

创建页面元素

在Controls目录下创建不同大小的磁贴控件,如下图所示。

在这里插入图片描述

在MainPage中创建CollectionView,用于将磁贴元素以列表形式展示。

<CollectionView Grid.Row="1"
                x:Name="MainCollectionView"
                ItemsSource="{Binding TileSegments}"
                ItemTemplate="{StaticResource TileSegmentDataTemplateSelector}">
    <CollectionView.ItemsLayout>
        <LinearItemsLayout Orientation="Vertical" />
    </CollectionView.ItemsLayout>
</CollectionView>

创建MainPageViewModel,创建绑定服务类集合TileSegments,初始化中添加一些不同颜色,大小的磁贴,并将TileSegementService.Container设置为自己(this)。

不同大小的磁贴通过绑定相应的数据,使用不同的数据模板进行展示。请阅读博文 [MAUI程序设计]界面多态与实现,了解如何实现列表Item的多态。

在这里插入图片描述

在MainPage中创建磁贴片段数据模板选择器(TileSegmentDataTemplateSelector),用于根据磁贴片段的大小选择不同的数据模板。

<DataTemplate x:Key="SmallSegment">
    <controls1:SmallSegmentView  Margin="0,5"
                                    ControlTemplate="{StaticResource TileSegmentTemplate}">
    </controls1:SmallSegmentView>
</DataTemplate>
<DataTemplate x:Key="MediumSegment">
    <controls1:MediumSegmentView Margin="0,5"
                                    ControlTemplate="{StaticResource TileSegmentTemplate}">

    </controls1:MediumSegmentView>
</DataTemplate>
<DataTemplate x:Key="LargeSegment">
    <controls1:LargeSegmentView Margin="0,5"
                                ControlTemplate="{StaticResource TileSegmentTemplate}">

    </controls1:LargeSegmentView>
</DataTemplate>
<controls1:TileSegmentDataTemplateSelector x:Key="TileSegmentDataTemplateSelector"
                                            ResourcesContainer="{x:Reference Main}" />

创建磁贴控件模板TileSegmentTemplate,并在此指定DropGestureRecognizer

<ControlTemplate x:Key="TileSegmentTemplate">
    <ContentView>
        <StackLayout>
            <StackLayout.GestureRecognizers>
                <DropGestureRecognizer AllowDrop="True"
                                        DragLeaveCommand="{TemplateBinding BindingContext.DragLeave}"
                                        DragLeaveCommandParameter="{TemplateBinding}"
                                        DragOverCommand="{TemplateBinding BindingContext.DraggedOver}"
                                        DragOverCommandParameter="{TemplateBinding}"
                                        DropCommand="{TemplateBinding BindingContext.Dropped}"
                                        DropCommandParameter="{TemplateBinding}" />
            </StackLayout.GestureRecognizers>
            
        </StackLayout>
    </ContentView>
</ControlTemplate>

创建磁贴控件外观Layout,<ContentPresenter />处将呈现磁贴片段的内容。在Layout指定DragGestureRecognizer。

<Border x:Name="ContentLayout"
        Margin="0">
    <Grid>
        <Grid.GestureRecognizers>
            <DragGestureRecognizer CanDrag="True"
                                    DragStartingCommand="{TemplateBinding BindingContext.Dragged}"
                                    DragStartingCommandParameter="{TemplateBinding}" />
        </Grid.GestureRecognizers>

        <ContentPresenter />
        <Button CornerRadius="100"
                HeightRequest="20"
                WidthRequest="20"
                Padding="0"
                BackgroundColor="Red"
                TextColor="White"
                Command="{TemplateBinding BindingContext.Remove}"
                Text="×"
                HorizontalOptions="End"
                VerticalOptions="Start"></Button>
    </Grid>
</Border>

在这里插入图片描述

创建占位控件,用于指示松开手指时,控件将放置的位置区域,在这里绑定DropPlaceHolderItem的高度和宽度。

<Border StrokeThickness="4"
        StrokeDashArray="2 2"
        StrokeDashOffset="6"
        Stroke="black"
        HorizontalOptions="Center"
        IsVisible="{TemplateBinding BindingContext.IsBeingDraggedOver}">
    <Grid HeightRequest="{TemplateBinding BindingContext.DropPlaceHolderItem.Height}"
            WidthRequest="{TemplateBinding BindingContext.DropPlaceHolderItem.Width}">
        <Label HorizontalTextAlignment="Center"
                VerticalOptions="Center"
                Text="松开手指将放置条目至此处"></Label>


    </Grid>
</Border>

最终效果

在这里插入图片描述

项目地址

Github:maui-samples

关注我,学习更多.NET MAUI开发知识!

【MAUI】自定义 .NET MAUI XAML 页面中的布局 .NET MAUI 布局面板可帮助您在各种设备上为应用程序创建一致的用户界面。假设您正在构建一个提示计算器应用程序,您计划在许多计算机和设备上部署该应用程序。每个设备可以具有不同的屏幕尺寸和像素密度。您的目标是使应用程序在所有设备上看起来尽可能相似。您希望避免手动计算每个屏幕尺寸的视图大小和位置。.NET MAUI 包括一个布局管理系统,可为您执行这些计算。您可以将视图放在布局面板中,这些布局面板会自动管理其子视图的大小和位置。这些面板使在不同设备上创建一致的用户界面变得更加容易。在本模块中,您将构建一个在 阅读详情

相关推荐

在LangChain中使用DashVector进行高效向量检索

DashVector为需要处理高维向量数据的开发者提供了一种便捷且高效的解决方案。通过将其集成到LangChain生态系统中,您可以轻松实现复杂的语义搜索和数据分析功能。DashVector官方文档LangChain GitHub仓库有关DashVector的详细notebook示例。

sjufgwgfhoia的博客 455

.Net MAUI 页面导航,页面传值,集合,列表,object

MAUI不同页面键复杂传值,两个页面传值

qq_25414835的博客 2165

保姆级教程:在LKD3588开发板上为RK3588添加SC2210摄像头驱动(含完整DTS配置)

本文提供了一份详细的教程,指导如何在LKD3588开发板上为RK3588处理器添加SC2210摄像头驱动,包括完整的DTS配置和内核编译步骤。教程涵盖了环境准备、驱动文件添加、DTS配置详解、内核编译与烧录、驱动测试以及常见问题排查,帮助开发者快速实现SC2210传感器在RK3588平台上的集成与优化。

weixin_42641741的博客 480

[MAUI]实现动态拖拽排序网格

拖拽控件悬停在当前控件上方时,将IsBeingDraggedOver设置为true,通知当前控件正在有拖拽控件悬停在其上方,同时在服务列表中寻找当前正在被拖拽的服务,将DropPlaceHolderItem设置为当前控件。当以比较快的速度,拖拽Tile经过较多的位置时,后面的Tile会短暂地替代原先的位置,导致拖拽中的Tile不在期望的Tile上方,而拖拽中的Tile与错误的Tile产生了交叠从而触发DraggedOver事件,导致错乱。其是在松开手指之后才向列表提交条目位置变更的命令。

jevonsflash的专栏 721

Zynq/ZynqMP PL端以太网实战:手把手教你用GMII to RGMII IP和EMIO打通网络(附KSZ9031 PHY驱动修改)

本文详细介绍了在Zynq/ZynqMP平台上使用GMII to RGMII IP核和EMIO接口实现PL端以太网通信的全栈开发流程,特别针对KSZ9031 PHY芯片提供了定制化驱动修改方案。内容涵盖硬件设计、Vivado配置、裸机驱动开发、Linux系统集成及实战调试技巧,帮助开发者高效解决工业控制和边缘计算中的以太网连接问题。

weixin_30642561的博客 582

如何有效爬取“好大夫”评论数据?技术实现与合规性分析

本文探讨了爬取好大夫在线医生评论数据的技术与合规性问题。分析了好大夫平台评论数据的价值和特点,指出其动态加载和反爬机制的挑战。技术上,推荐使用Selenium模拟浏览器行为获取数据,并提供了分页爬取、代理IP、验证码识别等解决方案。同时强调必须遵守平台的爬虫策略,关注用户协议和隐私保护法规,建议通过官方API或授权方式获取数据。文章还讨论了数据清洗存储方法,并提醒注意数据伦理和最小化抓取原则。本文为医疗数据爬取提供了技术实现和合规性指导的平衡方案。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1052

推荐文章:探索高效列表渲染 —— .NET MAUI 虚拟化列表控件 VirtualListView

推荐文章:探索高效列表渲染 —— .NET MAUI 虚拟化列表控件 VirtualListView 在移动与跨平台应用开发的前沿阵地,我们常常面临一个挑战:如何展示大量数据,同时保持界面的流畅性和响应速度。对于.NET MAUI开发者而言,VirtualListView正是为此而生的一把利器,它以实验性的姿态,为你开辟了新的可能性。 项目简介 VirtualListView是针对.NET MAU...

gitblog_00009的博客 1385

平行趋势检验没通过怎么办?别慌,试试三重差分DDD与事件研究法

本文探讨了当平行趋势检验未通过时,如何运用三重差分法(DDD)与事件研究法进行政策评估。通过Stata代码示例和实战案例,详细介绍了DDD的原理、适用场景及实现步骤,并提供了替代方案如合成控制法和匹配DID,帮助研究者获得更准确的因果推断结果。

weixin_28732953的博客 614

虚拟化列表控件,提升MAUI应用性能:VirtualizeListView

虚拟化列表控件,提升MAUI应用性能:VirtualizeListView 虚拟化ListView:项目的核心功能/场景 MAUI中的ListView和CollectionView滚动性能不佳是公认的问题。VirtualizeListView项目旨在通过使用ScrollView和AbsoluteLayout实现虚拟列表,以提升滚动性能。 项目介绍 MPowerKit.VirtualizeListV...

gitblog_00223的博客 490

创龙 瑞芯微 RK3588 国产工业开发板—Qt交叉编译环境搭建与GPU图形渲染实战

本文详细介绍了在创龙RK3588国产工业开发板上搭建Qt交叉编译环境并利用GPU进行图形渲染的完整实战流程。文章从环境准备入手,讲解了交叉编译工具链的配置,并提供了命令行与Qt Creator两种编译方法。通过部署运行和自启动设置,确保程序在板卡上稳定运行。最后,通过OpenGL案例实战,展示了如何调用RK3588的GPU进行高效图形渲染,释放其图形处理潜力,适用于工业HMI、智能终端等高要求图形界面开发。

weixin_28278377的博客 450

从DCI-P3到sRGB:跨媒体色彩转换的矩阵奥秘与实践

本文深入解析从DCI-P3到sRGB的色彩空间转换技术,揭示矩阵运算的核心原理与实践技巧。通过实战案例展示如何正确处理白点差异、伽马曲线转换等关键环节,帮助影视从业者解决跨媒体色彩匹配问题,确保作品在不同设备上呈现一致的视觉效果。

weixin_28709649的博客 328

告别传统点击事件,.NET MAUI手势命令让你的应用瞬间灵动起来

掌握.NET MAUI 的手势识别命令,轻松实现滑动、捏合等交互操作,提升应用用户体验。适用于移动端多点触控场景,代码简洁易集成,告别传统点击事件束缚,让应用更灵动流畅,值得收藏。

SimSolve的博客 879

AUTOSAR进阶图解==>AUTOSAR_SWS_COM

AUTOSAR COM模块是AUTOSAR通信堆栈的核心组件,提供信号导向的通信服务。该模块位于通信服务层,连接RTE与PDU Router,主要功能包括信号封装/提取、传输模式管理、信号路由、超时监控和字节序转换等。COM模块架构分为应用层、通信服务层和通信抽象层,包含信号管理、I-PDU处理、传输模式管理等组件。其配置结构包括顶层容器、I-PDU组、I-PDU和信号等多层次配置对象,支持丰富的参数设置。模块采用严格的状态管理机制,包括模块状态和I-PDU组状态转换,确保通信可靠性。

一名留德华的,康德的信徒的,专注于汽车电子领域的博客 1244

揭秘 .NET MAUI 性能优化技巧:learn-dotnet-maui 中的最佳实践

.NET MAUI(Multi-platform App UI)作为微软推出的跨平台应用开发框架,允许开发者使用 C# 和 XAML 构建运行在 iOS、Android、macOS 和 Windows 上的原生应用。然而,跨平台应用常面临性能挑战,本文将结合 learn-dotnet-maui 项目中的资源,分享提升 .NET MAUI 应用性能的实用技巧,帮助开发者打造流畅高效的用户体验。 [

gitblog_01047的博客 434

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

【.NET MAUI开发必知】:3大常用手势命令的高效实现方案

掌握.NET MAUI手势交互核心技巧,本文详解点击、滑动、缩放三大常用手势识别命令的高效实现方案,涵盖移动端开发典型场景与响应式编程方法,提升应用用户体验。代码清晰易集成,值得收藏。

FuncFun的博客 378

精雕软件(JDpaint) 5.5 绿色版

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

[MAUI 项目实战] 笔记App(一):介绍与程序设计

有人说现在记事类app这么多,市场这么卷,为什么还想做一个笔记类App?一来,去年小孩刚出生,需要一个可以记录喂奶时间的app,发现市面上没有一款app能够在两步内简单记录一个时间,可能iOS可以通过备忘录配合捷径做到快速记录,但是安卓上就没有类似的app。二是,自去年做的音乐播放器以来,很长一段时间我在博客上的XF,MAUI都是在介绍局部的功能,[MAUI 项目实战]专题也很长没更新了,这次通过笔记类App做一次完整项目,包括如何上架MAUI应用等内容一并更新了。

jevonsflash的专栏 1786

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

【打造动态布局新体验】—— 探索Sharpnado.CollectionView(.Maui): 开源界的新星

【打造动态布局新体验】—— 探索Sharpnado.CollectionView(.Maui): 开源界的新星 在移动应用开发的浩瀚星空下,有一颗璀璨的新星正以其独特的光芒闪耀——那就是Sharpnado.CollectionView(.Maui)。这个项目,曾以“HorizontalListView”之名惊艳开发者社区,如今已蜕变升级为更强大、更灵活的解决方案,旨在为跨平台应用的UI设计带来革命...

gitblog_00013的博客 1204

仅限高级开发者知晓的.NET MAUI手势黑科技(90%人忽略的关键细节)

掌握.NET MAUI的手势识别命令,轻松实现复杂交互。适用于移动端高效开发,支持单击、双击、拖拽等场景,通过命令绑定提升代码可维护性。详解事件处理与自定义手势组合技巧,性能更优,值得收藏。

CodePulse的博客 593

.NET MAUI 6.1控件体系解析与跨平台开发实践

跨平台UI开发框架通过统一API抽象实现多端适配,其核心在于控件系统的设计与优化。以布局引擎为例,Grid/StackLayout等控件采用差异化的测量算法,在保持原生渲染性能的同时提供声明式编程接口。.NET MAUI 6.1作为微软新一代框架,将Xamarin.Forms的分散架构升级为统一控件模型,显著提升开发效率。该版本重点优化了FlexLayout等动态布局方案,并增强CollectionView的数据虚拟化能力,使百万级数据列表仍能保持60fps流畅滚动。在移动应用和桌面程序开发场景中,开发者可

weixin_29248653的博客 338

推荐开源项目:AiForms.SettingsView——打造高效.NET MAUI设置界面

推荐开源项目:AiForms.SettingsView——打造高效.NET MAUI设置界面 在构建移动应用时,提供一个直观且易于定制的设置界面是提升用户体验的关键一步。今天,我们来探索一款专为.NET MAUI设计的强大组件——AiForms.SettingsView。这个库旨在简化Android和iOS平台上设置界面的开发,即使是在预览阶段,其潜力已不容小觑。 项目介绍 AiForms.Set...

gitblog_00073的博客 656

ScottPlot 如何快速上手:.NET 数据可视化 3 步装好

你正在做一个 .NET 应用,手里有一批传感器或实验数据,想立刻在界面上画出折线图、散点图或直方图,又不想折腾复杂的渲染配置。**ScottPlot** 就是一个专为 .NET 设计的开源数据可视化库:MIT 协议,当前版本 5.1.60,通过 **NuGet** 直接安装,输出从控制台图片文件到交互式桌面窗口都能覆盖。 ## 📍 ScottPlot 是什么:3 句话定位 - 它是一个 .N

gitblog_00045的博客 232

Windows 桌面软件用什么框架开发好?

最方便上手、纯 Windows:直接用,几小时就能出个可用软件。追求现代/跨平台WinUI 3或.NET MAUI。有网页基础Electron。其他如 Qt(C++,专业跨平台 UI)、Avalonia(.NET 跨平台 UI)也很好,但上手门槛更高。建议从 Visual Studio 开始(免费下载试用),Microsoft 文档和社区支持最完善。如果你有具体需求(如语言、UI 复杂度),可以再细说,我帮你选更精确的!

纠缠AI的亮子 1684

.NET周刊【8月第3期 2023-08-20】

国内主题抓的是周树人,与我鲁迅有什么关系?https://www.cnblogs.com/JulianHuang/p/17642511.html问题:作者看到了一个关于Dictionary.Clear和new Dictionary的问题,想要探究为什么在foreach字典的过程中,这两种操作不会报错。分析:作者分析了C#字典的源码,发现foreach字典会产生一个迭代器,它有一个指向原字典的字段。...

dotNET跨平台 231

.NET周刊【6月第3期 2025-06-15】

本文介绍了一个开源的WPF自定义控件资源库WPF-ControlBase,功能丰富且免费(MIT许可证)。WPF是构建具有丰富用户界面的Windows桌面应用程序的强大框架,具备灵活布局、数据绑定和动画效果。文章提供了多个解决方案的源代码,包括演示项目和NuGet包的引用。同时,作者鼓励用户访问GitHub获取更多信息,并支持项目。该资源库已被列入优秀的C#/.NET/.NET Core项目推荐中,以帮助开发者获取最新的动态和最佳实践。

InCerry的博客 954

AiForms.SettingsView 使用指南

AiForms.SettingsView 使用指南 1. 项目介绍 AiForms.SettingsView 是一个专为 Xamarin.Forms 和 .NET MAUI 设计的高度灵活的 TableView 组件,主要用于构建 Android 和 iOS 平台上的设置界面。它提供了丰富的功能,包括但不限于自定义分隔线颜色、选中单元格颜色设定,以及针对各个部分(section)的高级定制能力,如...

gitblog_00396的博客 415
上一篇: 在Volo.Abp微服务中使用SignalR
下一篇: [MAUI]实现动态拖拽排序网格
林晓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、付费专栏及课程。

余额充值