当前位置: 首页 > article >正文

Maui学习笔记- SQLite简单使用案例

在本案例中我们将使用EFCore对象关系映射器,对SQLite数据库进行添加删除操作。我们将从数据库读取数据并显示在CollectionView中。并使用RefreshView实现下拉刷新数据。

 IOS下运行程序

 创建项目

首先需要安装NuGet包

  • Microsoft.EntityFrameworkCore.Sqlite

  • CommunityToolkit.Mvvm

  • CommunityToolkit.Maui(需要在MauiProgram内引入)

  • EFCore使用DbContext连接数据库并使用DbSet<>表示数据中的每个表。

创建用户表和数据模型

public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
}
public class UserContext:DbContext
{
    public DbSet<User> Users { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        string daPath = Path.Combine(FileSystem.AppDataDirectory, "localdatabase.db");
        //EFCore支持不同的数据库,这里我们使用SQLite
        optionsBuilder.UseSqlite($"Filename={daPath}");
        
        base.OnConfiguring(optionsBuilder);
    }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
      //为数据库设置初始数据
        modelBuilder.Entity<User>().HasData(new User
        {
            Id = 1,
            Name = "张三",
            Email = "张三@163.com",
            Phone = "123456789"
        });
        
        base.OnModelCreating(modelBuilder);
    }
}
  • 在APP.xaml.cs中初始化数据库

public partial class App : Application
{
    public App()
    {
        SQLitePCL.Batteries_V2.Init();

        using (var context = new UserContext())
        {
            context.Database.EnsureCreated();
        }
        
        InitializeComponent();

        MainPage = new AppShell();
    }
}
  • 创建ViewModels目录并创建MainViewModel

  • 使用User类绑定到CollectionView,并使用Refreshing绑定到RefreshView元素。

  • LoadUserAsync用来刷新视图,加载数据。

public partial class MainViewModel:ObservableObject
{
    [ObservableProperty]
    ObservableCollection<User> users;

    [ObservableProperty] private bool refreshing;

  
    [RelayCommand]
    private async Task LoadUserAsync()
    {
        await Task.Run(() =>
        {
            using var context = new UserContext();

            Users = new ObservableCollection<User>(context.Users);
        });

        Refreshing = false;
    }

    [RelayCommand]
    void Showing()
    {
        Refreshing = true;
    }
  
  //删除用户
  [RelayCommand]
    private void DeleteUser(User user)
    {
        var context = new UserContext();

        context.Users.Remove(user);
        
        context.SaveChanges();
        
        Users.Remove(user);
    }

  //导航到用户编辑页面
    [RelayCommand]
    private async Task ShowNewFormAsync()
    {
        await Shell.Current.GoToAsync(nameof(UserEditPage),parameters:new Dictionary<string, object>
        {
            {"ParentRefreshAction",(Func<User,Task>)RefreshAddedAsync},
            {"Item",new User()}
        });
    }

}
  • 创建UserEditPage视图页面和UserEditViewModel

  • 在UserEditViewModel中我们要实现IQueryAttributable接口

  • ApplyQueryAttributes从查询参数中加载用户对象和刷新回调函数。 SaveAsync保存用户信息到数据库,并调用父页面的刷新操作,最后返回上一页。

public partial class UserEditViewModel:ObservableObject,IQueryAttributable
{
  //接受当前编辑的用户信息
    [ObservableProperty] private User itemUser;

  //用于在保存后刷新主页
   protected Func<User, Task> ParentRefreshAction { get;set; }

    [RelayCommand]
    private async Task SaveAsync()
    {
        await using var context = new UserContext();
        
        context.Users.Add(ItemUser);

        context.SaveChangesAsync();
        
        await ParentRefreshAction(ItemUser);
        
        await Shell.Current.GoToAsync("..");
    }
    
    public void ApplyQueryAttributes(IDictionary<string, object> query) {
        if (query.TryGetValue("Item", out object currentItem)) {
             ItemUser = (User)currentItem;
        }
        if (query.TryGetValue("ParentRefreshAction", out object parentRefreshAction)) {
            ParentRefreshAction = (Func<User, Task>)parentRefreshAction;
        }
        query.Clear();
    }
}
  • UserEditPage页面上的Entry用来接收用户信息。

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:vm="clr-namespace:MauiApp3.ViewModels;assembly=MauiApp3"
             x:Class="MauiApp3.Views.UserEditPage"
             Title="新用户">
    <ContentPage.BindingContext>
        <vm:UserEditViewModel/>
    </ContentPage.BindingContext>
    
    <Grid>
        <VerticalStackLayout VerticalOptions="Start">
            <Entry Placeholder="用户名"
                   Text="{Binding ItemUser.Name}"/>
            <Entry Placeholder="电话"
                   Text="{Binding ItemUser.Phone}"/>
            <Entry Placeholder="Email"
                   Text="{Binding ItemUser.Email}"
                   ReturnCommand="{Binding SaveCommand}"/>
            <Button Text="保存" 
                    Command="{Binding SaveCommand}"/>
        </VerticalStackLayout>
        <ActivityIndicator 
            VerticalOptions="Center"
            HorizontalOptions="Center"
            IsRunning="{Binding SaveCommand.IsRunning}"/>
    </Grid>
</ContentPage>
  • 注册路由页面

public partial class AppShell : Shell
{
    public AppShell()
    {
        InitializeComponent();
        Routing.RegisterRoute(nameof(UserEditPage),typeof(UserEditPage));
    }
}
  • 主页代码

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:vm="clr-namespace:MauiApp3.ViewModels"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             xmlns:models="clr-namespace:MauiApp3.Models"
             x:DataType="{x:Type vm:MainViewModel}"
             x:Class="MauiApp3.MainPage">
    <ContentPage.BindingContext>
        <vm:MainViewModel/>
    </ContentPage.BindingContext>
    <ContentPage.Behaviors>
        <toolkit:EventToCommandBehavior
            EventName="Appearing"
            Command="{Binding ShowingCommand}"/>
    </ContentPage.Behaviors>
    <ContentPage.Resources>
        <DataTemplate 
            x:Key="UserTemplate"
            x:DataType="models:User">
            <SwipeView>
                <SwipeView.RightItems>
                    <SwipeItem
                        Text="Delete"
                        BackgroundColor="IndianRed"
                        Command="{Binding Path=BindingContext.DeleteUserCommand,Source={RelativeSource Mode=FindAncestor,AncestorType={x:Type ContentPage}}}"
                        CommandParameter="{Binding}"/>
                </SwipeView.RightItems>
            
            <Grid RowDefinitions="40,40"
                  ColumnDefinitions="*,*"
                  Padding="10">
                <Label
                    Text="{Binding Name}"/>
                <Label
                    Text="{Binding Phone}"
                    Grid.Column="1"/>
                <Label
                    Text="{Binding Email}"
                    TextColor="DarkGrey"
                    Grid.Row="1"
                    Grid.ColumnSpan="2"/>
                
            </Grid>
            </SwipeView>
        </DataTemplate>
    </ContentPage.Resources>
    <Grid>
        <RefreshView IsRefreshing="{Binding Refreshing}"
                     Command="{Binding LoadUsersCommand}">
            <CollectionView ItemsSource="{Binding Users}"
                            ItemTemplate="{StaticResource UserTemplate}"/>
        </RefreshView>
        
        <Button
            Text="+"
            Command="{Binding ShowNewFormCommand }"
            WidthRequest="56"
            HeightRequest="56"
            FontSize="24"
            HorizontalOptions="End"
            VerticalOptions="End"
            Margin="16"/>
    </Grid>
 

</ContentPage>

后续会对该案例添加一个用户详情页面,并改进优化一下代码。


http://www.kler.cn/a/519136.html

相关文章:

  • 2024年度总结(具身智能赛道,欢迎交流)
  • 【中间件快速入门】什么是Redis
  • 【算法】快速排序1
  • Linux的基本指令(上)
  • 论文阅读的附录(七):Understanding Diffusion Models: A Unified Perspective(二):公式46的推导
  • mysql数据被误删的恢复方案
  • 基于ESP32的桌面小屏幕实战[6]:环境搭建和软件基础
  • 一次StarRocks分析的经历
  • 第25章 测试驱动开发模式深度剖析
  • unity 粒子系统实现碰撞检测(collision)且使粒子不受力
  • tcp/ip协议和ip协议,tcp/ip协议 ip协议
  • 探索JavaScript:网页设计中的创意与实践
  • leetcode——翻转链表(java)
  • (回溯分割)leetcode93 复原IP地址
  • AI学习(vscode+deepseek+cline)
  • INMP441一款微型电容式麦克风(MEMS麦克风)
  • Zookeeper(28)Zookeeper的线性化写入和顺序一致性读是什么?
  • 代码随想录day4
  • 【论文推荐|深度学习,滑坡检测,多光谱影像,自然灾害,遥感】2022年Landslide4Sense竞赛成果:基于多源卫星影像的先进滑坡检测算法研究(一)
  • 手机app如何跳过无障碍权限实现弹框自动点击-ADB连接专题
  • Redis 详解
  • 开源智慧园区管理系统对比五款主流产品探索智能运营新模式
  • PCB布线注意事项(1)
  • 深度学习 | 表示学习 | 卷积神经网络|翻转卷积核是干啥呢|09
  • 搭建Spring Boot开发环境
  • hot100_141. 环形链表