test: 测试 MVVM 模式与绑定

This commit is contained in:
2025-01-24 01:17:06 +08:00
parent f6118e29f8
commit 44de222ed7
16 changed files with 368 additions and 1 deletions

15
TestMvvm/App.axaml Normal file
View File

@@ -0,0 +1,15 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="TestMvvm.App"
xmlns:local="using:TestMvvm"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.DataTemplates>
<local:ViewLocator />
</Application.DataTemplates>
<Application.Styles>
<FluentTheme />
</Application.Styles>
</Application>

46
TestMvvm/App.axaml.cs Normal file
View File

@@ -0,0 +1,46 @@
using System.Linq;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Data.Core.Plugins;
using Avalonia.Markup.Xaml;
using JackCraft.I18N;
using TestMvvm.ViewModels;
using TestMvvm.Views;
namespace TestMvvm;
public class App : Application
{
public static I18NManager I18NManager { get; } = new("TestMvvm.Assets.Resources");
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
// Avoid duplicate validations from both Avalonia and the CommunityToolkit.
// More info: https://docs.avaloniaui.net/docs/guides/development-guides/data-validation#manage-validationplugins
DisableAvaloniaDataAnnotationValidation();
desktop.MainWindow = new MainWindow
{
DataContext = new MainWindowViewModel()
};
}
base.OnFrameworkInitializationCompleted();
}
private void DisableAvaloniaDataAnnotationValidation()
{
// Get an array of plugins to remove
var dataValidationPluginsToRemove =
BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();
// remove each entry found
foreach (var plugin in dataValidationPluginsToRemove) BindingPlugins.DataValidators.Remove(plugin);
}
}

54
TestMvvm/Assets/Resources.Designer.cs generated Normal file
View File

@@ -0,0 +1,54 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TestMvvm.Assets {
using System;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static System.Resources.ResourceManager resourceMan;
private static System.Globalization.CultureInfo resourceCulture;
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
internal static System.Resources.ResourceManager ResourceManager {
get {
if (object.Equals(null, resourceMan)) {
System.Resources.ResourceManager temp = new System.Resources.ResourceManager("TestMvvm.Assets.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
internal static System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
internal static string Test1 {
get {
return ResourceManager.GetString("Test1", resourceCulture);
}
}
}
}

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" id="root"
xmlns="">
<xsd:element name="root" msdata:IsDataSet="true">
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="Test1" xml:space="preserve">
<value>Test1: {0}</value>
</data>
</root>

View File

@@ -0,0 +1,21 @@
<root>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>1.3</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
</value>
</resheader>
<data name="Test1" xml:space="preserve">
<value>测试1: {0}</value>
</data>
</root>

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

26
TestMvvm/Program.cs Normal file
View File

@@ -0,0 +1,26 @@
using System;
using Avalonia;
namespace TestMvvm;
internal 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()
{
return AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
}
}

47
TestMvvm/TestMvvm.csproj Normal file
View File

@@ -0,0 +1,47 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>
<ItemGroup>
<Folder Include="Models\"/>
<AvaloniaResource Include="Assets\**"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.2.3"/>
<PackageReference Include="Avalonia.Desktop" Version="11.2.3"/>
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.3"/>
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.3"/>
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Include="Avalonia.Diagnostics" Version="11.2.3">
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.1"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\JackCraft.I18N\JackCraft.I18N.csproj"/>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Update="Assets\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Compile Update="Assets\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
</Project>

27
TestMvvm/ViewLocator.cs Normal file
View File

@@ -0,0 +1,27 @@
using System;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using TestMvvm.ViewModels;
namespace TestMvvm;
public class ViewLocator : IDataTemplate
{
public Control? Build(object? param)
{
if (param is null)
return null;
var name = param.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
var type = Type.GetType(name);
if (type != null) return (Control)Activator.CreateInstance(type)!;
return new TextBlock { Text = "Not Found: " + name };
}
public bool Match(object? data)
{
return data is ViewModelBase;
}
}

View File

@@ -0,0 +1,29 @@
using System.Globalization;
using System.IO;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace TestMvvm.ViewModels;
public partial class MainWindowViewModel : ViewModelBase
{
[ObservableProperty] public string? test = Path.GetRandomFileName();
[RelayCommand]
public void RandomText()
{
Test = Path.GetRandomFileName();
}
[RelayCommand]
public void ChangeToChinese()
{
App.I18NManager.Culture = new CultureInfo("zh-hans");
}
[RelayCommand]
public void ChangeToDefault()
{
App.I18NManager.Culture = CultureInfo.InvariantCulture;
}
}

View File

@@ -0,0 +1,7 @@
using CommunityToolkit.Mvvm.ComponentModel;
namespace TestMvvm.ViewModels;
public class ViewModelBase : ObservableObject
{
}

View File

@@ -0,0 +1,30 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:TestMvvm.ViewModels"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:i18N="clr-namespace:JackCraft.I18N;assembly=JackCraft.I18N"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="TestMvvm.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
Icon="/Assets/avalonia-logo.ico"
Title="TestMvvm">
<Design.DataContext>
<!-- This only sets the DataContext for the previewer in an IDE,
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
<vm:MainWindowViewModel />
</Design.DataContext>
<StackPanel>
<TextBlock Text="{Binding Test}" HorizontalAlignment="Center" VerticalAlignment="Center" />
<TextBlock Text="{i18N:I18N Test1, {Binding Test}}" HorizontalAlignment="Center" VerticalAlignment="Center" />
<Button Content="随机文本"
Command="{Binding RandomTextCommand}" />
<Button Content="切换中文"
Command="{Binding ChangeToChineseCommand}" />
<Button Content="切换默认"
Command="{Binding ChangeToDefaultCommand}" />
</StackPanel>
</Window>

View File

@@ -0,0 +1,11 @@
using Avalonia.Controls;
namespace TestMvvm.Views;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}

18
TestMvvm/app.manifest Normal file
View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embedded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="TestMvvm.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
</application>
</compatibility>
</assembly>