.NET MAUI 开发电子木鱼(下)

简介: 本文介绍如何使用 .NET MAUI 开发一个电子木鱼应用。以实际的小应用开发为例,通过这个开发过程,介绍了其涉及的 .NET MAUI、Blazor、前端等相关知识点。文章涉及的应用已开源在 Github,大家可前往下载体验: https://github.com/sangyuxiaowu/MuYu

1. 背景

前面我们介绍了 《.NET MAUI 开发电子木鱼(上)》 ,接下来进行设置相关功能的开发。主要包含:敲击计数和自动敲击模式切换。

2. 相关知识点

本篇主要有如下相关知识点:

  1. .NET MAUI 生命周期
  2. .NET MAUI Blazor 在应用关闭前保存数据
  3. Blazor 中的计时器,System.Threading.Timer 的使用和启停

3. 开发过程

3.1 敲击计数

敲击计数这里主要记录当日敲击数和总敲击数,为了满足各路神仙的敲击,这里我们用 long,还是使用 Preferences 存储。

private long AllNum = 0;
private long TodayNum = 0;

在主页面 Index.razor 首次渲染时,我们读取存储的计数信息。

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        AllNum = Preferences.Default.Get("all_num", 0L);
        if (DateTime.Now.ToShortDateString() == Preferences.Default.Get("today",""))
        {
            TodayNum = Preferences.Default.Get("today_num", 0L);
        }
    }
}
需要注意的是: AllNumlong 型, Preferences.Default.Get 传的默认值是为了推断取得的存储内容的类型,所以这里要用 0L 需要标记为 long 型。否则首次启动无错误,当存储过数据后就会报错,数据类型无法转换。

接下来我们只需要实现一个计数的添加和存储功能即可:

void AddNum()
{
    // 当前日期
    var today = DateTime.Now.ToShortDateString();
    // 存储的日期
    string save_today = Preferences.Default.Get("today", "");

    // 天数未发生变更,防的就是半夜敲的
    if (save_today == today)
    {
        TodayNum++;
    }else{
        TodayNum = 1;
        Preferences.Default.Set("today", today);
    }

    AllNum++;

    Preferences.Default.Set("today_num", TodayNum);
    Preferences.Default.Set("all_num", AllNum);
}

3.2 计数问题优化

前面一节虽然实现了敲击计数,但是设计也存在一些不合理的地方:频繁的 Preferences 写入毕竟不好。毕竟这种应用,没必要实时保存了,最好是获取到应用的关闭事件,在应用关闭时保存即可。

但是因为 .NET MAUI Blazor 这种混合开发的模式,情况会稍微复杂一点,走的弯路这里就不再提及了。无论如何处理,我们首先还是需要了解一下 .NET MAUI 应用的生命周期。这里为了方便跨平台处理,我们可以选择跨平台的生命周期事件 Stopped:当窗口不再可见时,将引发此事件。此时我们就可以做一些关键数据存储了。

而对于敲击计数的功能,我们采用一个全局的静态类进行管理,方便在 Blazor 和 App 中访问。在 Data 目录下创建如下类 HitCounter.cs

public static class HitCounter
{
    private static long count;
    private static long todayCount;
    private static string today;

    static HitCounter()
    {
        count = Preferences.Default.Get("all_num", 0L);
        todayCount = 0;
        today = DateTime.Now.ToShortDateString();
        if (today == Preferences.Default.Get("today", ""))
        {
            todayCount = Preferences.Default.Get("today_num", 0L);
        }
    }

    /// <summary>
    /// 敲击后更新计数
    /// </summary>
    public static void Increment()
    {
        if (today != DateTime.Now.ToShortDateString())
        {
            today = DateTime.Now.ToShortDateString();
            todayCount = 0;
        }
        count++;
        todayCount++;
    }

    /// <summary>
    /// 保存数据到 Preferences
    /// </summary>
    public static void Save()
    {
        if (today != DateTime.Now.ToShortDateString())
        {
            today = DateTime.Now.ToShortDateString();
            todayCount = 0;
        }
        Preferences.Default.Set("today_num", todayCount);
        Preferences.Default.Set("today", today);
        Preferences.Default.Set("all_num", count);
    }

    /// <summary>
    /// 总计数
    /// </summary>
    public static long Count
    {
        get { return count; }
    }

    /// <summary>
    /// 当日计数
    /// </summary>
    public static long TodayCount
    {
        get { return todayCount; }
    }
}

要订阅 Window 生命周期事件,则需要在 App.xaml.cs 文件的 App 类中重写 CreateWindow 方法,并在其中添加订阅事件的实例:

protected override Window CreateWindow(IActivationState activationState)
{
    Window window = base.CreateWindow(activationState);

    window.Stopped += (s, e) =>
    {
        Data.HitCounter.Save();
    };

    return window;
}

Index.razor 则不需要重写 OnAfterRenderAsync ,直接赋值即可:

private long AllNum = Data.HitCounter.Count;
private long TodayNum = Data.HitCounter.TodayCount;

但是,此后敲击计数的更新并不是实时的在 Blazor 界面中显示了。在需要更新显示的时候,比如这里的动作是点开设置菜单显示在右上角,则只需要在打开菜单的事件中重新赋值:

void ShowMenu()
{
    ShowSetting = true;
    // 更新数据
    AllNum = Data.HitCounter.Count;
    TodayNum = Data.HitCounter.TodayCount;
}

计数显示

3.3 自动敲击

自动敲击,积攒功德也是电子木鱼的一个重要功能。在 Blazor 中,我们可以使用 System.Threading.TimerJavaScript Interop 来实现计时器。这里选择使用 System.Threading.Timer 来实现。

首先我们需要了解一下 Timer(TimerCallback callback, object state, int dueTime, int period); 的参数:

参数 说明
callback 委托将会在period时间间隔内重复执行
state 参数可以传入想在callback委托中处理的对象
dueTime 标识多久后callback开始执行
period 标识多久执行一次callback

Index.razor 我们定义并在 OnInitialized 时创建计时器,这里为了控制启动和停止,这里的 dueTimeperiod 设置为 Timeout.InfiniteTimeout.Infinite 是一个用于指定无限长等待时间的常数,这里就可以保证计时器不被触发 callback

private Timer _timer;//自动敲击计时器
private bool _isTimerRunning = false;//计时器启动开关

protected override void OnInitialized()
{
    _timer = new Timer(TimerCallback, null, Timeout.Infinite, Timeout.Infinite);
    base.OnInitialized();
}

之后我们只需通过下面的方法更改计时参数即可切换计时器的启停状态了:

private void TimerSwitch()
{
    if (_isTimerRunning)
    {
        _timer.Change(Timeout.Infinite, Timeout.Infinite);
        _isTimerRunning = false;
    }
    else
    {
        _timer.Change(0, 1000);
        _isTimerRunning = true;
    }
}

4. 最后

至此,一个简单的 .NET MAUI Blazor 的小应用已开发完毕,在 GitHub 上提供了预编译的 apk 和旁载的 windows_x64 应用, 感兴趣的同学可以前去尝试一下。

相关文章
|
25天前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
86 3
|
19天前
|
JSON C# 开发者
C#语言新特性深度剖析:提升你的.NET开发效率
【10月更文挑战第15天】C#语言凭借其强大的功能和易用性深受开发者喜爱。随着.NET平台的演进,C#不断引入新特性,如C# 7.0的模式匹配和C# 8.0的异步流,显著提升了开发效率和代码可维护性。本文将深入探讨这些新特性,助力开发者在.NET开发中更高效地利用它们。
28 1
|
25天前
|
开发框架 NoSQL MongoDB
C#/.NET/.NET Core开发实战教程集合
C#/.NET/.NET Core开发实战教程集合
|
25天前
|
C# Windows
一款基于.NET开发的简易高效的文件转换器
一款基于.NET开发的简易高效的文件转换器
|
25天前
|
开发框架 缓存 前端开发
WaterCloud:一套基于.NET 8.0 + LayUI的快速开发框架,完全开源免费!
WaterCloud:一套基于.NET 8.0 + LayUI的快速开发框架,完全开源免费!
|
2月前
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
38 7
|
2月前
|
存储 开发框架 前端开发
ASP.NET MVC 迅速集成 SignalR
ASP.NET MVC 迅速集成 SignalR
53 0
|
3月前
|
开发框架 前端开发 .NET
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
46 0