添加项目文件。

This commit is contained in:
lihanbo 2024-10-14 08:41:15 +08:00
parent 7fbf085a9f
commit 9de71dcef1
25 changed files with 1073 additions and 0 deletions

6
App.config Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8.1" />
</startup>
</configuration>

14
App.xaml Normal file
View File

@ -0,0 +1,14 @@
<Application
x:Class="ExcelHelper.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ExcelHelper">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml" />
<ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

46
App.xaml.cs Normal file
View File

@ -0,0 +1,46 @@
using System;
using System.Windows;
using ExcelHelper.Services;
using ExcelHelper.Utils;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace ExcelHelper
{
/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : Application
{
public static App AppHost;
private readonly IHost _host = Host.CreateDefaultBuilder()
.AddViewAndViewModel()
.ConfigureServices((context, services) =>
{
services.AddHostedService<ExcelHelperHostedService>();
services.AddSingleton<NavigationService>();
})
.Build();
protected override void OnStartup(StartupEventArgs e)
{
AppHost = this;
base.OnStartup(e);
// 初始化AppHost
_host.Start();
}
public T Get<T>()
{
return _host.Services.GetService<T>();
}
public object Get(Type type)
{
return _host.Services.GetService(type);
}
}
}

57
ExcelHelper.csproj Normal file
View File

@ -0,0 +1,57 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0-windows</TargetFramework>
<OutputType>WinExe</OutputType>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
<LangVersion>12.0</LangVersion>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<UseWPF>true</UseWPF>
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
</PropertyGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.8.1">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.8.1 %28x86 和 x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm">
<Version>8.3.2</Version>
</PackageReference>
<PackageReference Include="HandyControl">
<Version>3.5.1</Version>
</PackageReference>
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="MiniExcel">
<Version>1.34.2</Version>
</PackageReference>
<PackageReference Include="PolySharp">
<Version>1.14.1</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0-rc.2.24473.5" />
</ItemGroup>
</Project>

25
ExcelHelper.sln Normal file
View File

@ -0,0 +1,25 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.11.35327.3
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ExcelHelper", "ExcelHelper.csproj", "{C7A7E24D-513F-4D66-9953-42EDBD0038B7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C7A7E24D-513F-4D66-9953-42EDBD0038B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C7A7E24D-513F-4D66-9953-42EDBD0038B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C7A7E24D-513F-4D66-9953-42EDBD0038B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C7A7E24D-513F-4D66-9953-42EDBD0038B7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F92EF236-3F64-4327-8CF6-C6FDBDC7939E}
EndGlobalSection
EndGlobal

58
MainWindow.xaml Normal file
View File

@ -0,0 +1,58 @@
<Window
x:Class="ExcelHelper.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:local="clr-namespace:ExcelHelper"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewmodels="clr-namespace:ExcelHelper.Views.ViewModels"
Title="MainWindow"
Width="800"
Height="450"
d:DataContext="{d:DesignInstance Type=viewmodels:MainViewModel}"
WindowState="Maximized"
mc:Ignorable="d">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="200" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<hc:SideMenu Grid.Column="0" AutoSelect="True">
<hc:SideMenuItem
Command="{Binding SideMenuSelectCommand}"
CommandParameter="ImportExcelPage"
Header="导入"
IsSelected="True" />
<hc:SideMenuItem
Command="{Binding SideMenuSelectCommand}"
CommandParameter="DataListPage"
Header="已导入的数据" />
</hc:SideMenu>
<Frame
x:Name="MainFrame"
Grid.Column="1"
NavigationUIVisibility="Hidden" />
<hc:Dialog Background="Transparent" x:Name="MessageDialog" Visibility="Collapsed" Grid.Column="0" Grid.ColumnSpan="2">
<Border BorderBrush="Gray" Background="White" BorderThickness="1" CornerRadius="5" Padding="0">
<hc:SimpleStackPanel ClipToBounds="True" Orientation="Vertical" Height="300" Width="300" >
<Grid Margin="5" >
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*" MinHeight="200"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<DockPanel Width="300" Grid.Row="0" HorizontalAlignment="Left" >
<TextBlock Margin="5,0" DockPanel.Dock="Left" Text="12312312" VerticalAlignment="Center"/>
<Button Click="DialogCloseBtn_Click" Margin="15,0" HorizontalAlignment="Right" DockPanel.Dock="Right" Content="X"/>
</DockPanel>
<TextBlock Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding ErrorMessage}"/>
<StackPanel Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Right">
<Button x:Name="DialogCloseBtn" Content="确定" Click="DialogCloseBtn_Click"/>
</StackPanel>
</Grid>
</hc:SimpleStackPanel>
</Border>
</hc:Dialog>
</Grid>
</Window>

37
MainWindow.xaml.cs Normal file
View File

@ -0,0 +1,37 @@
using System.Windows;
using CommunityToolkit.Mvvm.Messaging;
using ExcelHelper.Message;
using ExcelHelper.Services;
using ExcelHelper.Views;
using ExcelHelper.Views.ViewModels;
namespace ExcelHelper
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window, IView
{
private MainViewModel ViewModel;
public MainWindow(MainViewModel viewModel, NavigationService navigationService)
{
InitializeComponent();
DataContext = ViewModel = viewModel;
navigationService.InitForFrame(MainFrame);
WeakReferenceMessenger.Default.Register<ErrorDialogMessage>(this, (r, message) =>
{
if (message.Value != null)
{
ViewModel.ErrorMessage = message.Value;
MessageDialog.Visibility = Visibility.Visible;
}
});
}
private void DialogCloseBtn_Click(object sender, System.Windows.RoutedEventArgs e)
{
MessageDialog.Visibility = System.Windows.Visibility.Collapsed;
}
}
}

View File

@ -0,0 +1,9 @@
using CommunityToolkit.Mvvm.Messaging.Messages;
namespace ExcelHelper.Message;
internal class ErrorDialogMessage : ValueChangedMessage<string>
{
public ErrorDialogMessage(string value) : base(value)
{
}
}

View File

@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.Windows.Controls;
using CommunityToolkit.Mvvm.Messaging.Messages;
namespace ExcelHelper.Message;
internal class UpdateDataGridColumnsMessage : ValueChangedMessage<List<DataGridColumn>>
{
public UpdateDataGridColumnsMessage(List<DataGridColumn> value) : base(value)
{
}
}

71
Properties/Resources.Designer.cs generated Normal file
View File

@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace ExcelHelper.Properties
{
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ExcelHelper.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

117
Properties/Resources.resx Normal file
View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</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>
</root>

30
Properties/Settings.Designer.cs generated Normal file
View File

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace ExcelHelper.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

View File

@ -0,0 +1,27 @@
using System.Threading;
using System.Threading.Tasks;
using ExcelHelper.Views.Pages;
using Microsoft.Extensions.Hosting;
namespace ExcelHelper.Services
{
public class ExcelHelperHostedService : IHostedService
{
public Task StartAsync(CancellationToken cancellationToken)
{
var mainWindow = App.AppHost.Get<MainWindow>();
if (mainWindow != null)
{
mainWindow.Show();
App.AppHost.Get<NavigationService>().NavigateTo<ImportExcelPage>();
}
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
}

View File

@ -0,0 +1,35 @@
using System;
using System.Windows.Controls;
using ExcelHelper.Views;
namespace ExcelHelper.Services
{
public class NavigationService
{
private Frame _frame;
public static string currentView;
public void InitForFrame(Frame frame)
{
_frame = frame;
}
public void NavigateTo<T>()
{
var target = App.AppHost.Get<T>();
if (target is IView page)
{
currentView = typeof(T).Name;
_frame.NavigationService.Navigate(page);
}
}
public void NavigateTo(Type type)
{
var target = App.AppHost.Get(type);
if (target is IView page)
{
currentView = type.Name;
_frame.NavigationService.Navigate(page);
}
}
}
}

32
Utils/HostExtension.cs Normal file
View File

@ -0,0 +1,32 @@
using System.Reflection;
using ExcelHelper.Views;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace ExcelHelper.Utils
{
internal static class HostExtension
{
public static IHostBuilder AddViewAndViewModel(this IHostBuilder hostBuilder)
{
// Scan all assemblies to find all types that implement IViewModel
var assem = Assembly.GetExecutingAssembly();
var types = assem.GetTypes();
foreach (var type in types)
{
if (type.IsInterface || type.IsAbstract)
{
continue;
}
if (typeof(IViewModel).IsAssignableFrom(type) || typeof(IView).IsAssignableFrom(type))
{
hostBuilder.ConfigureServices((context, services) =>
{
services.AddSingleton(type);
});
}
}
return hostBuilder;
}
}
}

View File

@ -0,0 +1,83 @@
using System.Windows;
using System.Windows.Controls;
namespace ExcelHelper.Utils;
public static class PasswordBoxHelper
{
public static readonly DependencyProperty PasswordProperty = DependencyProperty.RegisterAttached("Password", typeof(string), typeof(PasswordBoxHelper),
new FrameworkPropertyMetadata(string.Empty, OnPasswordPropertyChanged));
public static readonly DependencyProperty AttachProperty = DependencyProperty.RegisterAttached("Attach", typeof(bool), typeof(PasswordBoxHelper), new PropertyMetadata(false, OnAttachPropertyChanged));
private static readonly DependencyProperty IsUpdatingProperty = DependencyProperty.RegisterAttached("IsUpdating", typeof(bool), typeof(PasswordBoxHelper));
public static void SetAttach(DependencyObject dp, bool value)
{
dp.SetValue(AttachProperty, value);
}
public static bool GetAttach(DependencyObject dp)
{
return (bool)dp.GetValue(AttachProperty);
}
public static string GetPassword(DependencyObject dp)
{
return (string)dp.GetValue(PasswordProperty);
}
public static void SetPassword(DependencyObject dp, string value)
{
dp.SetValue(PasswordProperty, value);
}
private static bool GetIsUpdating(DependencyObject dp)
{
return (bool)dp.GetValue(IsUpdatingProperty);
}
private static void SetIsUpdating(DependencyObject dp, bool value)
{
dp.SetValue(IsUpdatingProperty, value);
}
private static void OnPasswordPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
PasswordBox passwordBox = sender as PasswordBox;
passwordBox.PasswordChanged -= PasswordChanged;
if (!(bool)GetIsUpdating(passwordBox))
{
passwordBox.Password = (string)e.NewValue;
}
passwordBox.PasswordChanged += PasswordChanged;
}
private static void OnAttachPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
PasswordBox passwordBox = sender as PasswordBox;
if (passwordBox == null)
{
return;
}
if ((bool)e.OldValue)
{
passwordBox.PasswordChanged -= PasswordChanged;
}
if ((bool)e.NewValue)
{
passwordBox.PasswordChanged += PasswordChanged;
}
}
private static void PasswordChanged(object sender, RoutedEventArgs e)
{
PasswordBox passwordBox = sender as PasswordBox;
SetIsUpdating(passwordBox, true);
SetPassword(passwordBox, passwordBox.Password);
SetIsUpdating(passwordBox, false);
}
}

6
Views/IView.cs Normal file
View File

@ -0,0 +1,6 @@
namespace ExcelHelper.Views
{
internal interface IView
{
}
}

6
Views/IViewModel.cs Normal file
View File

@ -0,0 +1,6 @@
namespace ExcelHelper.Views
{
internal interface IViewModel
{
}
}

View File

@ -0,0 +1,16 @@
<Page
x:Class="ExcelHelper.Views.Pages.DataListPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ExcelHelper.Views.Pages"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="DataListPage"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Grid>
<TextBlock Text="All data list" />
</Grid>
</Page>

View File

@ -0,0 +1,15 @@
using System.Windows.Controls;
namespace ExcelHelper.Views.Pages
{
/// <summary>
/// DataListPage.xaml 的交互逻辑
/// </summary>
public partial class DataListPage : Page, IView
{
public DataListPage()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,116 @@
<Page
x:Class="ExcelHelper.Views.Pages.ImportExcelPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:hc="https://handyorg.github.io/handycontrol"
xmlns:local="clr-namespace:ExcelHelper.Views.Pages"
xmlns:utils="clr-namespace:ExcelHelper.Utils"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewmodels="clr-namespace:ExcelHelper.Views.ViewModels"
Title="ImportExcelPage"
d:DataContext="{d:DesignInstance Type=viewmodels:ImportViewModel}"
d:DesignHeight="450"
d:DesignWidth="1200"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="Mask">
<Grid Background="#99424242">
<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="20"
Foreground="White"
Text="拖拽到此处放开" />
</Grid>
</DataTemplate>
</Page.Resources>
<Grid
AllowDrop="True"
DragEnter="Grid_DragEnter"
DragLeave="Grid_DragLeave"
Drop="Grid_Drop">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="800" />
<ColumnDefinition Width="370" MinWidth="370" />
</Grid.ColumnDefinitions>
<ContentPresenter
x:Name="DropFileMask"
Grid.Column="0"
Grid.ColumnSpan="2"
Panel.ZIndex="10"
ContentTemplate="{StaticResource Mask}"
Visibility="Collapsed" />
<hc:TabControl Grid.Column="0" Margin="5,5,7,5">
<hc:TabItem Header="预览">
<DataGrid IsReadOnly="True" x:Name="ExcelDataPreviewGrid" AutoGenerateColumns="False" ColumnWidth="Auto" ItemsSource="{Binding ExcelData}" />
</hc:TabItem>
<hc:TabItem Header="列信息">
<DataGrid>
<DataGrid.Columns >
<DataGridTextColumn Header="列" />
</DataGrid.Columns>
</DataGrid>
</hc:TabItem>
</hc:TabControl>
<GridSplitter
Grid.Column="0"
Width="2"
Margin="0,5" />
<GroupBox
Grid.Column="1"
Margin="5"
Padding="5">
<GroupBox.Header>
<StackPanel Orientation="Horizontal">
<TextBlock
Margin="5,0"
VerticalAlignment="Center"
Text="参数配置" />
<Button VerticalAlignment="Center" Content="重新读取Excel" />
</StackPanel>
</GroupBox.Header>
<hc:SimpleStackPanel SnapsToDevicePixels="True">
<hc:SimpleStackPanel.Resources>
<Style TargetType="{x:Type hc:SimpleStackPanel}">
<Setter Property="Margin" Value="5,0" />
</Style>
</hc:SimpleStackPanel.Resources>
<hc:SimpleStackPanel Orientation="Horizontal">
<Label Content="指定的Sheet" />
<hc:ComboBox MinWidth="60" Margin="0" ItemsSource="{Binding Sheets}" SelectedValue="{Binding SelectedSheetName}" />
<Button
Margin="0"
VerticalAlignment="Center"
Content="读取Excel" />
</hc:SimpleStackPanel>
<hc:SimpleStackPanel Height="Auto" Orientation="Horizontal">
<Label Content="起始位置:" />
<hc:TextBox MinWidth="40" Text="{Binding StartCell}" />
<CheckBox Content="包含列头" IsChecked="{Binding UseHeaderRow}" />
</hc:SimpleStackPanel>
<hc:SimpleStackPanel Orientation="Horizontal">
<Label Content="结束位置:" />
<hc:TextBox MinWidth="40" Text="{Binding EndCell}" />
</hc:SimpleStackPanel>
<hc:SimpleStackPanel Orientation="Horizontal">
<Label Content="最大读取行数:" />
<hc:NumericUpDown MinWidth="40" Minimum="1" Value="{Binding MaxRow}" />
</hc:SimpleStackPanel>
<hc:SimpleStackPanel Width="Auto" Orientation="Horizontal">
<Label Content="当前文件路径:" />
<!--<hc:TextBox MinWidth="200" />-->
<hc:ComboBox ItemsSource="{Binding ExcelFiles}" SelectedValue="{Binding CurrentFilePath}" MaxWidth="200" />
</hc:SimpleStackPanel>
<hc:SimpleStackPanel Orientation="Horizontal">
<Label Content="Excel密码" />
<PasswordBox utils:PasswordBoxHelper.Password="{Binding ExcelPassword, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" MinWidth="60" />
<Button Content="?" ToolTip="未加密留空多个Excel如果不同密码请分批次导入" />
</hc:SimpleStackPanel>
</hc:SimpleStackPanel>
</GroupBox>
</Grid>
</Page>

View File

@ -0,0 +1,79 @@
using System.Windows.Controls;
using CommunityToolkit.Mvvm.Messaging;
using ExcelHelper.Message;
using ExcelHelper.Views.ViewModels;
namespace ExcelHelper.Views.Pages
{
/// <summary>
/// ImportExcelPage.xaml 的交互逻辑
/// </summary>
public partial class ImportExcelPage : Page, IView, IRecipient<UpdateDataGridColumnsMessage>
{
private ImportViewModel ViewModel;
public ImportExcelPage(ImportViewModel viewModel)
{
InitializeComponent();
this.DataContext = ViewModel = viewModel;
//GenerateDataGridColumns();
//Messenger
ViewModel.IsActive = true;
// Register a message in some module
WeakReferenceMessenger.Default.Register<UpdateDataGridColumnsMessage>(this, (r, message) =>
{
if (message.Value != null)
{
ExcelDataPreviewGrid.Columns.Clear();
foreach (var column in message.Value)
{
ExcelDataPreviewGrid.Columns.Add(column);
}
}
});
}
private void Grid_DragEnter(object sender, System.Windows.DragEventArgs e)
{
if (e.Data.GetDataPresent(System.Windows.DataFormats.FileDrop))
{
e.Effects = System.Windows.DragDropEffects.Link;
}
else
{
e.Effects = System.Windows.DragDropEffects.None;
}
DropFileMask.Visibility = System.Windows.Visibility.Visible;
}
private void Grid_Drop(object sender, System.Windows.DragEventArgs e)
{
DropFileMask.Visibility = System.Windows.Visibility.Collapsed;
if (e.Data.GetDataPresent(System.Windows.DataFormats.FileDrop))
{
var files = (string[])e.Data.GetData(System.Windows.DataFormats.FileDrop);
if (files.Length > 0)
{
//ViewModel.FileDropCommand.CanExecute(files);
ViewModel.FileDrop(files);
}
}
}
private void Grid_DragLeave(object sender, System.Windows.DragEventArgs e)
{
DropFileMask.Visibility = System.Windows.Visibility.Collapsed;
}
void IRecipient<UpdateDataGridColumnsMessage>.Receive(UpdateDataGridColumnsMessage message)
{
if (message.Value != null)
{
ExcelDataPreviewGrid.Columns.Clear();
foreach (var column in message.Value)
{
ExcelDataPreviewGrid.Columns.Add(column);
}
}
}
}
}

View File

@ -0,0 +1,134 @@
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Messaging;
using ExcelHelper.Message;
using MiniExcelLibs;
namespace ExcelHelper.Views.ViewModels
{
public partial class ImportViewModel : ObservableRecipient, IViewModel
{
public void FileDrop(string[] files)
{
ExcelFiles.Clear();
foreach (var item in files)
{
ExcelFiles.Add(item);
}
//ReadForExcel(ExcelFiles.First());
CurrentFilePath = ExcelFiles.First();
}
public void ReadForExcel(string path)
{
ExcelData = MiniExcel.Query(path, useHeaderRow: UseHeaderRow);
var columns = MiniExcel.GetColumns(path, useHeaderRow: UseHeaderRow);
GenColumns(columns);
}
private void GenColumns(IEnumerable<string> columns)
{
Columns.Clear();
if (UseHeaderRow)
{
foreach (var columnName in columns)
{
var column = new DataGridTextColumn
{
Header = columnName,
Binding = new System.Windows.Data.Binding($"{columnName}"),
Width = DataGridLength.Auto
};
Columns.Add(column);
}
}
else
{
for (var i = 'A'; i < 'Z'; i++)
{
var column = new DataGridTextColumn
{
Header = $"{i}",
Binding = new System.Windows.Data.Binding($"{i}"),
Width = DataGridLength.Auto
};
Columns.Add(column);
}
}
if (Columns.Count > 0)
WeakReferenceMessenger.Default.Send(new UpdateDataGridColumnsMessage([.. Columns]));
else
{
WeakReferenceMessenger.Default.Send(new ErrorDialogMessage("未读取到列信息!"));
}
}
#region Props
[ObservableProperty]
private IEnumerable<dynamic> _excelData;
[ObservableProperty]
private ObservableCollection<string> _excelFiles = [];
[ObservableProperty]
private ObservableCollection<DataGridColumn> _columns = [];
/// <summary>
/// 使用首行作为表头
/// </summary>
[ObservableProperty]
private bool _useHeaderRow;
/// <summary>
/// 选中的Sheet
/// </summary>
[ObservableProperty]
private string _selectedSheetName;
/// <summary>
/// Sheets列表
/// </summary>
[ObservableProperty]
private ObservableCollection<string> _sheets = [];
/// <summary>
/// 起始位置
/// </summary>
[ObservableProperty]
private string _startCell;
/// <summary>
/// 结束位置
/// </summary>
[ObservableProperty]
private string _endCell;
/// <summary>
/// 最大行数
/// </summary>
[ObservableProperty]
private string _maxRow;
/// <summary>
/// 当前文件路径
/// </summary>
private string _currentFilePath;
public string CurrentFilePath
{
get => _currentFilePath;
set
{
SetProperty(ref _currentFilePath, value);
ReadForExcel(value);
}
}
/// <summary>
/// Excel文件密码
/// </summary>
[ObservableProperty]
private string _excelPassword;
#endregion
}
}

View File

@ -0,0 +1,34 @@
using System.Diagnostics;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using ExcelHelper.Views.Pages;
namespace ExcelHelper.Views.ViewModels
{
public partial class MainViewModel : ObservableObject, IViewModel
{
/// <summary>
/// 异常信息
/// </summary>
[ObservableProperty]
private string _errorMessage;
[RelayCommand]
private void OnSideMenuSelect(string itemTag)
{
Trace.WriteLine($"OnSideMenuSelect -> {itemTag}");
var targetPage = itemTag switch
{
"ImportExcelPage" => typeof(ImportExcelPage),
"DataListPage" => typeof(DataListPage),
_ => null
};
if (targetPage != null)
{
App.AppHost.Get<Services.NavigationService>().NavigateTo(targetPage);
}
}
}
}