左丘纨 发表于 2025-9-21 21:29:50

WPF治具软件模板分享

目录

[*]WPF治具软件模板分享

[*]程序功能介绍
[*]功能实现

[*]导航功能
[*]程序配置
[*]日志功能

[*]界面介绍


WPF治具软件模板分享

运行环境:VS2022   .NET 8.0
完整项目:Gitee仓库
项目重命名方法参考:网页
概要:针对治具单机软件制作了一个设计模板,此项目可对一些治具的PC简易软件项目提供一个软件模板,可以通过修改项目名快速开发,本项目使用了CommunityToolkit.Mvvm来搭建MVVM框架,使用了Microsoft.Extensions.DependencyInjection来实现DI依赖注入实现IOC,并使用了WPFUI作为UI框架 这个项目可以通过重命名修改成自己所需的软件项目,实现减少重复创建框架的目的 此项目还有很多不足,望大家多多谅解!
程序功能介绍

此程序适用于治具的PC简易软件的快速开发,软件各个功能实现如下:
MVVM框架:CommunityToolkit.Mvvm库
DI依赖注入:Microsoft.Extensions.DependencyInjection
UI框架:WPFUI库
程序日志:NLog库
程序配置:System.Text.Json库
多语言支持:resx资源文件+WPFLocalizeExtension库
软件文件架构如下图所示

功能实现

导航功能


[*]App.xaml.cs
var container = new ServiceCollection();

//...

//注册导航服务
container.AddSingleton<Common.Services.NavigationService>();

//...

Services = container.BuildServiceProvider();

[*]MainWindow.xaml
<Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="50"/>
      <RowDefinition/>
    </Grid.RowDefinitions>

    <Grid>
      <ui:TitleBar Title="JIG_SoftTemplate_V1.0.0" Background="#e5e5e5">
            <ui:TitleBar.Icon>
                <ui:ImageIcon Source="/Resources/Image/Company_logo.png"/>
            </ui:TitleBar.Icon>
      </ui:TitleBar>
    </Grid>

    <Grid Grid.Row="1" x:Name="ShowGrid">
      <Frame x:Name="rootFrame"/>
      <ui:SnackbarPresenter x:Name="rootSnackbarPresenter" Margin="0,0,0,-15"/>
      <ContentPresenter x:Name="rootContentDialog"/>
    </Grid>
</Grid>

[*]MainWindow.xaml.cs
public partial class MainWindow
{
    public MainWindow(MainWindowViewModel viewModel, Common.Services.NavigationService navigationService)
    {
      InitializeComponent();

      DataContext = viewModel;

      navigationService.SetMainFrame(rootFrame);

      App.Current.Services.GetRequiredService<ISnackbarService>().SetSnackbarPresenter(rootSnackbarPresenter);
      App.Current.Services.GetRequiredService<IContentDialogService>().SetDialogHost(rootContentDialog);


    }
}

[*]NavigationService.cs
public class NavigationService
{
    private Frame? mainFrame;

    public void SetMainFrame(Frame frame) => mainFrame = frame;

    private Type? FindView<VM>()
    {
      return Assembly
            .GetAssembly(typeof(VM))
            ?.GetTypes()
            .FirstOrDefault(t => t.Name == typeof(VM).Name.Replace("ViewModel", ""));
    }

    public void Navigate<VM>()
      where VM : ViewModelBase
    {
      Navigate<VM>(null);
    }

    public void Navigate<VM>(Dictionary<string, object?>? extraData)
      where VM : ViewModelBase
    {
      var viewType = FindView<VM>();
      if (viewType is null)
            return;

      var page = App.Current.Services.GetService(viewType) as Page;
      mainFrame?.Navigate(page, extraData);
    }
}在MainWindow.xaml里放Frame控件,在MainWindow.xaml.cs里,调用NavigationService的SetMainFrame方法设定了Frame组件实例,然后在VM中调用Navigate方法即可跳转页面,示例:navigationService.Navigate();
需注意,View和ViewModel需要名称对的上,如NavigationService.cs中所示,比如HomePage.xaml的ViewModel就是HomePageViewModel,名称错误的话,会在FindView方法中报错
程序配置


[*]App.xaml.cs
var container = new ServiceCollection();

//...

//注册Json配置文件服务
container.AddSingleton<Common.Services.JsonConfigService>();

//...

Services = container.BuildServiceProvider();

[*]AppConfigModel.cs
public class AppConfigModel
{
    public CommonConfig? Common {get; set; }

    public JIGCommConfig? JIGComm { get; set; }
}

public class CommonConfig
{
    public string? DataStoragePath { get; set; }
    public string? SelectedLang { get; set; }
}

public class JIGCommConfig
{

}

[*]JsonConfigService.cs
public class JsonConfigService
{
    private const string ConfigFileName = "AppSettings.json";

    private readonly LoggerService loggerService;

    public JsonConfigService(LoggerService loggerService)
    {
      this.loggerService = loggerService;
    }

    public async Task<T> LoadConfigAsync<T>(T defaultValue = default) where T : new()
    {
      try
      {
            var filePath = GetConfigFilePath();
            if (!File.Exists(filePath))
            {
                loggerService.Info("配置文件不存在,返回默认值");
                await SaveConfigAsync(defaultValue ?? new T());
                return defaultValue ?? new T();
            }

            await using var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read);
            return await JsonSerializer.DeserializeAsync<T>(fs) ?? new T();
      }
      catch (Exception ex)
      {
            loggerService.Error("加载配置文件失败", ex);
            return defaultValue ?? new T();
      }
    }

    public async Task SaveConfigAsync<T>(T config)
    {
      try
      {
            var filePath = GetConfigFilePath();
            var dirPath = Path.GetDirectoryName(filePath);

            if (!Directory.Exists(dirPath))
            {
                Directory.CreateDirectory(dirPath);
            }

            var options = new JsonSerializerOptions
            {
                WriteIndented = true,
                Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
            };

            await using var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write);
            await JsonSerializer.SerializeAsync(fs, config, options);
            loggerService.Info("配置文件保存成功");
      }
      catch (Exception ex)
      {
            loggerService.Error("保存配置文件失败", ex);
            throw;
      }
    }

    private static string GetConfigFilePath()
    {
      // 使用程序根目录存储配置文件
      return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ConfigFileName);
    }
}调用服务时,只需调用LoadConfigAsync和SaveConfigAsync异步方法即可,示例如下:
//读取配置文件
string DataStoragePath = "";

var loadedConfig = await jsonConfigService.LoadConfigAsync(new AppConfigModel());
if (loadedConfig != null)
{
    if (loadedConfig?.Common != null)
    {
      //更新到属性
      DataStoragePath = loadedConfig.Common.DataStoragePath;
    }
}

//保存配置到文件
private AppConfigModel appConfig;
//初始化appConfig
appConfig = new AppConfigModel();
appConfig.Common = new CommonConfig();

//更新界面上数据到配置appConfig中
appConfig.Common.DataStoragePath = DataStoragePath;

//保存配置
await jsonConfigService.SaveConfigAsync(appConfig);日志功能


[*]App.xaml.cs
var container = new ServiceCollection();

//...

//注册日志服务
container.AddSingleton<Common.Services.LoggerService>();

//...

Services = container.BuildServiceProvider();

[*]NLog.config
<?xml version="1.0" encoding="utf-8" ?>
<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      autoReload="true">

        <targets>
               
                <target name="InfoFile"
                                xsi:type="File"
                                fileName="LogFile/LogInfo/${shortdate}-Info.log"
                                layout="${date:format=yyyy-MM-dd HH\:mm\:ss.fff} ${message}${newline}"
                                encoding="UTF-8"
                                archiveEvery="Day"
                                maxArchiveFiles="100"
                                concurrentWrites="true"
                                keepFileOpen="false"/>

               
                <target name="ErrorFile"
                                xsi:type="File"
                                fileName="LogFile/LogError/${shortdate}-Error.log"
                                layout="${date:format=yyyy-MM-dd HH\:mm\:ss.fff} ${message}${newline}${newline}"
                                encoding="UTF-8"
                                archiveEvery="Day"
                                maxArchiveFiles="100"
                                concurrentWrites="true"
                                keepFileOpen="false"/>
        </targets>

        <rules>
               
                <logger name="MyLog" minlevel="Info" maxlevel="Info" writeTo="InfoFile" final="true" />
                <logger name="MyLog" minlevel="Error" maxlevel="Error" writeTo="ErrorFile" final="true" />
        </rules>
</nlog>

[*]LoggerService.cs
public class LoggerService
{
    private static readonly NLog.ILogger Logger = NLog.LogManager.GetLogger("MyLog");

    public void Info(string message)
    {
      Logger.Info(message);
    }

    public void Error(string message, Exception? ex = null)
    {
      Logger.Error(ex, message);
    }
}调用服务时,只需调用Info和Error方法即可,示例如下:
private void FunA()
{
    try
    {
      loggerService.Info("程序成功");
    }
    catch (Exception ex)
    {
      loggerService.Error("程序出错", ex);
    }
}界面介绍

各个界面如下图所示
主界面

登录界面

设置界面

具体项目请自行到Gitee仓库查看吧

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
页: [1]
查看完整版本: WPF治具软件模板分享