怪奇物语

怪奇物语

首页 新随笔 联系 管理

CommunityToolkit.Mvvm的使用 todolist 官网demo 改写 不适用注解 更好理解学习

SimpleToDoList\Models\ToDoItem.cs


using CommunityToolkit.Mvvm.ComponentModel;

namespace SimpleToDoList.Models;

public class ToDoItem
{
    public bool IsChecked { get; set; }
    public string? Content { get; set; }
}

SimpleToDoList\Services\ToDoListFileService.cs


using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using SimpleToDoList.Models;

namespace SimpleToDoList.Services;

/// <summary>
/// This class provides the needed functions to save and restore a ToDoList. This step is fully optional for this tutorial
/// </summary>
public static class ToDoListFileService
{
    // This is a hard coded path to the file. It may not be available on every platform. In your real world App you may
    // want to make this configurable
    private static string _jsonFileName = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Avalonia.SimpleToDoList", "MyToDoList.txt");

    /// <summary>
    /// Stores the given items into a file on disc
    /// </summary>
    /// <param name="itemsToSave">The items to save</param>
    public static async Task SaveToFileAsync(IEnumerable<ToDoItem> itemsToSave)
    {
        // Ensure all directories exists
        Directory.CreateDirectory(Path.GetDirectoryName(_jsonFileName)!);

        // We use a FileStream to write all items to disc
        using (var fs = File.Create(_jsonFileName))
        {
            await JsonSerializer.SerializeAsync(fs, itemsToSave);
        }
    }

    /// <summary>
    /// Loads the file from disc and returns the items stored inside
    /// </summary>
    /// <returns>An IEnumerable of items loaded or null in case the file was not found</returns>
    public static async Task<IEnumerable<ToDoItem>?> LoadFromFileAsync()
    {
        try
        {
            // We try to read the saved file and return the ToDoItemsList if successful
            using (var fs = File.OpenRead(_jsonFileName))
            {
                return await JsonSerializer.DeserializeAsync<IEnumerable<ToDoItem>>(fs);
            }
        }
        catch (Exception e) when (e is FileNotFoundException || e is DirectoryNotFoundException)
        {
            // In case the file was not found, we simply return null
            return null;
        }
    }
}

SimpleToDoList\ViewModels\MainViewModel.cs


using System.Collections.ObjectModel;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using SimpleToDoList.Models;
using SimpleToDoList.Services;

namespace SimpleToDoList.ViewModels;

public partial class MainViewModel : ViewModelBase
{
    private string? _newItemContent;
    public string? NewItemContent
    {
        get => _newItemContent;
        set
        {
            if (SetProperty(ref _newItemContent, value))
            {
                AddItemCommand.NotifyCanExecuteChanged();
            }
        }
    }
    public ObservableCollection<ToDoItemViewModel> ToDoItems { get; } = new ObservableCollection<ToDoItemViewModel>();
    public IRelayCommand AddItemCommand { get; }
    public IRelayCommand<ToDoItemViewModel> RemoveItemCommand { get; }
    public MainViewModel()
    {
        AddItemCommand = new RelayCommand(AddItem, CanAddItem);
        RemoveItemCommand = new RelayCommand<ToDoItemViewModel>(RemoveItem);

        if (Design.IsDesignMode)
        {
            ToDoItems = new ObservableCollection<ToDoItemViewModel>(
                new[]
                {
                    new ToDoItemViewModel() { Content = "Hello" },
                    new ToDoItemViewModel() { Content = "Avalonia", IsChecked = true }
                }
            );
        }
    }

    private void AddItem()
    {
        ToDoItems.Add(new ToDoItemViewModel() { Content = NewItemContent });
        NewItemContent = null;
    }

    private bool CanAddItem() => !string.IsNullOrWhiteSpace(NewItemContent);

    private void RemoveItem(ToDoItemViewModel? item)
    {
        if (item == null)
            return;
        ToDoItems.Remove(item);
    }
}

SimpleToDoList\ViewModels\ToDoItemViewModel.cs


using CommunityToolkit.Mvvm.ComponentModel;
using SimpleToDoList.Models;

namespace SimpleToDoList.ViewModels;

public partial class ToDoItemViewModel : ViewModelBase
{
    private bool _isChecked;
    private string? _content;

    public bool IsChecked
    {
        get => _isChecked;
        set => SetProperty(ref _isChecked, value);
    }

    public string? Content
    {
        get => _content;
        set => SetProperty(ref _content, value);
    }

    public ToDoItemViewModel() { }

    public ToDoItemViewModel(ToDoItem item)
    {
        IsChecked = item.IsChecked;
        Content = item.Content;
    }

    public ToDoItem GetToDoItem()
    {
        return new ToDoItem() { IsChecked = this.IsChecked, Content = this.Content };
    }
}

SimpleToDoList\ViewModels\ViewModelBase.cs


using CommunityToolkit.Mvvm.ComponentModel;

namespace SimpleToDoList.ViewModels;

public class ViewModelBase : ObservableObject { }


SimpleToDoList\Views\MainWindow.axaml.cs


using System.Linq;
using Avalonia.Controls;
using SimpleToDoList.Services;
using SimpleToDoList.ViewModels;

namespace SimpleToDoList.Views;

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

SimpleToDoList\.csharpierrc.json


{
  "printWidth": 200,
  "useTabs": false,
  "tabWidth": 4,
  "endOfLine": "auto"
}

SimpleToDoList\App.axaml.cs


using System.Linq;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using SimpleToDoList.Services;
using SimpleToDoList.ViewModels;
using SimpleToDoList.Views;

namespace SimpleToDoList;

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

    // This is a reference to our MainViewModel which we use to save the list on shutdown. You can also use Dependency Injection
    // in your App.
    private readonly MainViewModel _mainViewModel = new MainViewModel();

    public override async void OnFrameworkInitializationCompleted()
    {
        if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
        {
            desktop.MainWindow = new MainWindow
            {
                DataContext = _mainViewModel // Remember to change this line to use our private reference to the MainViewModel
            };

            // Listen to the ShutdownRequested-event
            desktop.ShutdownRequested += DesktopOnShutdownRequested;
        }
        base.OnFrameworkInitializationCompleted();

        // Init the MainViewModel
        await InitMainViewModelAsync();
    }

    // We want to save our ToDoList before we actually shutdown the App. As File I/O is async, we need to wait until file is closed
    // before we can actually close this window

    private bool _canClose; // This flag is used to check if window is allowed to close

    private async void DesktopOnShutdownRequested(object? sender, ShutdownRequestedEventArgs e)
    {
        e.Cancel = !_canClose; // cancel closing event first time

        if (!_canClose)
        {
            // To save the items, we map them to the ToDoItem-Model which is better suited for I/O operations
            var itemsToSave = _mainViewModel.ToDoItems.Select(item => item.GetToDoItem());

            await ToDoListFileService.SaveToFileAsync(itemsToSave);

            // Set _canClose to true and Close this Window again
            _canClose = true;
            if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
            {
                desktop.Shutdown();
            }
        }
    }

    // Optional: Load data from disc
    private async Task InitMainViewModelAsync()
    {
        // get the items to load
        var itemsLoaded = await ToDoListFileService.LoadFromFileAsync();

        if (itemsLoaded is not null)
        {
            foreach (var item in itemsLoaded)
            {
                _mainViewModel.ToDoItems.Add(new ToDoItemViewModel(item));
            }
        }
    }
}

SimpleToDoList\Program.cs


using System;
using Avalonia;

namespace SimpleToDoList;

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

SimpleToDoList\SimpleToDoList.csproj


<Project Sdk="Microsoft.NET.Sdk">
    <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>net6.0</TargetFramework>
        <Nullable>enable</Nullable>
        <BuiltInComInteropSupport>true</BuiltInComInteropSupport>
        <ApplicationManifest>app.manifest</ApplicationManifest>
        <AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
    </PropertyGroup>

    <ItemGroup>
        <AvaloniaResource Include="Assets\**"/>
    </ItemGroup>


    <ItemGroup>
        <PackageReference Include="Avalonia" Version="11.0.5"/>
        <PackageReference Include="Avalonia.Desktop" Version="11.0.5"/>
        <PackageReference Include="Avalonia.Themes.Fluent" Version="11.0.5"/>
        <PackageReference Include="Avalonia.Fonts.Inter" Version="11.0.5"/>
        <!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
        <PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.5"/>
        <PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.0" />
    </ItemGroup>
</Project>

SimpleToDoList\SimpleToDoList.sln


Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleToDoList", "SimpleToDoList.csproj", "{2B1D213D-DDB3-0066-BA10-EE293F7C9643}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Any CPU = Debug|Any CPU
		Release|Any CPU = Release|Any CPU
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{2B1D213D-DDB3-0066-BA10-EE293F7C9643}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
		{2B1D213D-DDB3-0066-BA10-EE293F7C9643}.Debug|Any CPU.Build.0 = Debug|Any CPU
		{2B1D213D-DDB3-0066-BA10-EE293F7C9643}.Release|Any CPU.ActiveCfg = Release|Any CPU
		{2B1D213D-DDB3-0066-BA10-EE293F7C9643}.Release|Any CPU.Build.0 = Release|Any CPU
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
	GlobalSection(ExtensibilityGlobals) = postSolution
		SolutionGuid = {EB53C1D9-A334-4FD2-9BF0-DDC019E52625}
	EndGlobalSection
EndGlobal

posted on 2025-02-18 08:00  超级无敌美少男战士  阅读(116)  评论(0)    收藏  举报