Avalonia+ReactiveUI+SourceGenerators设计简易待办事项(ToDoItem)程序

1、必要的包引用

    <PackageReference Include="Avalonia" Version="11.3.6" />
    <PackageReference Include="Avalonia.ReactiveUI" Version="11.3.6" />
    <PackageReference Include="ReactiveUI.SourceGenerators" Version="2.4.1">

2、ViewModel (使用 ReactiveUI Source Generators)

using Avalonia.Controls;
using AvaRea.Models;
using ReactiveUI;
using ReactiveUI.SourceGenerators;
using System;
using System.Collections.ObjectModel;

namespace AvaRea.ViewModels
{
    public partial  class TestTodoViewModel: ReactiveObject
    {
        public TestTodoViewModel()
        {
            // 设计模式下显示待办事项内容. 
            if (Design.IsDesignMode)
            {
                ToDoItems = new ObservableCollection<ToDoItem>(new[]
                {
                new ToDoItem() { Content = "学习RT-Thread嵌入式操作系统" },
                new ToDoItem() { Content = "学习Avalonia及响应式编程", IsChecked = true}
            });
            }
            // 响应式编程模式,自动判断初始化待办事项列表是否为空且是使能新增待办实现命令.
            _canAddItem = this.WhenAnyValue(x => x.NewItemContent,(x) => !string.IsNullOrWhiteSpace(x));
        }

        /// <summary>
        /// 界面中显示的待办事项列表
        /// </summary>
        public ObservableCollection<ToDoItem> ToDoItems { get; } = new ObservableCollection<ToDoItem>();

        /// <summary>
        /// 新增待办事项的命令,当输入内容不为空时,命令可用
        /// </summary>
        [ReactiveCommand(CanExecute = nameof(_canAddItem))]
        private void AddItem()
        {
            // 在待办事项列表中添加一个新的待办事项
            ToDoItems.Add(new ToDoItem() { Content = NewItemContent });

            // 复位输入框内容NewItemContent
            NewItemContent = null;
        }

        /// <summary>
        /// 输入框内容,当输入内容不为空时,命令可用
        /// </summary>
        [Reactive]
        private string? _newItemContent;

        /// <summary>
        /// 响应式编程模式检查输入框内容,当输入内容不为空时,新增待办事项命令可用
        /// </summary>
        private IObservable<bool> _canAddItem;

        /// <summary>
        /// 移除待办事项内容
        /// </summary>
        /// <param name="item"></param>
        [ReactiveCommand]
        private void RemoveItem(ToDoItem item)
        {
            // 在待办事项列表中移除指定的待办事项
            ToDoItems.Remove(item);
        }

}
}

2、Model


using ReactiveUI;
using ReactiveUI.SourceGenerators;

namespace AvaRea.Models
{
    /// <summary>
    /// 待办事项模型类 
    /// </summary>
    public partial class ToDoItem : ReactiveObject
    {
        /// <summary>
        /// 获取/设置待办事项是否已完成
        /// </summary>
        [Reactive] private bool _isChecked;

        /// <summary>
        /// 获取/设置待办事项内容
        /// </summary>
        [Reactive] string? _content;
    }
}

3、View

<Window
    x:Class="AvaRea.TestTodoView"
    xmlns="https://github.com/avaloniaui"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="using:AvaRea.ViewModels"
    Title="待办事项"
    d:DesignHeight="450"
    d:DesignWidth="800"
    x:DataType="vm:TestTodoViewModel"
    mc:Ignorable="d">
    <Design.DataContext>
        <vm:TestTodoViewModel />
    </Design.DataContext>
    <Grid x:Name="Root" RowDefinitions="Auto, *, Auto">
        <TextBlock Classes="h1" Text="我的待办事项" />
        <ScrollViewer Grid.Row="1">
            <!--  ItemsControl显示所有待办事项  -->
            <ItemsControl ItemsSource="{Binding ToDoItems}">
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Grid ColumnDefinitions="*, Auto">
                            <CheckBox Content="{Binding Content}" IsChecked="{Binding IsChecked}" />
                            <Button
                                Grid.Column="1"
                                Command="{Binding #Root.((vm:TestTodoViewModel)DataContext).RemoveItemCommand}"
                                CommandParameter="{Binding .}"
                                Content="删除"
                                Foreground="Red" />
                        </Grid>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
        <TextBox
            Grid.Row="2"
            Text="{Binding NewItemContent}"
            Watermark="新增待办事项">
            <TextBox.InnerRightContent>
                <Button Command="{Binding AddItemCommand}">
                    <TextBlock Foreground="Green" Text="新增" />
                </Button>
            </TextBox.InnerRightContent>
            <TextBox.KeyBindings>
                <KeyBinding Command="{Binding AddItemCommand}" Gesture="Enter" />
            </TextBox.KeyBindings>
        </TextBox>
    </Grid>
</Window>

4、App.axaml

<Application xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Class="AvaRea.App"
             RequestedThemeVariant="Default">
             <!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
    <Application.Styles>
	       <FluentTheme />
    </Application.Styles>
</Application>

5、App.axaml.cs

using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using AvaRea.ViewModels;

namespace AvaRea;

public partial class App : Application
{
    public override void Initialize()
    {
        AvaloniaXamlLoader.Load(this);
    }

    public override void OnFrameworkInitializationCompleted()
    {
        if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
        {
            desktop.MainWindow = new TestTodoView
            {
                DataContext = new TestTodoViewModel()
            };
        }
        else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform)
        {
            singleViewPlatform.MainView = new TestTodoView
            {
                DataContext = new TestTodoViewModel()
            };
        }

        base.OnFrameworkInitializationCompleted();
    }
}

6、Program.cs

using System;

using Avalonia;
using Avalonia.ReactiveUI;

namespace AvaRea.Desktop;

class Program
{
    // Initialization code. Don't use any Avalonia, third-party APIs or any
    // SynchronizationContext-reliant code before AppMain is called: things aren't initialized
    // yet and stuff might break.
    [STAThread]
    public static void Main(string[] args) => BuildAvaloniaApp()
        .StartWithClassicDesktopLifetime(args);

    // Avalonia configuration, don't remove; also used by visual designer.
    public static AppBuilder BuildAvaloniaApp()
        => AppBuilder.Configure<App>()
            .UsePlatformDetect()
            .WithInterFont()
            .LogToTrace()
            .UseReactiveUI();
}

7、程序运行界面

在这里插入图片描述

8、主要特点

使用 _canAddItem属性并利用ReactiveUI响应式编程特点和Sourcegenerators简化代码的功能控制 UI 状态和命令可用性,无需在axaml代码中进行使能绑定。

总结

Avalonia 给你跨平台的舞台,ReactiveUI 给你响应式的灵魂,Source Generators 给你自动生成代码;三者合体 = 用最少的代码,写出最快、最稳、最易维护的跨平台 .NET UI。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值