1. 创建文件夹目录
spartajet-template
|--working
|--content
|--test
2. 创建WPF项目
终端打开content
目录,运行cli
指令
dotnet new wpf -n Spartajet.WPF
输出如图所示
当前目录如图所示
3. 修改项目配置
3.1 添加Nuget以来
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.0" />
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.49-beta">
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="NLog" Version="5.2.8" />
<PackageReference Include="NLog.Extensions.Logging" Version="5.3.8" />
<PackageReference Include="SqlSugarCore" Version="5.1.4.130" />
<PackageReference Include="WPF-UI" Version="3.0.0-preview.13" />
3.2 添加icon
<ApplicationIcon>AppIcon.ico</ApplicationIcon>
3.3 添加多语言资源文件
- 添加资源文件
<ItemGroup>
<Resource Include="Assets\Language\Resources.de-DE.resx" />
<Resource Include="Assets\Language\Resources.resx">
<Generator>PublicResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</Resource>
<Resource Include="Assets\Language\Resources.zh-Hans.resx" />
<Resource Include="Assets\Language\Resources.zh-Hant.resx" />
</ItemGroup>
设置代码生成
<ItemGroup>
<Compile Update="Assets\Language\Resources.Designer.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
</ItemGroup>
- 添加Color资源文件
- 添加Templates文件
- 创建ViewModel文件夹
- 创建MainWindowViewModel类
4. 修改App.xaml.cs
文件
- 代码配置Nlog
private static void NlogConfig()
{
LoggingConfiguration config = new();
// Targets where to log to: File and Console
FileTarget logFile = new("logFile")
{
FileName = Path.Combine(LogFolder, "Debug.log"),
ArchiveEvery = FileArchivePeriod.Day,
ArchiveNumbering = ArchiveNumberingMode.Rolling,
ArchiveFileName = Path.Combine(LogFolder, "Debug.{#}.log"),
ArchiveDateFormat = "yyyyMMdd",
MaxArchiveFiles = 7,
AutoFlush = true
};
FileTarget errorFile = new("errorFile")
{
FileName = Path.Combine(LogFolder, "Error.log"),
ArchiveEvery = FileArchivePeriod.Day,
ArchiveNumbering = ArchiveNumberingMode.Rolling,
ArchiveFileName = Path.Combine(LogFolder, "Error.{#}.log"),
ArchiveDateFormat = "yyyyMMdd",
MaxArchiveFiles = 7,
AutoFlush = true
};
ConsoleTarget logConsole = new("logConsole");
// Rules for mapping loggers to targets
config.AddRule(NLog.LogLevel.Info, NLog.LogLevel.Fatal, logConsole);
config.AddRule(NLog.LogLevel.Debug, NLog.LogLevel.Info, logFile);
config.AddRule(NLog.LogLevel.Warn, NLog.LogLevel.Fatal, errorFile);
// Apply config
LogManager.Configuration = config;
}
- 设置Culture
private static void CultureSetting()
{
Thread.CurrentThread.CurrentCulture = new("en-US");
Thread.CurrentThread.CurrentUICulture = new("en-US");
}
- 配置Host
private static readonly IHost Host =
Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder()
.ConfigureAppConfiguration(c => { c.SetBasePath(AppContext.BaseDirectory); })
.ConfigureServices(
(host, services) =>
{
services.AddHostedService<DatabaseService>();
services.AddTransient<MainWindow>();
services.AddSingleton<MainWindowViewModel>();
services.AddSingleton<ISqlSugarClient>(s =>
{
SqlSugarScope sqlSugar =
new(new ConnectionConfig()
{
DbType = SqlSugar.DbType.Sqlite,
ConnectionString = $"DataSource={DataBasePath}",
IsAutoCloseConnection = true,
InitKeyType = InitKeyType.Attribute,
MoreSettings = new()
{
SqliteCodeFirstEnableDefaultValue = true //启用默认值
}
},
db => { db.Aop.OnLogExecuting = (sql, pars) => { }; });
return sqlSugar;
});
services.AddLogging(loggingBuilder =>
{
loggingBuilder.ClearProviders();
loggingBuilder.SetMinimumLevel(LogLevel.Trace);
loggingBuilder.AddNLog();
});
services.AddLocalization(option =>
{
option.ResourcesPath = "Assets/Language";
});
}
)
.Build();
- 删除
StartupUri="MainWindow.xaml"
- 重写
OnExit
和OnStartup
函数
private async void OnExit(object sender, ExitEventArgs e)
{
await Host.StopAsync();
Host.Dispose();
}
private async void OnStartup(object sender, StartupEventArgs e)
{
CultureSetting();
InitialFolders();
NlogConfig();
await Host.StartAsync();
MainWindow window = Host.Services.GetRequiredService<MainWindow>();
window.ShowDialog();
}
5. 创建模板配置
在项目文件夹下新建.template.config
文件夹,在此文件夹中创建template.json
文件,内容如下
{
"$schema": "http://json.schemastore.org/template",
"author": "Dr. Xiaozhong Guo",
"classifications": [ "Common", "WPF" ],
"identity": "Spartajet.WPFTemplate",
"name": "Spartajet WPF Template",
"shortName": "spartajet-wpf",
"sourceName":"Spartajet.WPF",
"tags": {
"language": "C#",
"type": "project"
}
}
安装模板
dotnet new install .\
6. 测试模板
略
7. 打包模板
- 安装templatepack模板
dotnet new install Microsoft.TemplateEngine.Authoring.Templates
- 创建模板包
dotnet new templatepack -n "Spartajet.WPF.Templates"
输入
3. 编辑Spartajet.WPF.Templates
文件
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<!-- The package metadata. Fill in the properties marked as TODO below -->
<!-- Follow the instructions on https://learn.microsoft.com/en-us/nuget/create-packages/package-authoring-best-practices -->
<PackageId>Spartajet.WPF.Templates</PackageId>
<PackageVersion>1.0</PackageVersion>
<Title>Dr.Spartajet WPF Templates</Title>
<Authors>Dr. Xiaozhong Guo</Authors>
<Description>Dr.Spartajet WPF Templates</Description>
<PackageTags>WPF</PackageTags>
<PackageProjectUrl>https://github.com/spartajet/spartajet-template</PackageProjectUrl>
<!-- Keep package type as 'Template' to show the package as a template package on nuget.org and make your template available in dotnet new search.-->
<PackageType>Template</PackageType>
<TargetFramework>net8.0</TargetFramework>
<IncludeContentInPack>true</IncludeContentInPack>
<IncludeBuildOutput>false</IncludeBuildOutput>
<ContentTargetFolders>content</ContentTargetFolders>
<NoWarn>$(NoWarn);NU5128</NoWarn>
<NoDefaultExcludes>true</NoDefaultExcludes>
<PackageReadmeFile>README.md</PackageReadmeFile>
</PropertyGroup>
<PropertyGroup>
<LocalizeTemplates>false</LocalizeTemplates>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.TemplateEngine.Tasks" Version="*" PrivateAssets="all" IsImplicitlyDefined="true"/>
</ItemGroup>
<ItemGroup>
<Content Include="content\**\*" Exclude="content\**\bin\**;content\**\obj\**" />
<Compile Remove="**\*" />
</ItemGroup>
<ItemGroup>
<None Include="README.md" Pack="true" PackagePath="" />
</ItemGroup>
</Project>
- 打包
dotnet pack