WPF 练手小案例 2

5 阅读12分钟

本文通过 11 个小案例强化 WPF 开发入门的基础。这 11 个案例是我从实际项目中抽象出来的,具有较强的实践意义,同时也能在很大程度上反映出 WPF 项目开发的一些基本概念。

1. 依赖注入以及动态打开 MainWindow

  1. 首先在 App.xaml 文件中删除 StartupUri="MainWindow.xaml" 这样就可以防止重复打开两个主窗口了。

  2. 然后为了成功的进行依赖注入,需要在 App.xaml.cs 文件中引入 Microsoft.Extensions.DependencyInjection.

  3. 接下来就是创建一个静态公有的属性 ServiceProvider.

  4. 设置生命周期函数 OnStartup, 在这个钩子函数中首先实例化一个 ServiceCollection 实例,使用此实例上的 AddTransient 方法将 MainWindow 注册到依赖树上去。

  5. serviceCollection 上提供一个名为 BuildServiceProvider 的方法,此方法返回一个获取依赖树上实例的方法 GetRequiredService.

  6. 完整的代码如下所示:

using System.Windows;
using Microsoft.Extensions.DependencyInjection;

namespace wpfdemo
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        public static IServiceProvider ServiceProvider { get; private set; }
        protected override void OnStartup(StartupEventArgs e)
        {
            var serviceCollection = new ServiceCollection();
            ConfigureServices(serviceCollection);

            ServiceProvider = serviceCollection.BuildServiceProvider();

            var mainWindow = ServiceProvider.GetRequiredService<MainWindow>();
            mainWindow.Show();
        }

        private void ConfigureServices(IServiceCollection services)
        {
            // 添加 WPF 主窗口
            services.AddTransient<MainWindow>();
        }
    }
}

2. 注册 sqlClient 服务,然后将依赖注入到 MainWindow 中去

  1. 创建一个文件夹 Services 用来放置所有需要注入的服务 mkdir Services.
  2. 在 Services 中创建文件 SqlClientService.cs 其内容如下:

首先使用 NuGet 中安装 System.Data.SqlClient:

using System.Data;
using System.Data.SqlClient;

namespace wpfdemo.Services
{
    public interface ISqlClientService
    {
        DataTable GetData(string query);
    }

    public class SqlClientService : ISqlClientService
    {
        private readonly string _connectionString;

        public SqlClientService(string connectionString)
        {
            _connectionString = connectionString;
        }

        
        public DataTable GetData(string query)
        {
            using (SqlConnection connection = new SqlConnection(_connectionString))
            {
                connection.Open();
                using (SqlCommand command = new SqlCommand(query, connection))
                {
                    using (SqlDataAdapter adapter = new SqlDataAdapter(command))
                    {
                        DataTable dataTable = new DataTable();
                        adapter.Fill(dataTable);
                        return dataTable;
                    }
                }
            }
        }
    }
}
  1. 然后来到 App.xaml.cs 文件中,找到 ConfigureServices 函数,这个函数中已经注册了 Main Window 现在在其下面注册 ISqlClientService
private void ConfigureServices(IServiceCollection services)
{
    // 添加 WPF 主窗口
    services.AddTransient<MainWindow>();

    // 注册数据库服务
    services.AddTransient<ISqlClientService, SqlClientService>(provider =>
    {
        string connectionString = "Data Source=db.db;";
        return new SqlClientService(connectionString);
    });
}

可以看出来我们仍然使用 services.AddTransient<T>() 的方式注册服务的。

  1. 保持 var mainWindow = ServiceProvider.GetRequiredService<MainWindow>(); 不变;在文件 MainWindow.xaml.cs 中修改构造函数为:
private readonly ISqlClientService _sqlClientService;

public MainWindow(ISqlClientService sqlClientService)
{
    InitializeComponent();
    DataContext = new MainViewModel();
    _sqlClientService = sqlClientService;

    Console.WriteLine(_sqlClientService);
}

如果能够成功打印出来,就证明注入成功了。

3. DateRange 的实现

<TextBlock Grid.Column="0"  Text="开始日期" VerticalAlignment="Center" FontSize="25" Foreground="White"/>
<hc:DatePicker Grid.Column="1" x:Name="startTime" ShowClearButton="False" Width="120" Height="40"  Margin="10,0,30,0"/>
<TextBlock Grid.Column="2"  Text="结束日期" VerticalAlignment="Center" FontSize="25" Foreground="White"/>
<hc:DatePicker Grid.Column="3" x:Name="endTime" ShowClearButton="False" Width="120" Height="40" Margin="10,0,30,0"/>

获取的数据做如下处理:

DateTime T1 = System.Convert.ToDateTime(startTime.Text);
DateTime T2 = System.Convert.ToDateTime(endTime.Text).AddDays(1); // 默认结束加1天

这样转换的目的就是利用 DateTime 实例是直接可以使用运算符进行大小比较的这种特性。

4. 使用 Grid 完成一个圣杯布局

   <Grid Cursor="">
       <Grid.RowDefinitions>
           <RowDefinition Height="50"></RowDefinition>
           <RowDefinition Height="*"></RowDefinition>
           <RowDefinition Height="50"></RowDefinition>
       </Grid.RowDefinitions>

       <Grid.ColumnDefinitions>
           <ColumnDefinition Width="100"></ColumnDefinition>
           <ColumnDefinition Width="*"></ColumnDefinition>
           <ColumnDefinition Width="100"></ColumnDefinition>
       </Grid.ColumnDefinitions>

       <TextBlock Text="Grid 布局标题" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
       <TextBlock Text="联系电话:17729563480" Grid.Row="2" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>

       <Grid Grid.Row="1" Grid.Column="0" Background="Gray"></Grid>
       <Grid Grid.Row="1" Grid.Column="2" Background="Gray"></Grid>

       <TextBlock Text="这是一个圣杯布局,使用 WPF 中的 Grid 完成" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="22" FontWeight="Bold" FontFamily="Arial" Cursor="Pen" IsEnabled="False"></TextBlock>
   </Grid>

5. 构造表格显示 List 中的数据

  1. 先构建 UI 界面,使用的是 DataGrid 控件,以及其中的名为 DataGrid.ColumnsDataGridTextColumn DataGridCheckBoxColumn 的属性标签
<DataGrid x:Name="myDataGrid" AutoGenerateColumns="False" Grid.Row="1" Grid.Column="1" Margin="0,60,0,70" HorizontalAlignment="Center" Width="202">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Name}"></DataGridTextColumn>
        <DataGridTextColumn Header="Age" Binding="{Binding Age}"></DataGridTextColumn>
        <DataGridCheckBoxColumn Header="Is Active" Binding="{Binding IsActive}"></DataGridCheckBoxColumn>
    </DataGrid.Columns>
</DataGrid>
  1. 然后构建数据结构,在 Models 中创建 MainModel/MainModel.cs 文件:
namespace wpfdemo.MainModel
{
    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public bool IsActive { get; set; }
    }
}
  1. 最后在隐藏文件中构造 List 变量并将其绑定到 myDataGrid 上即可
using wpfdemo.MainModel;
...
public MainWindow()
{
    InitializeComponent();
    List<Person> persons = new List<Person>
    {
        new Person { Name = "John", Age = 30, IsActive = false},
        new Person { Name = "Jane", Age = 20, IsActive = true},
    }
    
    myDataGrid.ItemSource = persons;
}

6. 创建自定义的组件库并引用

在 Visual Studio 中构建一个组件库项目,并在其他项目中引用它,是一个常见的开发需求。


步骤 1:创建组件库项目

  1. 打开 Visual Studio,选择 “创建新项目”

  2. 在项目类型中选择 “WPF 用户控件库”“WPF 控件库” (.NET Framework 或 .NET Core/5+,根据你的目标框架选择)。

    • 如果你使用的是 .NET Core 或 .NET 5+,选择 “WPF 控件库 (.NET Core)”
    • 如果你使用的是 .NET Framework,选择 “WPF 控件库”
  3. 命名你的组件库项目(例如:MyComponentLibrary),然后点击 “创建”


步骤 2:开发组件库

在组件库项目中,你可以创建用户控件(UserControl)、自定义控件(CustomControl)或其他共享资源。

示例:创建一个简单的用户控件

  1. 在组件库项目中,右键点击项目,选择 “添加” -> “用户控件”

  2. 命名用户控件(例如:MyCustomControl.xaml),然后点击 “添加”

  3. 编辑用户控件的 XAML 和代码,例如:

    xml复制

    <!-- MyCustomControl.xaml -->
    <UserControl x:Class="MyComponentLibrary.MyCustomControl"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 Width="200" Height="100">
        <Grid>
            <TextBlock Text="Hello from My Custom Control!" 
                       HorizontalAlignment="Center" 
                       VerticalAlignment="Center" 
                       FontSize="16" />
        </Grid>
    </UserControl>
    
  4. 在代码后台(MyCustomControl.xaml.cs)中,你可以添加逻辑:

    csharp复制

    namespace MyComponentLibrary
    {
        public partial class MyCustomControl : UserControl
        {
            public MyCustomControl()
            {
                InitializeComponent();
            }
        }
    }
    
  5. 构建组件库项目,确保编译成功。


步骤 3:引用组件库

方法 1:通过项目引用(适用于同一解决方案中的项目)

  1. 在主项目中(例如:一个 WPF 应用程序),右键点击 “引用” ,选择 “添加引用”

  2. 在弹出的窗口中,切换到 “项目” 选项卡,找到你的组件库项目(MyComponentLibrary),勾选它,然后点击 “确定”

  3. 在主项目的 XAML 文件中,添加组件库的命名空间:

    xml复制

    <Window x:Class="MyApp.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:MyApp"
            xmlns:mylib="clr-namespace:MyComponentLibrary;assembly=MyComponentLibrary"
            Title="MainWindow" Height="450" Width="800">
        <Grid>
            <mylib:MyCustomControl HorizontalAlignment="Center" VerticalAlignment="Center" />
        </Grid>
    </Window>
    
  4. 运行主项目,你应该能看到组件库中的控件显示在主项目中。


方法 2:通过 NuGet 包发布和引用(适用于跨解决方案的组件库)

  1. 打包组件库为 NuGet 包

    • 在组件库项目的根目录下,创建一个 .nuspec 文件(例如:MyComponentLibrary.nuspec)。

    • 编辑 .nuspec 文件,添加元数据:

      xml复制

      <?xml version="1.0"?>
      <package>
          <metadata>
              <id>MyComponentLibrary</id>
              <version>1.0.0</version>
              <authors>YourName</authors>
              <owners>YourName</owners>
              <requireLicenseAcceptance>false</requireLicenseAcceptance>
              <description>My custom WPF component library</description>
          </metadata>
      </package>
      
    • 使用命令行工具(如 nuget pack)打包组件库:

      bash复制

      nuget pack MyComponentLibrary.nuspec
      
    • 这将生成一个 .nupkg 文件。

  2. 发布 NuGet 包

    • 将生成的 .nupkg 文件上传到 NuGet 官方仓库(nuget.org)或私有 NuGet 服务器。
  3. 在主项目中引用 NuGet 包

    • 在主项目中,右键点击 “引用” ,选择 “管理 NuGet 包”
    • 搜索你的组件库包(例如:MyComponentLibrary),安装它。
    • 添加命名空间并使用组件,方法同上。

步骤 4:调试和更新组件库

  1. 调试组件库

    • 如果通过项目引用,直接在主项目中调试即可。
    • 如果通过 NuGet 包引用,可以设置符号服务器或使用 #if DEBUG 条件编译符号。
  2. 更新组件库

    • 修改组件库代码后,重新编译。
    • 如果通过项目引用,主项目会自动更新引用。
    • 如果通过 NuGet 包引用,需要重新打包并更新 NuGet 包版本,然后在主项目中更新包。

总结

通过以上步骤,你可以轻松创建一个组件库项目,并在其他项目中引用它。选择项目引用或 NuGet 包引用,取决于你的具体需求和开发场景。

7. 自定义 dll 提供函数并使用

在自定义一个 DLL 类库并在 WPF 项目中使用其提供的函数时,需要完成以下技术细节:

一、创建类库项目

  1. 新建项目

    • 在 Visual Studio 中,选择 “文件” -> “新建” -> “项目”。
    • 选择 “类库” 项目模板,可以选择基于 .NET Framework 或 .NET Core/.NET 5+。
    • 输入项目名称(如 YourLibraryNameSpace),选择保存位置,点击 “创建”。

注意,为了方便演示,请将 dll 库项目不要和使用它的 WPF 项目放在同一个解决方案下面,这样有助于演示这个过程中的细节;如果已经在一个解决方案中了,也可以右击类库项目选择 “移除”。移除不会删除项目文件,只是不在同一个解决方案中了而已。

  1. 编写类库代码

    • 在类库项目中,编写实现所需功能的代码。例如,一个简单的计算器功能:
namespace YourLibraryNamespace
{
    public class Calculator
    {
        public int Add(int a, int b)
        {
            return a + b;
        }

        public int Subtract(int a, int b)
        {
            return a - b;
        }
    }
}
  1. 生成 DLL 文件

    • 构建类库项目,生成的 DLL 文件将位于项目的输出目录(通常是 bin\Debugbin\Release)。这个过程是自动的,无须点击多余按钮。

二、在 WPF 项目中引用类库

  1. 引用 DLL 文件

    • 在 WPF 项目中,右键点击 “依赖项” 节点,“添加项目引用”节点,“浏览”,再点击“浏览”,输入 dll 文件的地址。
  2. 使用类库中的函数

    • 在 WPF 项目的代码文件中,添加对类库命名空间的引用:
using YourLibraryNamespace;

- 然后,可以实例化类库中的类并使用其方法:

Calculator calculator = new Calculator();
int result = calculator.Add(2, 3);

8. 加载配置文件

  1. 环境构造

在项目根目录下创建 ConfigFiles 文件夹,然后在其中构建 AppSettings.json 文件:

{
    "ConnectionStrings": {
        "Sqlite": "Data Source=db.sqlite;"
    }
}

这个文件需要参与运行,因此找到项目的 .csproj 文件,在其中将这个文件设置为运行时资源:

  <ItemGroup>
    <Resource Include="my.ico" />
    <Content Include="ConfigFiles\AppSettings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </Content>
  </ItemGroup>
  1. 然后再安装必要的依赖 Microsoft.Extensions.Configuration.Json
  2. 最后在 App.cs 的 OnStartup 钩子中将配置加载到 builder 中,然后打印出来
using Microsoft.Extensions.Configuration;
...
        ...
        protected override void OnStartup(StartupEventArgs e)
        {
            ...

            ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
            configurationBuilder
                .AddJsonFile("./ConfigFiles/AppSettings.json", optional: false, reloadOnChange: false);
            var configuration = configurationBuilder.Build();
            string ConnectionString = configuration["ConnectionStrings:Sqlite"];

            Console.WriteLine(ConnectionString);
        }

这个功能是通过 ConfigurationBuilder 类实现的,在上面的代码中我们读取了 sqlite 的配置文件。

9. 读取 json 中的数据并使用其初始化 VM 对象

  1. 创建 View Model 类
namespace wpfdemo.ViewModels
{
    public class MainViewModel 
    {
        [Newtonsoft.Json.JsonIgnore] public string ConfigPath { get; set; } = "./ConfigFiles/MainWindowSettings.json";
        // 属性示例
        private string _message = "你好 WPF";
        public string Message
        {
            get => _message;
            set
            {
                if (_message != value)
                {
                    _message = value;
                }
            }
        }

    }
}

这里设置了一个无需序列化的属性 ConfigPath 用来作为初始化配置文件路径。

  1. 创建 ./ConfigFiles/MainWindowSettings.json 文件,并使其格式和 MainViewModel 保持一致
{
  "Message": "来自配置文件:你好 WPF"
}
  1. 然后在 MainWindow 视图层文件中将 json 中的数据拷贝给 VM 对象,然后再将 VM 对象指向 DataContext.
mainViewModel = new MainViewModel();

if (!FileExtensions.DoesFileExist(mainViewModel.ConfigPath))//如果为空,先自动创建一个
    FileExtensions.WriteObject(mainViewModel.ConfigPath, new { });
//使用反射方法加载配置信息
FileExtensions.ReadObject<MainViewModel>(mainViewModel.ConfigPath).CopyPropertiesTo(mainViewModel);


DataContext = mainViewModel;

上述代码中做了防错处理,防止配置文件不存在的情况出现。

  1. 扩展 FileExtensions 类,在其中增加 DoesFileExist, WriteObject, ReadObjectCopyPropertiesTo 方法
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;

namespace wpfdemo.Models.Core
{
  public static class FileExtensions
  {
    // 将对象序列化为 JSON 并保存到文件
    public static void WriteObject<T>(string filePath, T obj)
    {
      string json = JsonConvert.SerializeObject(obj, Formatting.Indented);
      File.WriteAllText(filePath, json);
    }

    // 将对象序列化为 JSON 并保存到文件(带自定义 Serializer Settings)
    public static void WriteObject<T>(string filePath, T obj, JsonSerializerSettings settings)
    {
      string json = JsonConvert.SerializeObject(obj, settings);
      File.WriteAllText(filePath, json);
    }

    // 从文件中读取 JSON 并反序列化为指定类型的对象
    public static T ReadObject<T>(string filePath)
    {
      if (!File.Exists(filePath))
        throw new FileNotFoundException("File not found.", filePath);

      string json = File.ReadAllText(filePath);
      return JsonConvert.DeserializeObject<T>(json);
    }

    // 从文件中读取 JSON 并反序列化为动态对象(非泛型)
    public static dynamic ReadObject(string filePath)
    {
      if (!File.Exists(filePath))
        throw new FileNotFoundException("File not found.", filePath);

      string json = File.ReadAllText(filePath);
      return JsonConvert.DeserializeObject(json);
    }

    // 检查文件是否存在
    public static bool DoesFileExist(string filePath)
    {
      return File.Exists(filePath);
    }

    // 判断文件是否为空
    public static bool IsFileEmpty(string filePath)
    {
      if (!File.Exists(filePath))
        throw new FileNotFoundException("File not found.", filePath);

      return new FileInfo(filePath).Length == 0;
    }

    // 获取文件内容
    public static string ReadAllText(string filePath)
    {
      if (!File.Exists(filePath))
        throw new FileNotFoundException("File not found.", filePath);

      return File.ReadAllText(filePath);
    }

    // 拷贝文件
    public static void CopyFile(string sourcePath, string destinationPath, bool overwrite)
    {
      if (!File.Exists(sourcePath))
        throw new FileNotFoundException("Source file not found.", sourcePath);

      File.Copy(sourcePath, destinationPath, overwrite);
    }

    // 删除文件
    public static void DeleteFile(string filePath)
    {
      if (File.Exists(filePath))
        File.Delete(filePath);
    }

    // 获取文件大小
    public static long GetFileSize(string filePath)
    {
      if (!File.Exists(filePath))
        throw new FileNotFoundException("File not found.", filePath);

      return new FileInfo(filePath).Length;
    }

    // 将对象的属性值复制到另一个对象
    public static void CopyPropertiesTo(this object source, object target)
    {
      if (source == null || target == null)
        throw new ArgumentNullException("Source or target object is null.");

      Type sourceType = source.GetType();
      Type targetType = target.GetType();

      foreach (PropertyInfo sourceProperty in sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
      {
        if (sourceProperty.CanRead)
        {
          PropertyInfo targetProperty = targetType.GetProperty(sourceProperty.Name, BindingFlags.Public | BindingFlags.Instance);
          if (targetProperty != null && targetProperty.CanWrite)
          {
            if (sourceProperty.PropertyType.IsGenericType && sourceProperty.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
              Type nullableType = sourceProperty.PropertyType;
              Type underlyingType = Nullable.GetUnderlyingType(nullableType);
              object value = sourceProperty.GetValue(source);
              if (value != null)
              {
                if (targetProperty.PropertyType != underlyingType)
                  continue;
                targetProperty.SetValue(target, Convert.ChangeType(value, underlyingType));
              }
              else
              {
                targetProperty.SetValue(target, null);
              }
            }
            else
            {
              if (sourceProperty.PropertyType != targetProperty.PropertyType)
                continue;

              object value = sourceProperty.GetValue(source);
              targetProperty.SetValue(target, value);
            }
          }
        }
      }
    }
  }
}

10. 连接到 Sqlite 数据库并使用

  1. 安装 SqlSugar 和 System.Data.SQLite
  2. 从配置文件中读取连接本地数据库的 connectionstring 然后将单例注入,并完成数据库的初始化
using System.Windows;
using Microsoft.Extensions.DependencyInjection;
using wpfdemo.Services;
using Microsoft.Extensions.Configuration;
using SqlSugar;
using wpfdemo.Models.Core;
using System.IO;
using wpfdemo.Models.Vision;

namespace wpfdemo
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        public static IServiceProvider ServiceProvider { get; private set; }
        protected override void OnStartup(StartupEventArgs e)
        {
            ConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
            configurationBuilder
                .AddJsonFile("./ConfigFiles/AppSettings.json", optional: false, reloadOnChange: false);
            var configuration = configurationBuilder.Build();

            var serviceCollection = new ServiceCollection();
            ConfigureServices(serviceCollection);
            serviceCollection.AddScoped<ISqlSugarClient>(s =>
            {
                //Scoped用SqlSugarClient 
                SqlSugarClient sqlSugar = new SqlSugarClient(new ConnectionConfig()
                {
                    DbType = SqlSugar.DbType.Sqlite,
                    ConnectionString = configuration["ConnectionStrings:Sqlite"],
                    IsAutoCloseConnection = true,
                    InitKeyType = InitKeyType.Attribute
                },
               db =>
               {
                   db.Aop.OnLogExecuting = (sql, pars) => { };
               });
                return sqlSugar;
            });

            ServiceProvider = serviceCollection.BuildServiceProvider();

            if (FileExtensions.DoesFileExist("db.sqlite"))//如果数据库文件过大,重命名一下
            {
                long fileSize = FileExtensions.ReadAllText("db.sqlite").Length;
                var sizeGB = fileSize * 1.0 / (1024 * 1024);
                if (sizeGB > 3)//超过3个G自动重命名
                {
                    File.Move("db.sqlite", $"db{DateTime.Today.ToString("yyyyMMddHHmmss")}.sqlite");
                }
            }

            InitDatabase(ServiceProvider);

            var mainWindow = ServiceProvider.GetRequiredService<MainWindow>();
            mainWindow.Show();
        }

        private void InitDatabase(IServiceProvider service)
        {
            var db = service.GetService<ISqlSugarClient>();
            var isExist = db.DbMaintenance.CreateDatabase();
            db.CodeFirst.SetStringDefaultLength(300).InitTables(typeof(TestingRecord));
            db.CodeFirst.SetStringDefaultLength(300).InitTables(typeof(DailyRecord));

            // 测试插入并检索

            //db.Insertable<TestingRecord>(new TestingRecord
            //{
            //    SN = "Null",
            //    OrderCode = "Null",
            //    MATNR = "Null",
            //    TestName = "Null",
            //    TestTime = DateTime.Now,
            //    Result = "NG",
            //    Detail = "Null",
            //    OriginImgPath = "Null",
            //    ResultImgPath = "Null",
            //    MessagePath = "Null"
            //}).ExecuteCommandAsync();

            //List<TestingRecord> TempData = db.Queryable<TestingRecord>().Where(g => true).ToList();

            //Console.WriteLine(TempData);
        }

        private void ConfigureServices(IServiceCollection services)
        {
            // 添加 WPF 主窗口
            services.AddTransient<MainWindow>();
        }
    }
}

  • 使用 configuration 读取配置信息
  • 使用 serviceCollection.AddScoped<ISqlSugarClient> 注入单例
  • 使用 InitDatabase 初始化数据库
  • 注释的部分是在检测数据库的连接情况
  1. 在需要使用的视图层,接受注入的单例,然后调用方法来操作数据库
        public MainWindow(ISqlSugarClient sqlSugarClient)
        {
            InitializeComponent();
            _sqlSugarClient = sqlSugarClient;


            List<TestingRecord> TempData = _sqlSugarClient.Queryable<TestingRecord>().Where(g => true).ToList();

            Console.WriteLine(TempData);
  1. 查询数据库的依据是泛型,同样地,初始化数据库使用的也是泛型。以 TestingRecord 为例:
db.CodeFirst.SetStringDefaultLength(300).InitTables(typeof(TestingRecord));
...
List<TestingRecord> TempData = _sqlSugarClient.Queryable<TestingRecord>().Where(g => true).ToList();

在 Models 中创建一个子目录 Vision 在其中放入 TestingRecord.cs 文件:

using SqlSugar;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text;

namespace wpfdemo.Models.Vision
{
    public class TestingRecord
    {

        [Key]
        [ScaffoldColumn(false)]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        [SugarColumn(IsIdentity = true, IsPrimaryKey = true)]
        public int ID { get; set; }

        public string Werk { get; set; } = "";

        public string Factory { get; set; } = "";

        public string Line { get; set; } = "";

        public string Process { get; set; } = "";

        public string User { get; set; } = "";

        public string SN { get; set; } = "";

        public string OrderCode { get; set; } = "";

        public string MATNR { get; set; } = "";

        public string TestName { get; set; } = "";

        public DateTime TestTime { get; set; }

        public string Result { get; set; }

        public string Detail { get; set; } = "";

        public bool Rejudge { get; set; } = true;

        public string OriginImgPath { get; set; } = "";

        public string ResultImgPath { get; set; } = "";

        public string MessagePath { get; set; } = "";
    }
}
  • 在需要使用此类型的地方使用 using wpfdemo.Models.Vision; 即可。

11. 在任何地方拿到单例而不通过依赖注入的方式

ISqlSugarClient temp = App.ServiceProvider.GetService<ISqlSugarClient>() as ISqlSugarClient;
            
List<TestingRecord> TempData = new List<TestingRecord>();

if (temp != null)
{
    TempData = temp.Queryable<TestingRecord>().Where(g => true).ToList();
}

Console.WriteLine(TempData);

其中,App 是全局可访问的。