.Net-Avalonia学习笔记(七)-待办事项应用(MVVM实战)
这是一个简单的待办事项列表应用,使用了 Model-View-ViewModel (MVVM) 模式,您将会了解以下内容(官网话语;我是没了解到):
RaiseAndSetIfChanged
ReactiveCommand
IObservable<>
Observable.Merge()
与Select()
、Take()
和Subscribe()
方法的使用。
官方代码地址:https://github.com/AvaloniaUI/Avalonia.Samples
本文对官方代码进行了修改,修改后可作为一个单窗体的MVVM示例。首先安装NuGet包CommunityToolkit.Mvvm、Newtonsoft.Json
1、Model
namespace AvaloniaUI_MVVM_Simple.Models
{
/// <summary>
/// 待办事项应用 Model
/// </summary>
public class ToDoItem
{
/// <summary>
/// 是否勾选
/// </summary>
public bool IsChecked { get; set; }
/// <summary>
/// 事项内容
/// </summary>
public string Content { get; set; } = string.Empty;
}
}
2、View
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:AvaloniaUI_MVVM_Simple"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i="clr-namespace:Avalonia.Xaml.Interactivity;assembly=Avalonia.Xaml.Interactivity"
xmlns:iac="clr-namespace:Avalonia.Xaml.Interactions.Core;assembly=Avalonia.Xaml.Interactions"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="AvaloniaUI_MVVM_Simple.Views.ToDoItemsWindow"
x:DataType="vm:ToDoItemsViewModel"
Title="待办事项应用">
<!-- Loaded ="{Binding LoadedCommand}" Closed ="{Binding SaveCommand}" Closed="Window_Closed"-->
<i:Interaction.Behaviors>
<iac:EventTriggerBehavior EventName="Loaded">
<iac:InvokeCommandAction Command="{Binding LoadedCommand}"/>
</iac:EventTriggerBehavior>
<iac:EventTriggerBehavior EventName="Closing">
<iac:InvokeCommandAction Command="{Binding ClosingCommand}"/>
</iac:EventTriggerBehavior>
<iac:EventTriggerBehavior EventName="Closed">
<iac:InvokeCommandAction Command="{Binding ClosedCommand}"/>
</iac:EventTriggerBehavior>
</i:Interaction.Behaviors>
<Design.DataContext>
<vm:ToDoItemsViewModel />
</Design.DataContext>
<Grid RowDefinitions="Auto, *, Auto" x:Name="Root">
<TextBlock Text="待办事项列表" Classes="h1" />
<!-- 待办事项列表 -滑动框 -->
<ScrollViewer Grid.Row="1">
<!-- 待办事项列表 -->
<ItemsControl ItemsSource="{Binding ToDoItems}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="vm:ToDoItemViewModel">
<Grid ColumnDefinitions="*, Auto">
<!-- 一个选择框 -->
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Content}" />
<!-- 一个按钮 -->
<Button Grid.Column="1" Command="{Binding #Root.((vm:ToDoItemsViewModel)DataContext).RemoveItemCommand}" CommandParameter="{Binding .}">
<PathIcon Data="{DynamicResource DeleteIconData}" Height="15" Foreground="Red" />
</Button>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<!-- 用于添加新Item -->
<TextBox Grid.Row="2" Text="{Binding NewItemContent}" Watermark="添加新项">
<!-- 再内部添加一个按钮 -->
<TextBox.InnerRightContent>
<Button Command="{Binding AddItemCommand}">
<PathIcon Data="{DynamicResource AcceptIconData}" Foreground="Green" />
</Button>
</TextBox.InnerRightContent>
<!-- 绑定回车键 -->
<TextBox.KeyBindings>
<KeyBinding Gesture="Enter" Command="{Binding AddItemCommand}" />
</TextBox.KeyBindings>
</TextBox>
<!-- <Button Content="Click me">
<i:Interaction.Behaviors>
<iac:EventTriggerBehavior EventName="Click">
<iac:InvokeCommandAction Command="{Binding MyCommand}"/>
</iac:EventTriggerBehavior>
</i:Interaction.Behaviors>
</Button> -->
</Grid>
</Window>
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Markup.Xaml;
using System;
using System.Diagnostics;
namespace AvaloniaUI_MVVM_Simple.Views;
public partial class ToDoItemsWindow : Window
{
public ToDoItemsWindow()
{
InitializeComponent();
DataContext = new ToDoItemsViewModel();
}
//private void Window_Closed(object? sender, System.EventArgs e)
//{
// Debug.WriteLine("Closed");
//}
}
3、ViewModel
using AvaloniaUI_MVVM_Simple.Models;
using AvaloniaUI_MVVM_Simple.ViewModels;
using CommunityToolkit.Mvvm.ComponentModel;
using System;
namespace AvaloniaUI_MVVM_Simple
{
/// <summary>
/// 待办事项应用 ViewModel
/// </summary>
public partial class ToDoItemViewModel : ViewModelBase
{
#region 变量
/// <summary>
/// 是否勾选
/// </summary>
[ObservableProperty]
private bool _isChecked;
/// <summary>
/// 事项内容
/// </summary>
[ObservableProperty]
private string _content = string.Empty;
#endregion 变量
/// <summary>
/// 构造函数
/// </summary>
/// <param name="item"></param>
public ToDoItemViewModel()
{
}
/// <summary>
/// 构造函数
/// </summary>
/// <param name="item"></param>
public ToDoItemViewModel(ToDoItem item)
{
IsChecked = item.IsChecked;
Content = item.Content;
}
/// <summary>
/// 转ToDoItem
/// </summary>
/// <returns>The ToDoItem</returns>
public ToDoItem GetToDoItem()
=> new ToDoItem()
{
IsChecked = this.IsChecked,
Content = this.Content
};
}
}
using Avalonia.Controls;
using AvaloniaUI_MVVM_Simple.Services;
using AvaloniaUI_MVVM_Simple.ViewModels;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
namespace AvaloniaUI_MVVM_Simple
{
/// <summary>
/// 待办事项列表 ViewModel
/// </summary>
public partial class ToDoItemsViewModel : ViewModelBase
{
#region 变量
/// <summary>
///待办事项列表
/// </summary>
public ObservableCollection<ToDoItemViewModel> ToDoItems { get; } = new ObservableCollection<ToDoItemViewModel>();
/// <summary>
/// 新Item的内容
/// </summary>
[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(AddItemCommand))] // 绑定事件
private string _newItemContent = string.Empty;
#endregion 变量
/// <summary>
/// 构造函数
/// </summary>
/// <param name="item"></param>
public ToDoItemsViewModel()
{
if (Design.IsDesignMode) // 设计预览环境下
{
ToDoItems = new ObservableCollection<ToDoItemViewModel>(
new[]
{
new ToDoItemViewModel() { Content = "Hello" },
new ToDoItemViewModel() { Content = "Avalonia", IsChecked = true}
});
}
}
#region 操作
/// <summary>
/// 加载数据
/// </summary>
//private void Window_Loaded(object sender, RoutedEventArgs e)
[RelayCommand]
//private void Loaded(RoutedEventArgs e)
private void Loaded()
{
Debug.WriteLine("Loaded");
if (!Design.IsDesignMode)
{
// 数据列表
var itemsLoaded = ToDoListFileService.LoadFromFile();
if (itemsLoaded is not null)
{
ToDoItems.Clear();
foreach (var item in itemsLoaded)
{
ToDoItems.Add(new ToDoItemViewModel(item));
}
}
}
}
/// <summary>
/// 保存数据
/// </summary>
[RelayCommand]
private void Closing()
{
Debug.WriteLine("Closing");
var itemsToSave = ToDoItems.Select(item => item.GetToDoItem());
ToDoListFileService.SaveToFile(itemsToSave);
}
/// <summary>
/// 保存数据
/// 因为ToDoItemsViewModel销毁在窗口前所以Closed不可用
/// </summary>
[RelayCommand]
private void Closed()
{
Debug.WriteLine("Closed");
// var itemsToSave = ToDoItems.Select(item => item.GetToDoItem());
// ToDoListFileService.SaveToFile(itemsToSave);
}
/// <summary>
/// 添加 项
/// </summary>
[RelayCommand(CanExecute = nameof(CanAddItem))]
private void AddItem()
{
ToDoItems.Add(new ToDoItemViewModel() { Content = NewItemContent });
// 清空NewItemContent
NewItemContent = string.Empty;
}
private bool CanAddItem() => !string.IsNullOrEmpty(NewItemContent);
/// <summary>
/// 删除 项
/// </summary>
/// <param name="item"></param>
[RelayCommand]
private void RemoveItem(ToDoItemViewModel item)
{
ToDoItems.Remove(item);
}
/// <summary>
/// 删除 项
/// </summary>
/// <param name="item"></param>
[RelayCommand]
private void My()
{
Debug.WriteLine("Test");
}
#endregion 操作
}
}
4、ViewModelBase.cs
using CommunityToolkit.Mvvm.ComponentModel;
namespace AvaloniaUI_MVVM_Simple.ViewModels
{
public class ViewModelBase : ObservableObject
{
}
}
本文来自博客园,作者:꧁执笔小白꧂,转载请注明原文链接:https://www.cnblogs.com/qq2806933146xiaobai/p/18320879