Sicherung
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFrameworks>net6.0-windows;net472</TargetFrameworks>
|
<TargetFrameworks>net472;net6.0-windows</TargetFrameworks>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
|
|||||||
390
FSI.Lib/.gitignore
vendored
390
FSI.Lib/.gitignore
vendored
@@ -1,390 +0,0 @@
|
|||||||
# ---> VisualStudio
|
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
|
||||||
## files generated by popular Visual Studio add-ons.
|
|
||||||
##
|
|
||||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
|
||||||
|
|
||||||
# User-specific files
|
|
||||||
*.rsuser
|
|
||||||
*.suo
|
|
||||||
*.user
|
|
||||||
*.userosscache
|
|
||||||
*.sln.docstates
|
|
||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
|
||||||
*.userprefs
|
|
||||||
|
|
||||||
# Mono auto generated files
|
|
||||||
mono_crash.*
|
|
||||||
|
|
||||||
# Build results
|
|
||||||
[Dd]ebug/
|
|
||||||
[Dd]ebugPublic/
|
|
||||||
[Rr]elease/
|
|
||||||
[Rr]eleases/
|
|
||||||
x64/
|
|
||||||
x86/
|
|
||||||
[Ww][Ii][Nn]32/
|
|
||||||
[Aa][Rr][Mm]/
|
|
||||||
[Aa][Rr][Mm]64/
|
|
||||||
bld/
|
|
||||||
[Bb]in/
|
|
||||||
[Oo]bj/
|
|
||||||
[Ll]og/
|
|
||||||
[Ll]ogs/
|
|
||||||
|
|
||||||
# Visual Studio 2015/2017 cache/options directory
|
|
||||||
.vs/
|
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
|
||||||
#wwwroot/
|
|
||||||
|
|
||||||
# Visual Studio 2017 auto generated files
|
|
||||||
Generated\ Files/
|
|
||||||
|
|
||||||
# MSTest test Results
|
|
||||||
[Tt]est[Rr]esult*/
|
|
||||||
[Bb]uild[Ll]og.*
|
|
||||||
|
|
||||||
# NUnit
|
|
||||||
*.VisualState.xml
|
|
||||||
TestResult.xml
|
|
||||||
nunit-*.xml
|
|
||||||
|
|
||||||
# Build Results of an ATL Project
|
|
||||||
[Dd]ebugPS/
|
|
||||||
[Rr]eleasePS/
|
|
||||||
dlldata.c
|
|
||||||
|
|
||||||
# Benchmark Results
|
|
||||||
BenchmarkDotNet.Artifacts/
|
|
||||||
|
|
||||||
# .NET Core
|
|
||||||
project.lock.json
|
|
||||||
project.fragment.lock.json
|
|
||||||
artifacts/
|
|
||||||
|
|
||||||
# ASP.NET Scaffolding
|
|
||||||
ScaffoldingReadMe.txt
|
|
||||||
|
|
||||||
# StyleCop
|
|
||||||
StyleCopReport.xml
|
|
||||||
|
|
||||||
# Files built by Visual Studio
|
|
||||||
*_i.c
|
|
||||||
*_p.c
|
|
||||||
*_h.h
|
|
||||||
*.ilk
|
|
||||||
*.meta
|
|
||||||
*.obj
|
|
||||||
*.iobj
|
|
||||||
*.pch
|
|
||||||
*.pdb
|
|
||||||
*.ipdb
|
|
||||||
*.pgc
|
|
||||||
*.pgd
|
|
||||||
*.rsp
|
|
||||||
*.sbr
|
|
||||||
*.tlb
|
|
||||||
*.tli
|
|
||||||
*.tlh
|
|
||||||
*.tmp
|
|
||||||
*.tmp_proj
|
|
||||||
*_wpftmp.csproj
|
|
||||||
*.log
|
|
||||||
*.tlog
|
|
||||||
*.vspscc
|
|
||||||
*.vssscc
|
|
||||||
.builds
|
|
||||||
*.pidb
|
|
||||||
*.svclog
|
|
||||||
*.scc
|
|
||||||
|
|
||||||
# Chutzpah Test files
|
|
||||||
_Chutzpah*
|
|
||||||
|
|
||||||
# Visual C++ cache files
|
|
||||||
ipch/
|
|
||||||
*.aps
|
|
||||||
*.ncb
|
|
||||||
*.opendb
|
|
||||||
*.opensdf
|
|
||||||
*.sdf
|
|
||||||
*.cachefile
|
|
||||||
*.VC.db
|
|
||||||
*.VC.VC.opendb
|
|
||||||
|
|
||||||
# Visual Studio profiler
|
|
||||||
*.psess
|
|
||||||
*.vsp
|
|
||||||
*.vspx
|
|
||||||
*.sap
|
|
||||||
|
|
||||||
# Visual Studio Trace Files
|
|
||||||
*.e2e
|
|
||||||
|
|
||||||
# TFS 2012 Local Workspace
|
|
||||||
$tf/
|
|
||||||
|
|
||||||
# Guidance Automation Toolkit
|
|
||||||
*.gpState
|
|
||||||
|
|
||||||
# ReSharper is a .NET coding add-in
|
|
||||||
_ReSharper*/
|
|
||||||
*.[Rr]e[Ss]harper
|
|
||||||
*.DotSettings.user
|
|
||||||
|
|
||||||
# TeamCity is a build add-in
|
|
||||||
_TeamCity*
|
|
||||||
|
|
||||||
# DotCover is a Code Coverage Tool
|
|
||||||
*.dotCover
|
|
||||||
|
|
||||||
# AxoCover is a Code Coverage Tool
|
|
||||||
.axoCover/*
|
|
||||||
!.axoCover/settings.json
|
|
||||||
|
|
||||||
# Coverlet is a free, cross platform Code Coverage Tool
|
|
||||||
coverage*.json
|
|
||||||
coverage*.xml
|
|
||||||
coverage*.info
|
|
||||||
|
|
||||||
# Visual Studio code coverage results
|
|
||||||
*.coverage
|
|
||||||
*.coveragexml
|
|
||||||
|
|
||||||
# NCrunch
|
|
||||||
_NCrunch_*
|
|
||||||
.*crunch*.local.xml
|
|
||||||
nCrunchTemp_*
|
|
||||||
|
|
||||||
# MightyMoose
|
|
||||||
*.mm.*
|
|
||||||
AutoTest.Net/
|
|
||||||
|
|
||||||
# Web workbench (sass)
|
|
||||||
.sass-cache/
|
|
||||||
|
|
||||||
# Installshield output folder
|
|
||||||
[Ee]xpress/
|
|
||||||
|
|
||||||
# DocProject is a documentation generator add-in
|
|
||||||
DocProject/buildhelp/
|
|
||||||
DocProject/Help/*.HxT
|
|
||||||
DocProject/Help/*.HxC
|
|
||||||
DocProject/Help/*.hhc
|
|
||||||
DocProject/Help/*.hhk
|
|
||||||
DocProject/Help/*.hhp
|
|
||||||
DocProject/Help/Html2
|
|
||||||
DocProject/Help/html
|
|
||||||
|
|
||||||
# Click-Once directory
|
|
||||||
publish/
|
|
||||||
|
|
||||||
# Publish Web Output
|
|
||||||
*.[Pp]ublish.xml
|
|
||||||
*.azurePubxml
|
|
||||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
|
||||||
# but database connection strings (with potential passwords) will be unencrypted
|
|
||||||
*.pubxml
|
|
||||||
*.publishproj
|
|
||||||
|
|
||||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
|
||||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
|
||||||
# in these scripts will be unencrypted
|
|
||||||
PublishScripts/
|
|
||||||
|
|
||||||
# NuGet Packages
|
|
||||||
*.nupkg
|
|
||||||
# NuGet Symbol Packages
|
|
||||||
*.snupkg
|
|
||||||
# The packages folder can be ignored because of Package Restore
|
|
||||||
**/[Pp]ackages/*
|
|
||||||
# except build/, which is used as an MSBuild target.
|
|
||||||
!**/[Pp]ackages/build/
|
|
||||||
# Uncomment if necessary however generally it will be regenerated when needed
|
|
||||||
#!**/[Pp]ackages/repositories.config
|
|
||||||
# NuGet v3's project.json files produces more ignorable files
|
|
||||||
*.nuget.props
|
|
||||||
*.nuget.targets
|
|
||||||
|
|
||||||
# Nuget personal access tokens and Credentials
|
|
||||||
nuget.config
|
|
||||||
|
|
||||||
# Microsoft Azure Build Output
|
|
||||||
csx/
|
|
||||||
*.build.csdef
|
|
||||||
|
|
||||||
# Microsoft Azure Emulator
|
|
||||||
ecf/
|
|
||||||
rcf/
|
|
||||||
|
|
||||||
# Windows Store app package directories and files
|
|
||||||
AppPackages/
|
|
||||||
BundleArtifacts/
|
|
||||||
Package.StoreAssociation.xml
|
|
||||||
_pkginfo.txt
|
|
||||||
*.appx
|
|
||||||
*.appxbundle
|
|
||||||
*.appxupload
|
|
||||||
|
|
||||||
# Visual Studio cache files
|
|
||||||
# files ending in .cache can be ignored
|
|
||||||
*.[Cc]ache
|
|
||||||
# but keep track of directories ending in .cache
|
|
||||||
!?*.[Cc]ache/
|
|
||||||
|
|
||||||
# Others
|
|
||||||
ClientBin/
|
|
||||||
~$*
|
|
||||||
*~
|
|
||||||
*.dbmdl
|
|
||||||
*.dbproj.schemaview
|
|
||||||
*.jfm
|
|
||||||
*.pfx
|
|
||||||
*.publishsettings
|
|
||||||
orleans.codegen.cs
|
|
||||||
|
|
||||||
# Including strong name files can present a security risk
|
|
||||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
|
||||||
#*.snk
|
|
||||||
|
|
||||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
|
||||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
|
||||||
#bower_components/
|
|
||||||
|
|
||||||
# RIA/Silverlight projects
|
|
||||||
Generated_Code/
|
|
||||||
|
|
||||||
# Backup & report files from converting an old project file
|
|
||||||
# to a newer Visual Studio version. Backup files are not needed,
|
|
||||||
# because we have git ;-)
|
|
||||||
_UpgradeReport_Files/
|
|
||||||
Backup*/
|
|
||||||
UpgradeLog*.XML
|
|
||||||
UpgradeLog*.htm
|
|
||||||
ServiceFabricBackup/
|
|
||||||
*.rptproj.bak
|
|
||||||
|
|
||||||
# SQL Server files
|
|
||||||
*.mdf
|
|
||||||
*.ldf
|
|
||||||
*.ndf
|
|
||||||
|
|
||||||
# Business Intelligence projects
|
|
||||||
*.rdl.data
|
|
||||||
*.bim.layout
|
|
||||||
*.bim_*.settings
|
|
||||||
*.rptproj.rsuser
|
|
||||||
*- [Bb]ackup.rdl
|
|
||||||
*- [Bb]ackup ([0-9]).rdl
|
|
||||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
|
||||||
|
|
||||||
# Microsoft Fakes
|
|
||||||
FakesAssemblies/
|
|
||||||
|
|
||||||
# GhostDoc plugin setting file
|
|
||||||
*.GhostDoc.xml
|
|
||||||
|
|
||||||
# Node.js Tools for Visual Studio
|
|
||||||
.ntvs_analysis.dat
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# Visual Studio 6 build log
|
|
||||||
*.plg
|
|
||||||
|
|
||||||
# Visual Studio 6 workspace options file
|
|
||||||
*.opt
|
|
||||||
|
|
||||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
|
||||||
*.vbw
|
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/ModelManifest.xml
|
|
||||||
**/*.Server/GeneratedArtifacts
|
|
||||||
**/*.Server/ModelManifest.xml
|
|
||||||
_Pvt_Extensions
|
|
||||||
|
|
||||||
# Paket dependency manager
|
|
||||||
.paket/paket.exe
|
|
||||||
paket-files/
|
|
||||||
|
|
||||||
# FAKE - F# Make
|
|
||||||
.fake/
|
|
||||||
|
|
||||||
# CodeRush personal settings
|
|
||||||
.cr/personal
|
|
||||||
|
|
||||||
# Python Tools for Visual Studio (PTVS)
|
|
||||||
__pycache__/
|
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# Cake - Uncomment if you are using it
|
|
||||||
# tools/**
|
|
||||||
# !tools/packages.config
|
|
||||||
|
|
||||||
# Tabs Studio
|
|
||||||
*.tss
|
|
||||||
|
|
||||||
# Telerik's JustMock configuration file
|
|
||||||
*.jmconfig
|
|
||||||
|
|
||||||
# BizTalk build output
|
|
||||||
*.btp.cs
|
|
||||||
*.btm.cs
|
|
||||||
*.odx.cs
|
|
||||||
*.xsd.cs
|
|
||||||
|
|
||||||
# OpenCover UI analysis results
|
|
||||||
OpenCover/
|
|
||||||
|
|
||||||
# Azure Stream Analytics local run output
|
|
||||||
ASALocalRun/
|
|
||||||
|
|
||||||
# MSBuild Binary and Structured Log
|
|
||||||
*.binlog
|
|
||||||
|
|
||||||
# NVidia Nsight GPU debugger configuration file
|
|
||||||
*.nvuser
|
|
||||||
|
|
||||||
# MFractors (Xamarin productivity tool) working folder
|
|
||||||
.mfractor/
|
|
||||||
|
|
||||||
# Local History for Visual Studio
|
|
||||||
.localhistory/
|
|
||||||
|
|
||||||
# BeatPulse healthcheck temp database
|
|
||||||
healthchecksdb
|
|
||||||
|
|
||||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
|
||||||
MigrationBackup/
|
|
||||||
|
|
||||||
# Ionide (cross platform F# VS Code tools) working folder
|
|
||||||
.ionide/
|
|
||||||
|
|
||||||
# Fody - auto-generated XML schema
|
|
||||||
FodyWeavers.xsd
|
|
||||||
|
|
||||||
# VS Code files for those working on multiple tools
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/settings.json
|
|
||||||
!.vscode/tasks.json
|
|
||||||
!.vscode/launch.json
|
|
||||||
!.vscode/extensions.json
|
|
||||||
*.code-workspace
|
|
||||||
|
|
||||||
# Local History for Visual Studio Code
|
|
||||||
.history/
|
|
||||||
|
|
||||||
# Windows Installer files from build outputs
|
|
||||||
*.cab
|
|
||||||
*.msi
|
|
||||||
*.msix
|
|
||||||
*.msm
|
|
||||||
*.msp
|
|
||||||
|
|
||||||
# JetBrains Rider
|
|
||||||
.idea/
|
|
||||||
*.sln.iml
|
|
||||||
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 16
|
|
||||||
VisualStudioVersion = 16.0.31321.278
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FSI.Lib", "FSI.Lib\FSI.Lib.csproj", "{1394B606-4AAC-4D8D-BAF4-DB38E1FCEAAA}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{1394B606-4AAC-4D8D-BAF4-DB38E1FCEAAA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{1394B606-4AAC-4D8D-BAF4-DB38E1FCEAAA}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{1394B606-4AAC-4D8D-BAF4-DB38E1FCEAAA}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{1394B606-4AAC-4D8D-BAF4-DB38E1FCEAAA}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {0198E104-F95E-49D7-8FA5-9366011FAA9A}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Alg
|
|
||||||
{
|
|
||||||
public class Casts
|
|
||||||
{
|
|
||||||
|
|
||||||
public static dynamic Cast(dynamic obj, Type castTo)
|
|
||||||
{
|
|
||||||
return Convert.ChangeType(obj, castTo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
namespace FSI.Lib.DeEncryptString
|
|
||||||
{
|
|
||||||
public static class DeEncrypt
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts the string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="clearText">The clear text.</param>
|
|
||||||
/// <param name="Key">The key.</param>
|
|
||||||
/// <param name="IV">The IV.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static byte[] CryptString(byte[] clearText, byte[] Key, byte[] IV)
|
|
||||||
{
|
|
||||||
MemoryStream ms = new MemoryStream();
|
|
||||||
Rijndael alg = Rijndael.Create();
|
|
||||||
alg.Key = Key;
|
|
||||||
alg.IV = IV;
|
|
||||||
CryptoStream cs = new CryptoStream(ms, alg.CreateEncryptor(), CryptoStreamMode.Write);
|
|
||||||
cs.Write(clearText, 0, clearText.Length);
|
|
||||||
cs.Close();
|
|
||||||
byte[] encryptedData = ms.ToArray();
|
|
||||||
return encryptedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts the string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="clearText">The clear text.</param>
|
|
||||||
/// <param name="Password">The password.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string CryptString(string clearText, string Password)
|
|
||||||
{
|
|
||||||
byte[] clearBytes = System.Text.Encoding.Unicode.GetBytes(clearText);
|
|
||||||
PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
|
|
||||||
byte[] encryptedData = CryptString(clearBytes, pdb.GetBytes(32), pdb.GetBytes(16));
|
|
||||||
return Convert.ToBase64String(encryptedData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts the string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="cipherData">The cipher data.</param>
|
|
||||||
/// <param name="Key">The key.</param>
|
|
||||||
/// <param name="IV">The IV.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private static byte[] DecryptString(byte[] cipherData, byte[] Key, byte[] IV)
|
|
||||||
{
|
|
||||||
MemoryStream ms = new MemoryStream();
|
|
||||||
var alg = Rijndael.Create();
|
|
||||||
alg.Key = Key;
|
|
||||||
alg.IV = IV;
|
|
||||||
CryptoStream cs = new CryptoStream(ms, alg.CreateDecryptor(), CryptoStreamMode.Write);
|
|
||||||
cs.Write(cipherData, 0, cipherData.Length);
|
|
||||||
cs.Close();
|
|
||||||
byte[] decryptedData = ms.ToArray();
|
|
||||||
return decryptedData;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts the string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="cipherText">The cipher text.</param>
|
|
||||||
/// <param name="Password">The password.</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public static string DecryptString(string cipherText, string Password)
|
|
||||||
{
|
|
||||||
byte[] cipherBytes = Convert.FromBase64String(cipherText);
|
|
||||||
PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
|
|
||||||
byte[] decryptedData = DecryptString(cipherBytes, pdb.GetBytes(32), pdb.GetBytes(16));
|
|
||||||
return System.Text.Encoding.Unicode.GetString(decryptedData);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,704 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
namespace FSI.Lib.EasyEncryption
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Encryption algorithm types.
|
|
||||||
/// </summary>
|
|
||||||
public enum EncryptionAlgorithm
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies the Advanced Encryption Standard (AES) symmetric encryption algorithm.
|
|
||||||
/// </summary>
|
|
||||||
Aes,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies the Data Encryption Standard (DES) symmetric encryption algorithm.
|
|
||||||
/// </summary>
|
|
||||||
Des,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies the RC2 symmetric encryption algorithm.
|
|
||||||
/// </summary>
|
|
||||||
Rc2,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies the Rijndael symmetric encryption algorithm.
|
|
||||||
/// </summary>
|
|
||||||
Rijndael,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies the TripleDES symmetric encryption algorithm.
|
|
||||||
/// </summary>
|
|
||||||
TripleDes
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class to provide encryption and decryption services.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// <para>
|
|
||||||
/// The Encryption class performs encryption and decryption using the specified algorithm.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// The encrypted values may appear considerably larger than the decrypted values
|
|
||||||
/// because encrypted values contains some additional meta data. If either data size or
|
|
||||||
/// performance is a concern, use the <see cref="CreateStreamReader(Stream)"/> or
|
|
||||||
/// <see cref="CreateStreamWriter(Stream)"/> methods to work with the streaming classes
|
|
||||||
/// instead.
|
|
||||||
/// </para>
|
|
||||||
/// </remarks>
|
|
||||||
public class Encryption
|
|
||||||
{
|
|
||||||
private static readonly int SaltLength = 8;
|
|
||||||
|
|
||||||
private static readonly Dictionary<EncryptionAlgorithm, Type> AlgorithmLookup = new Dictionary<EncryptionAlgorithm, Type>
|
|
||||||
{
|
|
||||||
[EncryptionAlgorithm.Aes] = typeof(Aes),
|
|
||||||
[EncryptionAlgorithm.Des] = typeof(DES),
|
|
||||||
[EncryptionAlgorithm.Rc2] = typeof(RC2),
|
|
||||||
[EncryptionAlgorithm.Rijndael] = typeof(Rijndael),
|
|
||||||
[EncryptionAlgorithm.TripleDes] = typeof(TripleDES),
|
|
||||||
};
|
|
||||||
|
|
||||||
private string Password { get; }
|
|
||||||
private Type AlgorithmType { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a byte array to a string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bytes">The byte array to be converted.</param>
|
|
||||||
/// <returns>Returns the converted string.</returns>
|
|
||||||
public static string EncodeBytesToString(byte[] bytes) => Convert.ToBase64String(bytes);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Converts a string to a byte array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s">The string to be converted.</param>
|
|
||||||
/// <returns>Returns the converted byte array.</returns>
|
|
||||||
public static byte[] DecodeBytesFromString(string s) => Convert.FromBase64String(s);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a new <c>Encryption</c> instance.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="password">Specifies the encryption password. Leading and trailing spaces are removed.</param>
|
|
||||||
/// <param name="algorithm">Specifies which encryption algorithm is used.</param>
|
|
||||||
public Encryption(string password, EncryptionAlgorithm algorithm)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(password))
|
|
||||||
throw new ArgumentException("Password is required.", nameof(password));
|
|
||||||
Password = password.Trim();
|
|
||||||
AlgorithmType = AlgorithmLookup[algorithm];
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Encryption stream creation methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates an <see cref="EncryptionWriter"/> instance using the specified stream.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The <see cref="EncryptionWriter"/> class is the preferred method to encrypt data
|
|
||||||
/// as it will store some necessary meta data only once for all data in the stream.
|
|
||||||
/// It is also more performant. The other encryption methods defer to the EncryptionWriter
|
|
||||||
/// class for actual encryption.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="stream">The stream the encrypted data will be written to.</param>
|
|
||||||
/// <returns>An instance of the <see cref="EncryptionWriter"/> class.</returns>
|
|
||||||
public EncryptionWriter CreateStreamWriter(Stream stream)
|
|
||||||
{
|
|
||||||
// Create a random salt and write to stream
|
|
||||||
byte[] salt = CreateSalt();
|
|
||||||
stream.Write(salt, 0, salt.Length);
|
|
||||||
// Create symmetric algorithm
|
|
||||||
SymmetricAlgorithm algorithm = CreateAlgorithm();
|
|
||||||
algorithm.Padding = PaddingMode.PKCS7;
|
|
||||||
// Create key and IV
|
|
||||||
byte[] key, iv;
|
|
||||||
GenerateKeyAndIv(algorithm, salt, out key, out iv);
|
|
||||||
// Create EncryptionWriter
|
|
||||||
ICryptoTransform encryptor = algorithm.CreateEncryptor(key, iv);
|
|
||||||
CryptoStream cs = new CryptoStream(stream, encryptor, CryptoStreamMode.Write);
|
|
||||||
return new EncryptionWriter(algorithm, encryptor, stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates an <see cref="EncryptionWriter"/> instance using the specified file name.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The <see cref="EncryptionWriter"/> class is the preferred method to encrypt data
|
|
||||||
/// as it will store some necessary meta data only once for all data in the stream.
|
|
||||||
/// It is also more performant. The other encryption methods defer to the EncryptionWriter
|
|
||||||
/// class for actual encryption.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="path">The file name the encrypted data will be written to.</param>
|
|
||||||
/// <returns>An instance of the <see cref="EncryptionWriter"/> class.</returns>
|
|
||||||
public EncryptionWriter CreateStreamWriter(string path)
|
|
||||||
{
|
|
||||||
return CreateStreamWriter(File.Open(path, FileMode.OpenOrCreate, FileAccess.Write));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates an <see cref="EncryptionReader"/> instance using the specified stream.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The <see cref="EncryptionReader"/> class is the preferred method to decrypt data.
|
|
||||||
/// It is also more performant. The other decryption methods defer to the EncryptionReader
|
|
||||||
/// class for actual decryption.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="stream">The stream the encrypted data will be read from.</param>
|
|
||||||
/// <returns>An instance of the <see cref="EncryptionReader"/> class.</returns>
|
|
||||||
public EncryptionReader CreateStreamReader(Stream stream)
|
|
||||||
{
|
|
||||||
// Read salt from input stream
|
|
||||||
byte[] salt = new byte[SaltLength];
|
|
||||||
if (stream.Read(salt, 0, salt.Length) < SaltLength)
|
|
||||||
throw new ArgumentOutOfRangeException("Reached end of input stream before reading encryption metadata.");
|
|
||||||
// Create symmetric algorithm
|
|
||||||
SymmetricAlgorithm algorithm = CreateAlgorithm();
|
|
||||||
algorithm.Padding = PaddingMode.PKCS7;
|
|
||||||
// Create key and IV
|
|
||||||
byte[] key, iv;
|
|
||||||
GenerateKeyAndIv(algorithm, salt, out key, out iv);
|
|
||||||
// Create EncryptionReader
|
|
||||||
ICryptoTransform decryptor = algorithm.CreateDecryptor(key, iv);
|
|
||||||
CryptoStream cs = new CryptoStream(stream, decryptor, CryptoStreamMode.Read);
|
|
||||||
return new EncryptionReader(algorithm, decryptor, stream);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates an <see cref="EncryptionReader"/> instance using the specified file name.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The <see cref="EncryptionReader"/> class is the preferred method to decrypt data.
|
|
||||||
/// It is also more performant. The other decryption methods defer to the EncryptionReader
|
|
||||||
/// class for actual decryption.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="path">The file name the encrypted data will be read from.</param>
|
|
||||||
/// <returns>An instance of the <see cref="EncryptionReader"/> class.</returns>
|
|
||||||
public EncryptionReader CreateStreamReader(string path)
|
|
||||||
{
|
|
||||||
return CreateStreamReader(File.Open(path, FileMode.Open, FileAccess.Read));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Encryption
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>string</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(string value) => Encrypt(w => w.Write(value ?? string.Empty));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>bool</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(bool value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>char</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(char value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>sbyte</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(sbyte value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>byte</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(byte value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>short</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(short value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>ushort</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(ushort value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>int</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(int value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>uint</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(uint value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>long</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(long value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>ulong</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(ulong value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>float</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(float value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>double</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(double value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>decimal</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(decimal value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>DateTime</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(DateTime value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>byte[]</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(byte[] value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts a <c>string[]</c> value.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encrypted value will be larger than the unencrypted value because the
|
|
||||||
/// encrypted value will contain some additional meta data. To minimize the
|
|
||||||
/// size of this meta data when encrypting multiple values, use <see cref="CreateStreamWriter(Stream)"/>
|
|
||||||
/// to create a <see cref="EncryptionWriter"/> instead.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the encrypted value</returns>
|
|
||||||
public string Encrypt(string[] value) => Encrypt(w => w.Write(value));
|
|
||||||
|
|
||||||
private string Encrypt(Action<EncryptionWriter> action)
|
|
||||||
{
|
|
||||||
using (MemoryStream stream = new MemoryStream())
|
|
||||||
using (EncryptionWriter writer = CreateStreamWriter(stream))
|
|
||||||
{
|
|
||||||
action(writer);
|
|
||||||
return EncodeBytesToString(stream.ToArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Decryption
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>string</c> value encrypted with <see cref="Encrypt(string)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public string DecryptString(string encryptedValue) => (string)Decrypt(encryptedValue, r => r.ReadString());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>bool</c> value encrypted with <see cref="Encrypt(bool)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public bool DecryptBoolean(string encryptedValue) => (bool)Decrypt(encryptedValue, r => r.ReadBoolean());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>char</c> value encrypted with <see cref="Encrypt(char)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public char DecryptChar(string encryptedValue) => (char)Decrypt(encryptedValue, r => r.ReadChar());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>sbyte</c> value encrypted with <see cref="Encrypt(sbyte)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public sbyte DecryptSByte(string encryptedValue) => (sbyte)Decrypt(encryptedValue, r => r.ReadSByte());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>byte</c> value encrypted with <see cref="Encrypt(byte)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public byte DecryptByte(string encryptedValue) => (byte)Decrypt(encryptedValue, r => r.ReadByte());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>short</c> value encrypted with <see cref="Encrypt(short)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public short DecryptInt16(string encryptedValue) => (short)Decrypt(encryptedValue, r => r.ReadInt16());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>ushort</c> value encrypted with <see cref="Encrypt(ushort)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public ushort DecryptUInt16(string encryptedValue) => (ushort)Decrypt(encryptedValue, r => r.ReadUInt16());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>int</c> value encrypted with <see cref="Encrypt(int)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public int DecryptInt32(string encryptedValue) => (int)Decrypt(encryptedValue, r => r.ReadInt32());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>uint</c> value encrypted with <see cref="Encrypt(uint)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public uint DecryptUInt32(string encryptedValue) => (uint)Decrypt(encryptedValue, r => r.ReadUInt32());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>long</c> value encrypted with <see cref="Encrypt(long)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public long DecryptInt64(string encryptedValue) => (long)Decrypt(encryptedValue, r => r.ReadInt64());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>ulong</c> value encrypted with <see cref="Encrypt(ulong)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public ulong DecryptUInt64(string encryptedValue) => (ulong)Decrypt(encryptedValue, r => r.ReadUInt64());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>float</c> value encrypted with <see cref="Encrypt(float)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public float DecryptSingle(string encryptedValue) => (float)Decrypt(encryptedValue, r => r.ReadSingle());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>double</c> value encrypted with <see cref="Encrypt(double)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public double DecryptDouble(string encryptedValue) => (double)Decrypt(encryptedValue, r => r.ReadDouble());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>decimal</c> value encrypted with <see cref="Encrypt(decimal)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public decimal DecryptDecimal(string encryptedValue) => (decimal)Decrypt(encryptedValue, r => r.ReadDecimal());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>DateTime</c> value encrypted with <see cref="Encrypt(DateTime)"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public DateTime DecryptDateTime(string encryptedValue) => (DateTime)Decrypt(encryptedValue, r => r.ReadDateTime());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>byte[]</c> value encrypted with <see cref="Encrypt(byte[])"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public byte[] DecryptByteArray(string encryptedValue) => (byte[])Decrypt(encryptedValue, r => r.ReadByteArray());
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts a <c>string[]</c> value encrypted with <see cref="Encrypt(string[])"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The value to decrypt.</param>
|
|
||||||
/// <returns>Returns the decrypted value</returns>
|
|
||||||
public string[] DecryptStringArray(string encryptedValue) => (string[])Decrypt(encryptedValue, r => r.ReadStringArray());
|
|
||||||
|
|
||||||
private object Decrypt(string encryptedValue, Func<EncryptionReader, object> action)
|
|
||||||
{
|
|
||||||
using (MemoryStream stream = new MemoryStream(DecodeBytesFromString(encryptedValue)))
|
|
||||||
using (EncryptionReader reader = CreateStreamReader(stream))
|
|
||||||
{
|
|
||||||
return action(reader);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Encryption/decryption of objects
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class to hold encrypt/decrypt functions for each supported data type.
|
|
||||||
/// </summary>
|
|
||||||
private class TypeInfo
|
|
||||||
{
|
|
||||||
public Func<Encryption, object, string> Encrypt { get; set; }
|
|
||||||
public Func<Encryption, string, object> Decrypt { get; set; }
|
|
||||||
|
|
||||||
public TypeInfo(Func<Encryption, object, string> encrypt, Func<Encryption, string, object> decrypt)
|
|
||||||
{
|
|
||||||
Encrypt = encrypt;
|
|
||||||
Decrypt = decrypt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static readonly Dictionary<Type, TypeInfo> TypeInfoLookup = new Dictionary<Type, TypeInfo>()
|
|
||||||
{
|
|
||||||
[typeof(string)] = new TypeInfo((e, v) => e.Encrypt((string)v), (e, s) => e.DecryptString(s)),
|
|
||||||
[typeof(bool)] = new TypeInfo((e, v) => e.Encrypt((bool)v), (e, s) => e.DecryptBoolean(s)),
|
|
||||||
[typeof(char)] = new TypeInfo((e, v) => e.Encrypt((char)v), (e, s) => e.DecryptChar(s)),
|
|
||||||
[typeof(sbyte)] = new TypeInfo((e, v) => e.Encrypt((sbyte)v), (e, s) => e.DecryptSByte(s)),
|
|
||||||
[typeof(byte)] = new TypeInfo((e, v) => e.Encrypt((byte)v), (e, s) => e.DecryptByte(s)),
|
|
||||||
[typeof(short)] = new TypeInfo((e, v) => e.Encrypt((short)v), (e, s) => e.DecryptInt16(s)),
|
|
||||||
[typeof(ushort)] = new TypeInfo((e, v) => e.Encrypt((ushort)v), (e, s) => e.DecryptUInt16(s)),
|
|
||||||
[typeof(int)] = new TypeInfo((e, v) => e.Encrypt((int)v), (e, s) => e.DecryptInt32(s)),
|
|
||||||
[typeof(uint)] = new TypeInfo((e, v) => e.Encrypt((uint)v), (e, s) => e.DecryptUInt32(s)),
|
|
||||||
[typeof(long)] = new TypeInfo((e, v) => e.Encrypt((long)v), (e, s) => e.DecryptInt64(s)),
|
|
||||||
[typeof(ulong)] = new TypeInfo((e, v) => e.Encrypt((ulong)v), (e, s) => e.DecryptUInt64(s)),
|
|
||||||
[typeof(float)] = new TypeInfo((e, v) => e.Encrypt((float)v), (e, s) => e.DecryptSingle(s)),
|
|
||||||
[typeof(double)] = new TypeInfo((e, v) => e.Encrypt((double)v), (e, s) => e.DecryptDouble(s)),
|
|
||||||
[typeof(decimal)] = new TypeInfo((e, v) => e.Encrypt((decimal)v), (e, s) => e.DecryptDecimal(s)),
|
|
||||||
[typeof(DateTime)] = new TypeInfo((e, v) => e.Encrypt((DateTime)v), (e, s) => e.DecryptDateTime(s)),
|
|
||||||
[typeof(byte[])] = new TypeInfo((e, v) => e.Encrypt((byte[])v), (e, s) => e.DecryptByteArray(s)),
|
|
||||||
[typeof(string[])] = new TypeInfo((e, v) => e.Encrypt((string[])v), (e, s) => e.DecryptStringArray(s)),
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates if the specified data type is supported by the encryption and decryption methods.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// The encryption code supports all basic .NET data types in addition to <c>byte[]</c>
|
|
||||||
/// and <c>string[]</c>. More complex data types are not supported.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="type">The data type to be tested.</param>
|
|
||||||
/// <returns>True if the specified type is supported. False otherwise.</returns>
|
|
||||||
public static bool IsTypeSupported(Type type) => TypeInfoLookup.ContainsKey(type);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Encrypts an object value. The object must hold one of the supported data types.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">Object to be encrypted.</param>
|
|
||||||
/// <exception cref="ArgumentException"><paramref name="value"/> holds an unsupported data type.</exception>
|
|
||||||
/// <returns>An encrypted string that can be decrypted using Decrypt.</returns>
|
|
||||||
public string Encrypt(object value)
|
|
||||||
{
|
|
||||||
if (value == null)
|
|
||||||
return null;
|
|
||||||
if (TypeInfoLookup.TryGetValue(value.GetType(), out TypeInfo info))
|
|
||||||
return info.Encrypt(this, value);
|
|
||||||
throw new ArgumentException(string.Format("Cannot encrypt value : Data type '{0}' is not supported", value.GetType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decrypts an object value of the specified type.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="encryptedValue">The encrypted string to be decrypted.</param>
|
|
||||||
/// <param name="targetType">The type of data that was originally encrypted into <paramref name="encryptedValue"/>.</param>
|
|
||||||
/// <exception cref="ArgumentException"></exception>
|
|
||||||
/// <returns>Returns the decrypted value.</returns>
|
|
||||||
public object Decrypt(string encryptedValue, Type targetType)
|
|
||||||
{
|
|
||||||
if (TypeInfoLookup.TryGetValue(targetType, out TypeInfo info))
|
|
||||||
return info.Decrypt(this, encryptedValue);
|
|
||||||
throw new ArgumentException(string.Format("Cannot decrypt value : Data type '{0}' is not supported", targetType));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Support methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a SymmetricAlgorithm instance for the current encryption algorithm.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>
|
|
||||||
/// Returns the created SymmetricAlgorithm instance.
|
|
||||||
/// </returns>
|
|
||||||
protected SymmetricAlgorithm CreateAlgorithm()
|
|
||||||
{
|
|
||||||
MethodInfo method = AlgorithmType.GetMethod("Create", Array.Empty<Type>());
|
|
||||||
if (method != null)
|
|
||||||
{
|
|
||||||
if (method.Invoke(null, null) is SymmetricAlgorithm algorithm)
|
|
||||||
return algorithm;
|
|
||||||
}
|
|
||||||
throw new Exception($"Unable to create instance of {AlgorithmType.FullName}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates a salt that contains a cryptographically strong sequence of random values.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The generated salt value.</returns>
|
|
||||||
private byte[] CreateSalt()
|
|
||||||
{
|
|
||||||
byte[] salt = new byte[SaltLength];
|
|
||||||
using (RNGCryptoServiceProvider generator = new RNGCryptoServiceProvider())
|
|
||||||
{
|
|
||||||
generator.GetBytes(salt);
|
|
||||||
}
|
|
||||||
return salt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates a pseudorandom key and initialization vector from the current password and the
|
|
||||||
/// given salt.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="algorithm"><see cref="SymmetricAlgorithm"></see> being used to encrypt.</param>
|
|
||||||
/// <param name="salt">The salt used to derive the key and initialization vector.</param>
|
|
||||||
/// <param name="key">Returns the generated key.</param>
|
|
||||||
/// <param name="iv">Returns the generated initialization vector.</param>
|
|
||||||
protected void GenerateKeyAndIv(SymmetricAlgorithm algorithm, byte[] salt, out byte[] key, out byte[] iv)
|
|
||||||
{
|
|
||||||
int keyLength = algorithm.KeySize >> 3;
|
|
||||||
int ivLength = algorithm.BlockSize >> 3;
|
|
||||||
byte[] bytes = DeriveBytes(salt, keyLength + ivLength);
|
|
||||||
key = new byte[keyLength];
|
|
||||||
Buffer.BlockCopy(bytes, 0, key, 0, keyLength);
|
|
||||||
iv = new byte[ivLength];
|
|
||||||
Buffer.BlockCopy(bytes, keyLength, iv, 0, ivLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Generates a series of pseudorandom bytes of the specified length based on the current
|
|
||||||
/// password and the given salt.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="salt">The salt used to derive the bytes.</param>
|
|
||||||
/// <param name="bytes">The number of bits of data to generate.</param>
|
|
||||||
/// <returns>Returns the derived bytes.</returns>
|
|
||||||
protected byte[] DeriveBytes(byte[] salt, int bytes)
|
|
||||||
{
|
|
||||||
Rfc2898DeriveBytes derivedBytes = new Rfc2898DeriveBytes(Password, salt, 1000);
|
|
||||||
return derivedBytes.GetBytes(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
namespace FSI.Lib.EasyEncryption
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Class that provides streaming decryption functionality.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Using this class is the preferred way to decrypt values from a file or memory.
|
|
||||||
/// Other decryption methods defer to this class for actual decryption.
|
|
||||||
/// </remarks>
|
|
||||||
public class EncryptionReader : BinaryReader, IDisposable
|
|
||||||
{
|
|
||||||
private SymmetricAlgorithm Algorithm;
|
|
||||||
private ICryptoTransform Decryptor;
|
|
||||||
|
|
||||||
internal EncryptionReader(SymmetricAlgorithm algorithm, ICryptoTransform decryptor, Stream stream) : base(stream)
|
|
||||||
{
|
|
||||||
Algorithm = algorithm;
|
|
||||||
Decryptor = decryptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads a <c>DateTime</c> value from the encrypted stream.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The decrypted value.</returns>
|
|
||||||
public DateTime ReadDateTime()
|
|
||||||
{
|
|
||||||
return new DateTime(ReadInt64());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads a <c>byte[]</c> value from the encrypted stream.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The decrypted values.</returns>
|
|
||||||
public byte[] ReadByteArray()
|
|
||||||
{
|
|
||||||
int count = ReadInt32();
|
|
||||||
byte[] bytes = new byte[count];
|
|
||||||
if (count > 0)
|
|
||||||
Read(bytes, 0, count);
|
|
||||||
return bytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Reads a <c>string[]</c> value from the encrypted stream.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The decrypted values.</returns>
|
|
||||||
public string[] ReadStringArray()
|
|
||||||
{
|
|
||||||
int count = ReadInt32();
|
|
||||||
string[] strings = new string[count];
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
strings[i] = ReadString();
|
|
||||||
return strings;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region IDisposable implementation
|
|
||||||
|
|
||||||
private bool disposed = false; // To detect redundant calls
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases all resources used by the current instance of the <c>EncryptionReader</c> class.
|
|
||||||
/// </summary>
|
|
||||||
public new void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases the unmanaged resources used by the <c>EncryptionReader</c> class and optionally
|
|
||||||
/// releases the managed resources.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources;
|
|
||||||
/// <c>false</c> to release only unmanaged resources.</param>
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (!disposed)
|
|
||||||
{
|
|
||||||
disposed = true;
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
// Dispose managed objects
|
|
||||||
base.Dispose(true);
|
|
||||||
Decryptor.Dispose();
|
|
||||||
Algorithm.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Destructs this instance of <c>EncryptionReader</c>.
|
|
||||||
/// </summary>
|
|
||||||
~EncryptionReader()
|
|
||||||
{
|
|
||||||
Dispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
namespace FSI.Lib.EasyEncryption
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Class that provides streaming encryption functionality.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Using this class is the preferred way to encrypt values to a file or memory.
|
|
||||||
/// Other encryption methods defer to this class for actual encryption. Meta data
|
|
||||||
/// that must be stored with the encrypted result is only stored once for all
|
|
||||||
/// data in the stream.
|
|
||||||
/// </remarks>
|
|
||||||
public class EncryptionWriter : BinaryWriter, IDisposable
|
|
||||||
{
|
|
||||||
private readonly SymmetricAlgorithm Algorithm;
|
|
||||||
private readonly ICryptoTransform Encryptor;
|
|
||||||
|
|
||||||
internal EncryptionWriter(SymmetricAlgorithm algorithm, ICryptoTransform encryptor, Stream stream) : base(stream)
|
|
||||||
{
|
|
||||||
Algorithm = algorithm;
|
|
||||||
Encryptor = encryptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Writes a <c>DateTime</c> value to the encrypted stream.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"><c>DateTime</c> value to write.</param>
|
|
||||||
public void Write(DateTime value)
|
|
||||||
{
|
|
||||||
Write(value.Ticks);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Writes a <c>byte</c> array to the encrypted stream.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// Note: Hides <c>BinaryWriter.Write(byte[])</c>.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="value"><c>byte[]</c> values to write.</param>
|
|
||||||
public new void Write(byte[] value)
|
|
||||||
{
|
|
||||||
Write(value.Length);
|
|
||||||
Write(value, 0, value.Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Writes a <c>string</c> to the encrypted stream.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value"><c>string[]</c> values to write.</param>
|
|
||||||
public void Write(string[] value)
|
|
||||||
{
|
|
||||||
Write(value.Length);
|
|
||||||
for (int i = 0; i < value.Length; i++)
|
|
||||||
Write(value[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region IDisposable implementation
|
|
||||||
|
|
||||||
private bool disposed = false; // To detect redundant calls
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases all resources used by the current instance of the <c>EncryptionWriter</c> class.
|
|
||||||
/// </summary>
|
|
||||||
public new void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases the unmanaged resources used by the <c>EncryptionWriter</c> class and optionally
|
|
||||||
/// releases the managed resources.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="disposing"><c>true</c> to release both managed and unmanaged resources;
|
|
||||||
/// <c>false</c> to release only unmanaged resources.</param>
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (!disposed)
|
|
||||||
{
|
|
||||||
disposed = true;
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
// Dispose managed objects
|
|
||||||
base.Dispose(true);
|
|
||||||
Encryptor.Dispose();
|
|
||||||
Algorithm.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Destructs this instance of <c>EncryptionWriter</c>.
|
|
||||||
/// </summary>
|
|
||||||
~EncryptionWriter()
|
|
||||||
{
|
|
||||||
Dispose(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
# EasyEncryption
|
|
||||||
|
|
||||||
[](https://www.nuget.org/packages/SoftCircuits.EasyEncryption/)
|
|
||||||
|
|
||||||
```
|
|
||||||
Install-Package SoftCircuits.EasyEncryption
|
|
||||||
```
|
|
||||||
|
|
||||||
The .NET Framework provides a number of encryption routines. However, these routines generally require a bit of work to set up correctly. Use `EasyEncryption` to make these encryption routines more easily accessible.
|
|
||||||
|
|
||||||
## Encrypting a String
|
|
||||||
|
|
||||||
The `Encrypt()` method can be used to encrypt a string. Use `DecryptString()` to decrypt the string back to the original.
|
|
||||||
|
|
||||||
```cs
|
|
||||||
Encryption encrypt = new Encryption("Password123", EncryptionAlgorithm.TripleDes);
|
|
||||||
|
|
||||||
string original = "This is my message";
|
|
||||||
string cipher = encrypt.Encrypt(original);
|
|
||||||
string result = encrypt.DecryptString(cipher);
|
|
||||||
|
|
||||||
Debug.Assert(result == message);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Encrypting other Types
|
|
||||||
|
|
||||||
The `Encrypt()` method is overloaded to encrypt many different data types. When decrypting, you must use the decryption method specific to the data type you are decrypting. This example encrypts an `int` and `double` value.
|
|
||||||
|
|
||||||
```cs
|
|
||||||
Encryption encrypt = new Encryption("Password123", EncryptionAlgorithm.TripleDes);
|
|
||||||
|
|
||||||
int originalInt = 55;
|
|
||||||
double originalDouble = 123.45;
|
|
||||||
string cipherInt = encrypt.Encrypt(originalInt);
|
|
||||||
string cipherDouble = encrypt.Encrypt(originalDouble);
|
|
||||||
int resultInt = encrypt.DecryptInt32(cipherInt);
|
|
||||||
double resultDouble = encrypt.DecryptDouble(cipherDouble);
|
|
||||||
|
|
||||||
Debug.Assert(resultInt == originalInt);
|
|
||||||
Debug.Assert(resultDouble == originalDouble);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Streams
|
|
||||||
|
|
||||||
`EasyEncryption` also provides the streaming classes `EncryptionWriter` and `EncryptionReader`. These classes work well when encrypting to (or decrypting from) files.
|
|
||||||
|
|
||||||
The following example uses the `CreateStreamWriter()` to encrypt a number of integer values to a file.
|
|
||||||
|
|
||||||
```cs
|
|
||||||
Encryption encrypt = new Encryption("Password123", EncryptionAlgorithm.TripleDes);
|
|
||||||
int[] intValues = { 123, 88, 902, 27, 16, 4, 478, 54 };
|
|
||||||
|
|
||||||
using (EncryptionWriter writer = encrypt.CreateStreamWriter(path))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < intValues.Length; i++)
|
|
||||||
writer.Write(intValues[i]);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Use the `CreateStreamReader()` method to decrypt those integer values from the file.
|
|
||||||
|
|
||||||
```cs
|
|
||||||
Encryption encrypt = new Encryption("Password123", EncryptionAlgorithm.TripleDes);
|
|
||||||
int[] intValues = new int[8];
|
|
||||||
|
|
||||||
using (EncryptionReader reader = encrypt.CreateStreamReader(path))
|
|
||||||
{
|
|
||||||
for (int i = 0; i < intValues.Length; i++)
|
|
||||||
intValues[i] = reader.ReadInt32();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Also, the `CreateStreamWriter()` and `CreateStreamReader()` methods are overloaded to accept a stream argument, allowing you to use custom streams. For example, you could use a `MemoryStream` to encrypt data to memory. This is demonstrated in the following example. It also uses the static method `EncodeBytesToString()` method to convert the results to a string. (Note that there is also a corresponding static `DecodeBytesFromString()` method.)
|
|
||||||
|
|
||||||
```cs
|
|
||||||
Encryption encrypt = new Encryption("Password123", EncryptionAlgorithm.TripleDes);
|
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream())
|
|
||||||
using (EncryptionWriter writer = encrypt.CreateStreamWriter(stream))
|
|
||||||
{
|
|
||||||
writer.Write("ABC");
|
|
||||||
writer.Write(123);
|
|
||||||
writer.Write(123.45);
|
|
||||||
string s = Encryption.EncodeBytesToString(stream.ToArray());
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Note that the streaming classes are actually the most efficient way to encrypt and decrypt data. In fact the `Encrypt()` and decryption methods create an instance of `EncryptionWriter` internally (using a `MemoryStream`), even when only encrypting or decrypting a single byte.
|
|
||||||
|
|
||||||
In addition, it should be pointed out that the encrypted results produced by these routines include embedded meta data, making the encrypted data slightly larger than it would otherwise be. However, when encrypting to a stream, this data would only be stored once regardless of the number of values added to the stream. The takeaway is that you can use the `Encrypt()` method for a simple encryption, but should use the streaming classes for anything more complex.
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net472;net6.0-windows</TargetFramework>
|
|
||||||
<OutputType>Library</OutputType>
|
|
||||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
|
||||||
<UseWPF>true</UseWPF>
|
|
||||||
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
|
|
||||||
<AssemblyVersion>3.0</AssemblyVersion>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Remove="Icons\Cross.png" />
|
|
||||||
<None Remove="Icons\FondiumU.ico" />
|
|
||||||
<None Remove="Icons\Open.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<AppDesigner Include="Properties\" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<Resource Include="Icons\Cross.png" />
|
|
||||||
<Resource Include="Icons\FondiumU.ico" />
|
|
||||||
<Resource Include="Icons\Open.png" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="Guis\SieStarterCsvExporter\Convert_SINAMICS_trace_CSV.exe">
|
|
||||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
|
||||||
</None>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
<Window x:Class="FSI.Lib.Guis.AutoPw.FrmMain"
|
|
||||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:local="clr-namespace:FSI.Lib.Guis.AutoPw"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Title="Passwort eingeben"
|
|
||||||
SizeToContent="WidthAndHeight"
|
|
||||||
Height="Auto"
|
|
||||||
Width="Auto"
|
|
||||||
Icon="../../Icons/FondiumU.ico"
|
|
||||||
WindowStyle="ToolWindow">
|
|
||||||
|
|
||||||
<Grid FocusManager.FocusedElement="{Binding ElementName=TbPw}">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBlock Text="Passwort:"
|
|
||||||
Margin="5 5" />
|
|
||||||
<PasswordBox x:Name="TbPw"
|
|
||||||
Margin=" 5 5 5 5"
|
|
||||||
MinWidth="150"
|
|
||||||
PasswordChanged="TbPw_PasswordChanged"
|
|
||||||
KeyDown="TbPw_KeyDown"/>
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StackPanel Grid.Row="1"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<Button x:Name="BtnOk"
|
|
||||||
Content="Ok"
|
|
||||||
MinWidth="75"
|
|
||||||
Click="BtnOk_Click"
|
|
||||||
Margin="5 5 " />
|
|
||||||
|
|
||||||
<Button x:Name="BtnCancel"
|
|
||||||
Content="Abbruch"
|
|
||||||
MinWidth="75"
|
|
||||||
Click="BtnCancel_Click"
|
|
||||||
Margin="5 5 " />
|
|
||||||
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StatusBar Grid.Row="2">
|
|
||||||
<StatusBarItem HorizontalAlignment="Right">
|
|
||||||
<TextBlock Text="{Binding CurrentTime}" />
|
|
||||||
</StatusBarItem>
|
|
||||||
</StatusBar>
|
|
||||||
</Grid>
|
|
||||||
</Window>
|
|
||||||
@@ -1,79 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using System.Windows.Shapes;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Guis.AutoPw
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interaktionslogik für FrmMain.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class FrmMain : Window
|
|
||||||
{
|
|
||||||
public bool CloseAtLostFocus { get; set; }
|
|
||||||
public bool PwOk { get; set; }
|
|
||||||
public FrmMain()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
BtnOk.IsEnabled = false;
|
|
||||||
Deactivated += FrmMain_Deactivated;
|
|
||||||
DataContext = new MVVM.ViewModel.CurrentTimeViewModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FrmMain_Deactivated(object sender, System.EventArgs e)
|
|
||||||
{
|
|
||||||
if (CloseAtLostFocus)
|
|
||||||
Visibility = Visibility.Hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BtnOk_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BtnCancel_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
PwOk = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void TbPw_PasswordChanged(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (((PasswordBox)sender).Password.Equals(DateTime.Now.ToString("yyyyMMdd")))
|
|
||||||
{
|
|
||||||
BtnOk.IsEnabled = true;
|
|
||||||
PwOk = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BtnOk.IsEnabled = false;
|
|
||||||
PwOk = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TbPw_KeyDown(object sender, KeyEventArgs e)
|
|
||||||
{
|
|
||||||
if (BtnOk.IsEnabled == true)
|
|
||||||
{
|
|
||||||
PwOk = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PwOk = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
<Window x:Class="FSI.Lib.Guis.DeEncryptMessage.FrmMain"
|
|
||||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:local="clr-namespace:FSI.Lib.Guis.DeEncryptMessage"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Title="FSI Message Ent-/Verschlüsseln"
|
|
||||||
SizeToContent="WidthAndHeight"
|
|
||||||
Height="Auto"
|
|
||||||
Width="Auto"
|
|
||||||
Icon="../../Icons/FondiumU.ico">
|
|
||||||
|
|
||||||
<Grid MinWidth="300">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition MinHeight="100" />
|
|
||||||
<RowDefinition MinHeight="100" />
|
|
||||||
<RowDefinition MaxHeight="30"
|
|
||||||
Height="*" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<TextBox x:Name="tbInput"
|
|
||||||
TextWrapping="Wrap"
|
|
||||||
AcceptsReturn="True"
|
|
||||||
HorizontalScrollBarVisibility="Disabled"
|
|
||||||
VerticalScrollBarVisibility="Auto" />
|
|
||||||
|
|
||||||
<TextBox x:Name="tboutput"
|
|
||||||
Grid.Row="1"
|
|
||||||
AcceptsReturn="True"
|
|
||||||
HorizontalScrollBarVisibility="Disabled"
|
|
||||||
VerticalScrollBarVisibility="Auto" />
|
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal"
|
|
||||||
Grid.Row="2">
|
|
||||||
<Button x:Name="btnCrypt"
|
|
||||||
Content="verschlüsseln"
|
|
||||||
Margin="5 5 5 5 "
|
|
||||||
Click="btnCrypt_Click" />
|
|
||||||
<Button x:Name="btnDeCrypt"
|
|
||||||
Content="entschlüsseln"
|
|
||||||
Margin="5 5 5 5 "
|
|
||||||
Click="btnDeCrypt_Click" />
|
|
||||||
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StatusBar Grid.Row="3">
|
|
||||||
<StatusBarItem HorizontalAlignment="Right">
|
|
||||||
<TextBlock Text="{Binding CurrentTime}" />
|
|
||||||
</StatusBarItem>
|
|
||||||
</StatusBar>
|
|
||||||
|
|
||||||
</Grid>
|
|
||||||
</Window>
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using System.Windows.Shapes;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Guis.DeEncryptMessage
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interaktionslogik für FrmMain.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class FrmMain : Window
|
|
||||||
{
|
|
||||||
public string Password { get; set; }
|
|
||||||
public bool CloseAtLostFocus { get; set; }
|
|
||||||
public FrmMain()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
Deactivated += FrmMain_Deactivated;
|
|
||||||
DataContext = new MVVM.ViewModel.CurrentTimeViewModel();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FrmMain_Deactivated(object sender, System.EventArgs e)
|
|
||||||
{
|
|
||||||
if (CloseAtLostFocus)
|
|
||||||
Visibility = Visibility.Hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnDeCrypt_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
tboutput.Text = DeEncryptString.DeEncrypt.DecryptString(tbInput.Text, Password);
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
MessageBox.Show("Text kann nicht entschlüsselt werden!", "Achtung", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnCrypt_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
tboutput.Text = DeEncryptString.DeEncrypt.CryptString(tbInput.Text, Password);
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
MessageBox.Show("Text kann nicht verschlüsselt werden!", "Achtung", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Configuration;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Guis.Pdf.Mgt
|
|
||||||
{
|
|
||||||
public class Cmds
|
|
||||||
{
|
|
||||||
public static Task DelDirectoriesAsync(string path)
|
|
||||||
{
|
|
||||||
return Task.Factory.StartNew(() =>
|
|
||||||
{
|
|
||||||
Action<string> DelPath = null;
|
|
||||||
DelPath = p =>
|
|
||||||
{
|
|
||||||
Directory.EnumerateFiles(p).ToList().ForEach(System.IO.File.Delete); // Dateien im Verzeichnis löschen
|
|
||||||
Directory.EnumerateDirectories(p).ToList().ForEach(DelPath);
|
|
||||||
Directory.EnumerateDirectories(p).ToList().ForEach(Directory.Delete); // Verzeichnis löschen
|
|
||||||
};
|
|
||||||
|
|
||||||
if (Directory.Exists(path))
|
|
||||||
{
|
|
||||||
string[] directories = Directory.GetDirectories(path); // Alle Unterverzeichniss auslesen
|
|
||||||
|
|
||||||
foreach (string directory in directories)
|
|
||||||
{
|
|
||||||
if (!(directory.Replace(path, "")).StartsWith(".")) // Überprüfen ob Verzeichnis mit "." startet
|
|
||||||
{
|
|
||||||
DelPath(directory); // Unterverzeichnisse inkl. Dateien löschen
|
|
||||||
Directory.Delete(directory); // Verzeichnis löschen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Task DelFilesAsync(string path)
|
|
||||||
{
|
|
||||||
return Task.Factory.StartNew(() =>
|
|
||||||
{
|
|
||||||
var files = Directory.GetFiles(path);
|
|
||||||
|
|
||||||
foreach (string file in files)
|
|
||||||
{
|
|
||||||
FileInfo fileInfo = new FileInfo(file);
|
|
||||||
|
|
||||||
const int STR_LENGTH = 27; // min. Dateinamen Länge (Zahlen inkl. Bindestriche)
|
|
||||||
|
|
||||||
if (!fileInfo.Name.StartsWith(".")) // Überprüfen ob Datei mit "." startet
|
|
||||||
{
|
|
||||||
if (fileInfo.Extension != ".pdf" || fileInfo.Name.Length <= STR_LENGTH) // Überprüfen ob es sich um eine PDF-Datei handelt
|
|
||||||
{
|
|
||||||
System.IO.File.Delete(fileInfo.FullName); // ... wenn nicht Datei löschen
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string[] fileStrings = fileInfo.Name.Substring(0, STR_LENGTH - 1).Split('-'); // Zahlenblock splitten für Überprüfung
|
|
||||||
|
|
||||||
if (fileStrings.Length == 3) // 3 Zahlenblöcke vorhanden?
|
|
||||||
{
|
|
||||||
if (fileStrings[0].Length != 10 || !Int64.TryParse(fileStrings[0], out _) || fileStrings[1].Length != 10 || !Int64.TryParse(fileStrings[1], out _) || fileStrings[2].Length != 4 || !Int64.TryParse(fileStrings[2], out _)) // Länge der Zahlenblöcke überprüfen
|
|
||||||
{
|
|
||||||
System.IO.File.Delete(fileInfo.FullName); // ..., wenn Länge nicht passt, Datei löschen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
System.IO.File.Delete(fileInfo.FullName); // ..., wenn nicht Datei löschen
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Task CreatePdfShortcutsAsync(string path)
|
|
||||||
{
|
|
||||||
return Task.Factory.StartNew(() =>
|
|
||||||
{
|
|
||||||
var files = Directory.GetFiles(path, "*.pdf"); // alle PDF-Dateien einlesen
|
|
||||||
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
FileInfo fileInfo = new FileInfo(file);
|
|
||||||
|
|
||||||
string[] fileStrings = System.IO.Path.GetFileNameWithoutExtension(fileInfo.Name).Split(' '); // Datei-Namen für Verzeichnis Bezeichnung aufteilen
|
|
||||||
|
|
||||||
string tmpPath = path + fileStrings[1] + " " + fileStrings[2]; // Verzeichnis Bezeichnung zusammenstellen
|
|
||||||
|
|
||||||
if (Convert.ToBoolean(ConfigurationManager.AppSettings["SubDir"])) // mit/ohne Unterverzeichnis
|
|
||||||
{
|
|
||||||
tmpPath = path + fileStrings[1] + @"\" + fileStrings[2]; // mit Unterverzeichnis
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tmpPath = path + fileStrings[1] + " " + fileStrings[2]; // ohne Unterverzeichnis
|
|
||||||
}
|
|
||||||
|
|
||||||
Directory.CreateDirectory(tmpPath); // Verzeichnis erstellen
|
|
||||||
|
|
||||||
// Shortcut erstellen
|
|
||||||
if (Convert.ToBoolean(ConfigurationManager.AppSettings["WithNo"]))
|
|
||||||
{
|
|
||||||
LnkParser.ShortCut.Create(System.IO.Path.GetFileNameWithoutExtension(tmpPath + "\\" + fileInfo.Name), tmpPath, fileInfo.FullName, System.IO.Path.GetFileNameWithoutExtension(fileInfo.FullName));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LnkParser.ShortCut.Create(System.IO.Path.GetFileNameWithoutExtension(fileInfo.Name.Replace(fileStrings[0], "")), tmpPath, fileInfo.FullName, System.IO.Path.GetFileNameWithoutExtension(fileInfo.FullName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
<Window x:Class="FSI.Lib.Guis.Pdf.Mgt.FrmMain"
|
|
||||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:local="clr-namespace:FSI.Lib.Guis.Pdf.Mgt"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Title="FSI Eplan PDF Mgt"
|
|
||||||
SizeToContent="WidthAndHeight"
|
|
||||||
Height="Auto"
|
|
||||||
Width="Auto"
|
|
||||||
Icon="../../Icons/FondiumU.ico"
|
|
||||||
WindowStyle="ToolWindow">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition MaxHeight="30"
|
|
||||||
Height="*" />
|
|
||||||
<RowDefinition />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<Button x:Name="btnCleanUp"
|
|
||||||
Content="aufräumen"
|
|
||||||
Margin="5 5 5 5 "
|
|
||||||
Click="btnCleanUp_Click" />
|
|
||||||
<Button x:Name="btnCreateShortcuts"
|
|
||||||
Content="Verknüpfungen erstellen"
|
|
||||||
Margin="5 5 5 5 "
|
|
||||||
Click="btnCreateShortcuts_Click" />
|
|
||||||
<Button x:Name="btnStart"
|
|
||||||
Content="alles ausführen"
|
|
||||||
Margin="5 5 5 5 "
|
|
||||||
Click="btnStart_Click" />
|
|
||||||
</StackPanel>
|
|
||||||
<StatusBar Grid.Row="2">
|
|
||||||
<StatusBar.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="4*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
</Grid>
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</StatusBar.ItemsPanel>
|
|
||||||
<StatusBarItem>
|
|
||||||
<TextBlock x:Name="tbStatus" />
|
|
||||||
</StatusBarItem>
|
|
||||||
<StatusBarItem Grid.Column="1">
|
|
||||||
<ProgressBar x:Name="pgProgress"
|
|
||||||
Width="80"
|
|
||||||
Height="18" />
|
|
||||||
</StatusBarItem>
|
|
||||||
|
|
||||||
|
|
||||||
<StatusBarItem HorizontalAlignment="Right">
|
|
||||||
<TextBlock Text="{Binding CurrentTime}" />
|
|
||||||
</StatusBarItem>
|
|
||||||
|
|
||||||
|
|
||||||
</StatusBar>
|
|
||||||
</Grid>
|
|
||||||
</Window>
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
using System.Configuration;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Windows;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Guis.Pdf.Mgt
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interaktionslogik für FrmMain.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class FrmMain : Window
|
|
||||||
{
|
|
||||||
public bool CloseAtLostFocus { get; set; }
|
|
||||||
|
|
||||||
public FrmMain()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
DataContext = new MVVM.ViewModel.CurrentTimeViewModel();
|
|
||||||
Title += " v" + Assembly.GetExecutingAssembly().GetName().Version; // Version in Titel eintragen
|
|
||||||
Deactivated += FrmMain_Deactivated;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FrmMain_Deactivated(object sender, System.EventArgs e)
|
|
||||||
{
|
|
||||||
if (CloseAtLostFocus)
|
|
||||||
Visibility = Visibility.Hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void btnCleanUp_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
BtnMgt(false); // Schaltflächen sperren
|
|
||||||
|
|
||||||
await Cmds.DelDirectoriesAsync(ConfigurationManager.AppSettings["PdfPath"]); // nicht benötigte/zulässige Verzeichnisse löschen
|
|
||||||
await Cmds.DelFilesAsync(ConfigurationManager.AppSettings["PdfPath"]); // nicht benötigte/zulässige Datien löschen
|
|
||||||
BtnMgt(true); // Schaltflächen freigeben
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void btnCreateShortcuts_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
BtnMgt(false); // Schaltflächen sperren
|
|
||||||
await Cmds.CreatePdfShortcutsAsync(ConfigurationManager.AppSettings["PdfPath"]); // Verzeichnisstruktur und Verknüpfungen erstellen
|
|
||||||
BtnMgt(true); // Schaltflächen freigeben
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void btnStart_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
BtnMgt(false); // Schaltflächen sperren
|
|
||||||
await Cmds.DelDirectoriesAsync(ConfigurationManager.AppSettings["PdfPath"]); // nicht benötigte/zulässige Verzeichnisse löschen
|
|
||||||
await Cmds.DelFilesAsync(ConfigurationManager.AppSettings["PdfPath"]); // nicht benötigte/zulässige Datien lösche
|
|
||||||
await Cmds.CreatePdfShortcutsAsync(ConfigurationManager.AppSettings["PdfPath"]); // Verzeichnisstruktur und Verknüpfungen erstellen
|
|
||||||
BtnMgt(true); // Schaltflächen freigeben
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BtnMgt(bool enable)
|
|
||||||
{
|
|
||||||
btnCleanUp.IsEnabled =
|
|
||||||
btnCreateShortcuts.IsEnabled =
|
|
||||||
btnStart.IsEnabled = enable;
|
|
||||||
pgProgress.IsIndeterminate = !enable;
|
|
||||||
|
|
||||||
// Status anzeige
|
|
||||||
if (enable)
|
|
||||||
{
|
|
||||||
tbStatus.Text = "beendet";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
tbStatus.Text = "gestartet";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
<Window x:Class="FSI.Lib.Guis.Prj.Mgt.FrmMain"
|
|
||||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:diagnostics="clr-namespace:System.Diagnostics;assembly=WindowsBase"
|
|
||||||
xmlns:local="clr-namespace:FSI.Lib.Guis.Prj.Mgt"
|
|
||||||
xmlns:control="clr-namespace:FSI.Lib.Wpf.Ctrls.FilterDataGrid"
|
|
||||||
xmlns:viewmodel="clr-namespace:FSI.Lib.Guis.Prj.Mgt.ViewModel"
|
|
||||||
d:DataContext="{d:DesignInstance Type=viewmodel:ViewModelPrj}"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
SizeToContent="Width"
|
|
||||||
Height="800"
|
|
||||||
Width="Auto"
|
|
||||||
Icon="../../Icons/FondiumU.ico">
|
|
||||||
|
|
||||||
<Window.Resources>
|
|
||||||
<ObjectDataProvider x:Key="PrjsFiltered"></ObjectDataProvider>
|
|
||||||
</Window.Resources>
|
|
||||||
|
|
||||||
<Window.InputBindings>
|
|
||||||
<KeyBinding Command="{Binding CmdOpen}"
|
|
||||||
Gesture="CTRL+o" />
|
|
||||||
</Window.InputBindings>
|
|
||||||
|
|
||||||
<Grid FocusManager.FocusedElement="{Binding ElementName=tbSearch}">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<Grid Grid.Row="0"
|
|
||||||
Margin="0,10"
|
|
||||||
HorizontalAlignment="Stretch">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="2*" />
|
|
||||||
<ColumnDefinition Width="1*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<StackPanel Grid.Column="0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<Label Margin="0,0,20,0"
|
|
||||||
VerticalAlignment="Bottom"
|
|
||||||
Content="Suche:"
|
|
||||||
FontWeight="Bold" />
|
|
||||||
<TextBox Name="tbSearch"
|
|
||||||
Height="26"
|
|
||||||
MinWidth="200"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
VerticalContentAlignment="Center"
|
|
||||||
Text="{Binding Search, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
|
||||||
TextChanged="tbSearch_TextChanged" />
|
|
||||||
<Button Width="Auto"
|
|
||||||
Margin="5,0,0,0"
|
|
||||||
Padding="4"
|
|
||||||
Command="{Binding RefreshCommand}"
|
|
||||||
ToolTip="Filter löschen"
|
|
||||||
Cursor="Hand">
|
|
||||||
<Image Source="../../Icons/Cross.png"
|
|
||||||
Height="14" />
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
|
||||||
<StackPanel Grid.Column="2"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Orientation="Horizontal">
|
|
||||||
<Button Width="Auto"
|
|
||||||
Margin="0 0 20 0"
|
|
||||||
Padding="4"
|
|
||||||
ToolTip="öffen"
|
|
||||||
Command="{Binding CmdOpen}"
|
|
||||||
IsEnabled="{Binding CanExecuteOpen}"
|
|
||||||
Cursor="Hand">
|
|
||||||
<Image Source="../../Icons/Open.png"
|
|
||||||
Height="14" />
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<StackPanel Grid.Row="1"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Orientation="Horizontal"
|
|
||||||
Margin="0,5">
|
|
||||||
<Label Margin="0,0,20,0"
|
|
||||||
VerticalAlignment="Bottom"
|
|
||||||
Content="Quick-Filter:"
|
|
||||||
FontWeight="Bold" />
|
|
||||||
<Button Width="Auto"
|
|
||||||
Margin="5,0,0,0"
|
|
||||||
Padding="4"
|
|
||||||
ToolTip="Filter löschen"
|
|
||||||
Command="{Binding RefreshCommand}"
|
|
||||||
Cursor="Hand">
|
|
||||||
<Image Source="../../Icons/Cross.png"
|
|
||||||
Height="14" />
|
|
||||||
</Button>
|
|
||||||
<Button Content="PL1"
|
|
||||||
Width="Auto"
|
|
||||||
Margin="10,0,0,0"
|
|
||||||
ToolTip="Filter auf PL1"
|
|
||||||
Command="{Binding CmdQuickSearch}"
|
|
||||||
CommandParameter="PL1"
|
|
||||||
FocusManager.FocusedElement="{Binding ElementName=tbSearch}" />
|
|
||||||
<Button Content="PL2"
|
|
||||||
Width="Auto"
|
|
||||||
Margin="10,0,0,0"
|
|
||||||
ToolTip="Filter auf PL2"
|
|
||||||
Command="{Binding CmdQuickSearch}"
|
|
||||||
CommandParameter="PL2"
|
|
||||||
FocusManager.FocusedElement="{Binding ElementName=tbSearch}" />
|
|
||||||
<Button Content="PL3"
|
|
||||||
Width="Auto"
|
|
||||||
Margin="10,0,0,0"
|
|
||||||
ToolTip="Filter auf PL3"
|
|
||||||
Command="{Binding CmdQuickSearch}"
|
|
||||||
CommandParameter="PL3"
|
|
||||||
FocusManager.FocusedElement="{Binding ElementName=tbSearch}" />
|
|
||||||
<Button Content="SMZ"
|
|
||||||
Width="Auto"
|
|
||||||
Margin="10,0,0,0"
|
|
||||||
ToolTip="Filter auf SMZ"
|
|
||||||
Command="{Binding CmdQuickSearch}"
|
|
||||||
CommandParameter="SMZ"
|
|
||||||
FocusManager.FocusedElement="{Binding ElementName=tbSearch}" />
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<control:FilterDataGrid x:Name="FilterDataGrid"
|
|
||||||
Grid.Row="2"
|
|
||||||
AutoGenerateColumns="False"
|
|
||||||
DateFormatString="d"
|
|
||||||
FilterLanguage="German"
|
|
||||||
ItemsSource="{Binding PrjsFiltered, UpdateSourceTrigger=PropertyChanged}"
|
|
||||||
SelectionMode="Single"
|
|
||||||
SelectedItem="{Binding SeletctedPrj, UpdateSourceTrigger=PropertyChanged}"
|
|
||||||
ShowElapsedTime="false"
|
|
||||||
ShowRowsCount="True"
|
|
||||||
ShowStatusBar="True">
|
|
||||||
|
|
||||||
<control:FilterDataGrid.InputBindings>
|
|
||||||
<MouseBinding MouseAction="LeftDoubleClick"
|
|
||||||
Command="{Binding CmdOpen}" />
|
|
||||||
|
|
||||||
</control:FilterDataGrid.InputBindings>
|
|
||||||
<control:FilterDataGrid.Columns>
|
|
||||||
|
|
||||||
<control:DataGridTemplateColumn FieldName="PlantNo"
|
|
||||||
Header="Anlagen-Nr."
|
|
||||||
IsColumnFiltered="True"
|
|
||||||
SortMemberPath="PlantNo">
|
|
||||||
<control:DataGridTemplateColumn.CellTemplate>
|
|
||||||
<DataTemplate DataType="local:Prj">
|
|
||||||
<TextBlock Text="{Binding PlantNo}" />
|
|
||||||
</DataTemplate>
|
|
||||||
</control:DataGridTemplateColumn.CellTemplate>
|
|
||||||
</control:DataGridTemplateColumn>
|
|
||||||
|
|
||||||
<control:DataGridTextColumn Binding="{Binding SubPlantNo}"
|
|
||||||
Header="Teilanlagen-Nr."
|
|
||||||
IsReadOnly="True"
|
|
||||||
IsColumnFiltered="True" />
|
|
||||||
|
|
||||||
<control:DataGridTextColumn Binding="{Binding No, StringFormat={}{0:0000}}"
|
|
||||||
Header="Lfd.-Nr."
|
|
||||||
IsReadOnly="True"
|
|
||||||
IsColumnFiltered="True" />
|
|
||||||
|
|
||||||
<control:DataGridTextColumn Binding="{Binding Plant}"
|
|
||||||
Header="Anlage"
|
|
||||||
IsReadOnly="True"
|
|
||||||
IsColumnFiltered="True" />
|
|
||||||
|
|
||||||
<control:DataGridTextColumn Binding="{Binding SubPlant}"
|
|
||||||
Header="Teilanlage"
|
|
||||||
IsReadOnly="True"
|
|
||||||
IsColumnFiltered="True" />
|
|
||||||
|
|
||||||
<control:DataGridTextColumn Binding="{Binding Description}"
|
|
||||||
Header="Bezeichnung"
|
|
||||||
IsReadOnly="True"
|
|
||||||
IsColumnFiltered="True" />
|
|
||||||
</control:FilterDataGrid.Columns>
|
|
||||||
</control:FilterDataGrid>
|
|
||||||
</Grid>
|
|
||||||
</Window>
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
using FSI.Lib.Guis.Prj.Mgt.ViewModel;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Guis.Prj.Mgt
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interaktionslogik für Main.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class FrmMain : Window
|
|
||||||
{
|
|
||||||
public ViewModelPrj Prj { get; set; }
|
|
||||||
public bool ShowPdf { get; set; }
|
|
||||||
public bool CloseAtLostFocus { get; set; }
|
|
||||||
public string Path { get; set; }
|
|
||||||
public string[] EplExes { get; set; }
|
|
||||||
|
|
||||||
public FrmMain()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
Loaded += Main_Loaded;
|
|
||||||
Deactivated += FrmMain_Deactivated;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void FrmMain_Deactivated(object sender, System.EventArgs e)
|
|
||||||
{
|
|
||||||
if (CloseAtLostFocus)
|
|
||||||
Visibility = Visibility.Hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Main_Loaded(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
if (ShowPdf)
|
|
||||||
{
|
|
||||||
Title = "FSI PDF-Auswahl";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Title = "FSI Epl Projektauswahl";
|
|
||||||
}
|
|
||||||
|
|
||||||
Title += " v" + Assembly.GetExecutingAssembly().GetName().Version; // Version in Titel eintragen
|
|
||||||
|
|
||||||
Prj = new ViewModelPrj(new PrjDataProvider())
|
|
||||||
{
|
|
||||||
DataPath = Path,
|
|
||||||
ShowPdf = ShowPdf,
|
|
||||||
EplExes = EplExes,
|
|
||||||
};
|
|
||||||
DataContext = Prj;
|
|
||||||
|
|
||||||
Prj.Load();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void tbSearch_TextChanged(object sender, TextChangedEventArgs e)
|
|
||||||
{
|
|
||||||
tbSearch.Select(tbSearch.Text.Length, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Guis.Prj.Mgt.Model
|
|
||||||
{
|
|
||||||
public class Prj
|
|
||||||
{
|
|
||||||
public Int64 PlantNo { get; set; }
|
|
||||||
public Int64 SubPlantNo { get; set; }
|
|
||||||
public Int64 No { get; set; }
|
|
||||||
public string Plant { get; set; }
|
|
||||||
public string SubPlant { get; set; }
|
|
||||||
public string Description { get; set; }
|
|
||||||
public string DescriptionDetail { get; set; }
|
|
||||||
public string FullName { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public interface IPrjDataProvider
|
|
||||||
{
|
|
||||||
IEnumerable<Prj> Load(string path, bool showPdf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,208 +0,0 @@
|
|||||||
using FSI.Lib.Guis.Prj.Mgt.Model;
|
|
||||||
using FSI.Lib.MVVM;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Configuration;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Input;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Guis.Prj.Mgt.ViewModel
|
|
||||||
{
|
|
||||||
public class ViewModelPrj : MVVM.ViewModelBase
|
|
||||||
{
|
|
||||||
readonly IPrjDataProvider _prjDataProvider;
|
|
||||||
private string _search;
|
|
||||||
private ICollectionView _collView;
|
|
||||||
|
|
||||||
public ICommand RefreshCommand => new DelegateCommand(RefreshData);
|
|
||||||
private ICommand _cmdQuickSearch;
|
|
||||||
private ICommand _cmdOpen;
|
|
||||||
|
|
||||||
public ViewModelPrj(IPrjDataProvider prjDataProvider)
|
|
||||||
{
|
|
||||||
Prjs = new ObservableCollection<Model.Prj>();
|
|
||||||
_prjDataProvider = prjDataProvider;
|
|
||||||
|
|
||||||
_cmdQuickSearch = new RelayCommand<object>(ExecuteQuickSearch, CanExecuteQuickSearch);
|
|
||||||
_cmdOpen = new RelayCommand<object>(ExecuteOpen, CanExecuteOpen);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableCollection<Model.Prj> Prjs { get; }
|
|
||||||
public ObservableCollection<Model.Prj> PrjsFiltered { get; set; }
|
|
||||||
|
|
||||||
public Model.Prj SeletctedPrj { get; set; }
|
|
||||||
|
|
||||||
public string DataPath { get; set; }
|
|
||||||
|
|
||||||
public bool ShowPdf { get; set; }
|
|
||||||
public string[] EplExes { get; set; }
|
|
||||||
|
|
||||||
public void Load()
|
|
||||||
{
|
|
||||||
var prjs = _prjDataProvider.Load(DataPath, ShowPdf);
|
|
||||||
Prjs.Clear();
|
|
||||||
|
|
||||||
if (prjs != null)
|
|
||||||
{
|
|
||||||
foreach (Model.Prj prj in prjs)
|
|
||||||
{
|
|
||||||
Prjs.Add(prj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PrjsFiltered = new ObservableCollection<Model.Prj>(Prjs);
|
|
||||||
_collView = CollectionViewSource.GetDefaultView(PrjsFiltered);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Search
|
|
||||||
{
|
|
||||||
get => _search;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_search = value;
|
|
||||||
|
|
||||||
_collView.Filter = e =>
|
|
||||||
{
|
|
||||||
var item = (Model.Prj)e;
|
|
||||||
return item != null && ((item.Plant?.StartsWith(_search, StringComparison.OrdinalIgnoreCase) ?? false)
|
|
||||||
|| (item.SubPlant?.StartsWith(_search, StringComparison.OrdinalIgnoreCase) ?? false)
|
|
||||||
#if NET472
|
|
||||||
|| (item.Description?.Contains(_search) ?? false)
|
|
||||||
|| (item.DescriptionDetail?.Contains(_search) ?? false)
|
|
||||||
#elif NET6_0
|
|
||||||
|| (item.Description?.Contains(_search, StringComparison.OrdinalIgnoreCase) ?? false)
|
|
||||||
|| (item.DescriptionDetail?.Contains(_search, StringComparison.OrdinalIgnoreCase) ?? false)
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
_collView.Refresh();
|
|
||||||
PrjsFiltered = new ObservableCollection<Model.Prj>(_collView.OfType<Model.Prj>().ToList());
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void QuickSearch(string search)
|
|
||||||
{
|
|
||||||
Search = search + " ";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RefreshData(object obj)
|
|
||||||
{
|
|
||||||
Search = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CanExecuteQuickSearch(object obj)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExecuteQuickSearch(object obj)
|
|
||||||
{
|
|
||||||
QuickSearch(obj.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
public ICommand CmdQuickSearch
|
|
||||||
{
|
|
||||||
get { return _cmdQuickSearch; }
|
|
||||||
set => _cmdQuickSearch = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CanExecuteOpen(object obj)
|
|
||||||
{
|
|
||||||
if (SeletctedPrj != null)
|
|
||||||
return true;
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExecuteOpen(object obj)
|
|
||||||
{
|
|
||||||
if (ShowPdf)
|
|
||||||
{
|
|
||||||
new Process
|
|
||||||
{
|
|
||||||
StartInfo = new ProcessStartInfo(SeletctedPrj.FullName)
|
|
||||||
{
|
|
||||||
UseShellExecute = true
|
|
||||||
}
|
|
||||||
}.Start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var arguments = " /Variant:\"Electric P8\" ProjectOpen /Project:\"" + SeletctedPrj.FullName + "\"";
|
|
||||||
|
|
||||||
string fileName = string.Empty;
|
|
||||||
string path = string.Empty;
|
|
||||||
|
|
||||||
for (int i = 0; i <= EplExes.Length - 1; i++)
|
|
||||||
{
|
|
||||||
if (File.Exists(EplExes[i].Trim()))
|
|
||||||
{
|
|
||||||
fileName = EplExes[i].Trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
new Process
|
|
||||||
{
|
|
||||||
StartInfo = new ProcessStartInfo()
|
|
||||||
{
|
|
||||||
FileName = fileName,
|
|
||||||
Arguments = arguments,
|
|
||||||
}
|
|
||||||
}.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ICommand CmdOpen
|
|
||||||
{
|
|
||||||
get { return _cmdOpen; }
|
|
||||||
set => _cmdOpen = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PrjDataProvider : IPrjDataProvider
|
|
||||||
{
|
|
||||||
public IEnumerable<Model.Prj> Load(string path, bool showPdf)
|
|
||||||
{
|
|
||||||
var prjs = new ObservableCollection<Model.Prj>();
|
|
||||||
string[] files = Directory.GetFiles(path); // alle PDF-Dateien einlesen
|
|
||||||
|
|
||||||
foreach (var file in files)
|
|
||||||
{
|
|
||||||
if (((file.EndsWith(".elk") || file.EndsWith(".elp") || file.EndsWith(".els") || file.EndsWith(".elx") || file.EndsWith(".elr") || file.EndsWith(".ell") || file.EndsWith(".elf"))
|
|
||||||
&& !showPdf) || (file.EndsWith(".pdf") && showPdf))
|
|
||||||
{
|
|
||||||
Model.Prj prj = new();
|
|
||||||
FileInfo fileInfo = new(file);
|
|
||||||
string[] nameNo = fileInfo.Name[..(27 - 1)].Split('-');
|
|
||||||
|
|
||||||
if (nameNo.Length == 3) // 3 Zahlenblöcke vorhanden?
|
|
||||||
{
|
|
||||||
if (nameNo[0].Length == 10 || Int64.TryParse(nameNo[0], out _) || nameNo[1].Length == 10 || Int64.TryParse(nameNo[1], out _) || nameNo[2].Length == 4 || !Int64.TryParse(nameNo[2], out _)) // Länge der Zahlenblöcke überprüfen
|
|
||||||
{
|
|
||||||
prj.PlantNo = Int64.Parse(nameNo[0]);
|
|
||||||
prj.SubPlantNo = Int64.Parse(nameNo[1]);
|
|
||||||
prj.No = Int64.Parse(nameNo[2]);
|
|
||||||
|
|
||||||
string[] fileStrings = System.IO.Path.GetFileNameWithoutExtension(fileInfo.Name).Split(' ');
|
|
||||||
prj.Plant = fileStrings[1];
|
|
||||||
prj.SubPlant = fileStrings[2];
|
|
||||||
prj.Description = System.IO.Path.GetFileNameWithoutExtension(fileInfo.Name).Replace(nameNo[0] + "-" + nameNo[1] + "-" + nameNo[2] + " " + fileStrings[1] + " " + fileStrings[2], "");
|
|
||||||
prj.Description = prj.Description.Trim();
|
|
||||||
prj.DescriptionDetail = prj.Plant + " " + prj.SubPlant + " " + prj.Description;
|
|
||||||
prj.FullName = fileInfo.FullName;
|
|
||||||
prjs.Add(prj);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return prjs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
@@ -1,54 +0,0 @@
|
|||||||
<Window x:Class="FSI.Lib.Guis.SieStarterCsvExporter.FrmMain"
|
|
||||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Title="FSI Siemens Starter Trace Csv-Exporter"
|
|
||||||
SizeToContent="WidthAndHeight"
|
|
||||||
Height="Auto"
|
|
||||||
Width="Auto"
|
|
||||||
Icon="../../Icons/FondiumU.ico"
|
|
||||||
WindowStyle="ToolWindow">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<TextBlock Text="Datei:"
|
|
||||||
Margin="5 5 5 5" />
|
|
||||||
<TextBox x:Name="tbSrcFile"
|
|
||||||
Width="600"
|
|
||||||
Margin="5 5 5 5"
|
|
||||||
AllowDrop="True"
|
|
||||||
TextChanged="TbSrcFile_TextChanged"
|
|
||||||
PreviewDragEnter="TbSrcFile_PreviewDragEnter"
|
|
||||||
PreviewDragOver="TbSrcFile_PreviewDragOver"
|
|
||||||
Drop="TbSrcFile_Drop" />
|
|
||||||
|
|
||||||
<Button x:Name="btnSlctSrcFile"
|
|
||||||
Content="..."
|
|
||||||
Width="30"
|
|
||||||
Margin="5 5 5 5"
|
|
||||||
Click="BtnSlctSrcFile_Click" />
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StackPanel Grid.Row="1">
|
|
||||||
<Button x:Name="btnStart"
|
|
||||||
Content="Start"
|
|
||||||
Margin="5 5 5 5"
|
|
||||||
IsEnabled="False"
|
|
||||||
Click="BtnStart_Click" />
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StatusBar Grid.Row="2">
|
|
||||||
<StatusBarItem HorizontalAlignment="Right">
|
|
||||||
<TextBlock Text="{Binding CurrentTime}" />
|
|
||||||
</StatusBarItem>
|
|
||||||
</StatusBar>
|
|
||||||
|
|
||||||
</Grid>
|
|
||||||
</Window>
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
using Microsoft.Win32;
|
|
||||||
using System.Collections.Specialized;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Text;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Guis.SieStarterCsvExporter
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interaktionslogik für frmMain.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class FrmMain : Window
|
|
||||||
{
|
|
||||||
public FrmMain()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
DataContext = new MVVM.ViewModel.CurrentTimeViewModel();
|
|
||||||
}
|
|
||||||
private void BtnSlctSrcFile_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
OpenFileDialog dlg = new()
|
|
||||||
{
|
|
||||||
Filter = "Trace (*.trc)|*.trc|alle Dateien (*:*)|*.*"
|
|
||||||
};
|
|
||||||
|
|
||||||
if ((bool)dlg.ShowDialog())
|
|
||||||
{
|
|
||||||
tbSrcFile.Text = dlg.FileName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BtnStart_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
string[] tbEntries = tbSrcFile.Text.Split("\n");
|
|
||||||
|
|
||||||
string test = GetType().Namespace;
|
|
||||||
|
|
||||||
var test2 = Assembly.GetExecutingAssembly;
|
|
||||||
|
|
||||||
|
|
||||||
foreach (string tbEntry in tbEntries)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(tbEntry))
|
|
||||||
{
|
|
||||||
Process process= new Process();
|
|
||||||
process.StartInfo.FileName = Directory.GetCurrentDirectory() + @"\Guis\SieStarterCsvExporter\" + "Convert_SINAMICS_trace_CSV.exe";
|
|
||||||
process.StartInfo.Arguments = "\"" + tbEntry + "\"";
|
|
||||||
|
|
||||||
process.Start();
|
|
||||||
process.WaitForExit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tbSrcFile.Text = string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TbSrcFile_PreviewDragEnter(object sender, System.Windows.DragEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.Data.GetDataPresent(System.Windows.DataFormats.FileDrop))
|
|
||||||
{
|
|
||||||
e.Effects = System.Windows.DragDropEffects.Copy;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
e.Effects = System.Windows.DragDropEffects.None;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TbSrcFile_PreviewDragOver(object sender, System.Windows.DragEventArgs e)
|
|
||||||
{
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TbSrcFile_Drop(object sender, System.Windows.DragEventArgs e)
|
|
||||||
{
|
|
||||||
// Get data object
|
|
||||||
var dataObject = e.Data as System.Windows.DataObject;
|
|
||||||
|
|
||||||
// Check for file list
|
|
||||||
if (dataObject.ContainsFileDropList())
|
|
||||||
{
|
|
||||||
// Clear values
|
|
||||||
tbSrcFile.Text = string.Empty;
|
|
||||||
|
|
||||||
// Process file names
|
|
||||||
StringCollection fileNames = dataObject.GetFileDropList();
|
|
||||||
StringBuilder bd = new();
|
|
||||||
foreach (string fileName in fileNames)
|
|
||||||
{
|
|
||||||
if (fileName.EndsWith(".trc"))
|
|
||||||
{
|
|
||||||
bd.Append(fileName + "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set text
|
|
||||||
tbSrcFile.Text = bd.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TbSrcFile_TextChanged(object sender, TextChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(tbSrcFile.Text))
|
|
||||||
{
|
|
||||||
btnStart.IsEnabled = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
btnStart.IsEnabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
<Window x:Class="FSI.Lib.Guis.SieTiaWinCCMsgMgt.FrmMain"
|
|
||||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:local="clr-namespace:FSI.Lib.Guis.SieTiaWinCCMsgMgt"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Title="FSI WinCC Mgt"
|
|
||||||
SizeToContent="WidthAndHeight"
|
|
||||||
Height="Auto"
|
|
||||||
Width="Auto"
|
|
||||||
MinWidth="200"
|
|
||||||
Icon="../../Icons/FondiumU.ico"
|
|
||||||
WindowStyle="ToolWindow">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition MaxHeight="30"
|
|
||||||
Height="*" />
|
|
||||||
<RowDefinition />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<Button x:Name="btnStart"
|
|
||||||
Content="Start"
|
|
||||||
Margin="5 5 5 5 "
|
|
||||||
Click="btnStart_Click" />
|
|
||||||
<Button x:Name="btnStop"
|
|
||||||
Content="Stop"
|
|
||||||
Margin="5 5 5 5 "
|
|
||||||
Click="btnStop_Click" />
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<StatusBar Grid.Row="2">
|
|
||||||
<StatusBar.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="4*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
</Grid>
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</StatusBar.ItemsPanel>
|
|
||||||
<StatusBarItem>
|
|
||||||
<TextBlock x:Name="tbStatus" />
|
|
||||||
</StatusBarItem>
|
|
||||||
<StatusBarItem Grid.Column="1">
|
|
||||||
<ProgressBar x:Name="pgProgress"
|
|
||||||
Width="80"
|
|
||||||
Height="18" />
|
|
||||||
</StatusBarItem>
|
|
||||||
</StatusBar>
|
|
||||||
</Grid>
|
|
||||||
</Window>
|
|
||||||
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using System.Windows.Shapes;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Guis.SieTiaWinCCMsgMgt
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interaktionslogik für FrmMain.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class FrmMain : Window
|
|
||||||
{
|
|
||||||
public WinCC WinCC { get; set; }
|
|
||||||
|
|
||||||
public FrmMain()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnStart_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
WinCC.Start();
|
|
||||||
CtrlMgt();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void btnStop_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
WinCC.Stop();
|
|
||||||
CtrlMgt();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CtrlMgt()
|
|
||||||
{
|
|
||||||
if (WinCC.Status)
|
|
||||||
{
|
|
||||||
btnStart.IsEnabled = false;
|
|
||||||
btnStop.IsEnabled = true;
|
|
||||||
pgProgress.IsIndeterminate = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
btnStart.IsEnabled = true;
|
|
||||||
btnStop.IsEnabled = false;
|
|
||||||
pgProgress.IsIndeterminate = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,172 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Guis.SieTiaWinCCMsgMgt
|
|
||||||
{
|
|
||||||
public class WinCC
|
|
||||||
{
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
public static extern bool SetForegroundWindow(IntPtr hWnd);
|
|
||||||
|
|
||||||
|
|
||||||
[DllImport("user32.dll", CharSet = CharSet.Auto)]
|
|
||||||
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
|
|
||||||
|
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
|
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
static extern IntPtr PostMessage(IntPtr hwndParent, int msg, int wParam, IntPtr lParam);
|
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
|
||||||
static extern bool IsWindowVisible(IntPtr hWnd);
|
|
||||||
|
|
||||||
const int BM_CLICK = 0x00F5; //message for Click which is a constant
|
|
||||||
const int WM_LBUTTONDOWN = 0x0201; //message for Mouse down
|
|
||||||
const int WM_LBUTTONUP = 0x0202; // message for Mouse up
|
|
||||||
|
|
||||||
private CancellationTokenSource tokenSource = null;
|
|
||||||
private CancellationToken token;
|
|
||||||
private Task task = null;
|
|
||||||
|
|
||||||
private BackgroundWorker backgroundWorker;
|
|
||||||
|
|
||||||
|
|
||||||
public bool AutoStart { get; set; }
|
|
||||||
public int UpdateIntervall { get; set; }
|
|
||||||
public string WindowsName { get; set; }
|
|
||||||
public string WindowsClassName { get; set; }
|
|
||||||
public string ButtonName { get; set; }
|
|
||||||
|
|
||||||
public WinCC()
|
|
||||||
{
|
|
||||||
backgroundWorker = new BackgroundWorker
|
|
||||||
{
|
|
||||||
WorkerReportsProgress = true,
|
|
||||||
WorkerSupportsCancellation = true
|
|
||||||
};
|
|
||||||
backgroundWorker.DoWork += BackgroundWorker_DoWork;
|
|
||||||
backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
|
|
||||||
|
|
||||||
if (AutoStart)
|
|
||||||
{
|
|
||||||
Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
|
|
||||||
{
|
|
||||||
BackgroundWorker worker = sender as BackgroundWorker;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (worker.CancellationPending == true)
|
|
||||||
{
|
|
||||||
e.Cancel = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Perform a time consuming operation and report progress.
|
|
||||||
System.Threading.Thread.Sleep(UpdateIntervall);
|
|
||||||
|
|
||||||
// Find windos by Name
|
|
||||||
var windowHandle = FindWindow(WindowsClassName, WindowsName);
|
|
||||||
|
|
||||||
if (windowHandle != IntPtr.Zero && IsWindowVisible(windowHandle))
|
|
||||||
{
|
|
||||||
SetForegroundWindow(windowHandle);
|
|
||||||
var btnHandle = FindWindowEx(windowHandle, IntPtr.Zero, null, ButtonName);
|
|
||||||
SendMessage(btnHandle, BM_CLICK, IntPtr.Zero, IntPtr.Zero);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Start()
|
|
||||||
{
|
|
||||||
if (backgroundWorker.IsBusy != true)
|
|
||||||
{
|
|
||||||
backgroundWorker.RunWorkerAsync();
|
|
||||||
}
|
|
||||||
Status = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Stop()
|
|
||||||
{
|
|
||||||
if (backgroundWorker.WorkerSupportsCancellation == true)
|
|
||||||
{
|
|
||||||
backgroundWorker.CancelAsync();
|
|
||||||
}
|
|
||||||
Status = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Status { get; set; }
|
|
||||||
|
|
||||||
private void WinCCMsgMgt()
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (token.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
token.ThrowIfCancellationRequested();
|
|
||||||
}
|
|
||||||
//MessageBox.Show("13456");
|
|
||||||
Thread.Sleep(5000);
|
|
||||||
}
|
|
||||||
catch (OperationCanceledException)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
bool disposedValue = false;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!disposedValue)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
tokenSource.Cancel();
|
|
||||||
task.Wait();
|
|
||||||
tokenSource.Dispose();
|
|
||||||
task.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
disposedValue = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
tokenSource = null;
|
|
||||||
task = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
using System.Security.Principal;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Helpers
|
|
||||||
{
|
|
||||||
public static class IdentityHelpers
|
|
||||||
{
|
|
||||||
public static string ShortName(this WindowsIdentity Identity)
|
|
||||||
{
|
|
||||||
if (null != Identity)
|
|
||||||
{
|
|
||||||
return Identity.Name.Split(new char[] { '\\' })[1];
|
|
||||||
}
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 11 KiB |
@@ -1,57 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Runtime.InteropServices.ComTypes;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace FSI.Lib.LnkParser
|
|
||||||
{
|
|
||||||
public static class ShortCut
|
|
||||||
{
|
|
||||||
public static void Create(string shortcutName, string shortcutPath, string targetPath, string descripton)
|
|
||||||
{
|
|
||||||
IShellLink link = (IShellLink)new ShellLink();
|
|
||||||
|
|
||||||
// setup shortcut information
|
|
||||||
link.SetPath(targetPath);
|
|
||||||
link.SetDescription(descripton);
|
|
||||||
|
|
||||||
// save it
|
|
||||||
IPersistFile file = (IPersistFile)link;
|
|
||||||
file.Save(Path.Combine(shortcutPath, shortcutName) + ".lnk", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[ComImport]
|
|
||||||
[Guid("00021401-0000-0000-C000-000000000046")]
|
|
||||||
internal class ShellLink
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[ComImport]
|
|
||||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
||||||
[Guid("000214F9-0000-0000-C000-000000000046")]
|
|
||||||
internal interface IShellLink
|
|
||||||
{
|
|
||||||
void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, out IntPtr pfd, int fFlags);
|
|
||||||
void GetIDList(out IntPtr ppidl);
|
|
||||||
void SetIDList(IntPtr pidl);
|
|
||||||
void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
|
|
||||||
void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
|
|
||||||
void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
|
|
||||||
void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
|
|
||||||
void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
|
|
||||||
void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
|
|
||||||
void GetHotkey(out short pwHotkey);
|
|
||||||
void SetHotkey(short wHotkey);
|
|
||||||
void GetShowCmd(out int piShowCmd);
|
|
||||||
void SetShowCmd(int iShowCmd);
|
|
||||||
void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon);
|
|
||||||
void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
|
|
||||||
void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
|
|
||||||
void Resolve(IntPtr hwnd, int fFlags);
|
|
||||||
void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows.Input;
|
|
||||||
|
|
||||||
namespace FSI.Lib.MVVM
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// DelegateCommand borrowed from
|
|
||||||
/// http://www.wpftutorial.net/DelegateCommand.html
|
|
||||||
/// </summary>
|
|
||||||
public class DelegateCommand : ICommand
|
|
||||||
{
|
|
||||||
private readonly Predicate<object> _canExecute;
|
|
||||||
private readonly Action<object> _execute;
|
|
||||||
|
|
||||||
public DelegateCommand(Action<object> execute,
|
|
||||||
Predicate<object> canExecute = null)
|
|
||||||
{
|
|
||||||
_execute = execute;
|
|
||||||
_canExecute = canExecute;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RaiseCanExecuteChanged()
|
|
||||||
{
|
|
||||||
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region ICommand Members
|
|
||||||
|
|
||||||
public event EventHandler CanExecuteChanged;
|
|
||||||
|
|
||||||
public bool CanExecute(object parameter)
|
|
||||||
{
|
|
||||||
return _canExecute == null || _canExecute(parameter);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Execute(object parameter)
|
|
||||||
{
|
|
||||||
_execute(parameter);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,77 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows.Input;
|
|
||||||
|
|
||||||
namespace FSI.Lib.MVVM
|
|
||||||
{
|
|
||||||
public class RelayCommand<T> : ICommand
|
|
||||||
{
|
|
||||||
#region Fields
|
|
||||||
|
|
||||||
readonly Action<T> _execute = null;
|
|
||||||
readonly Predicate<T> _canExecute = null;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of <see cref="DelegateCommand{T}"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="execute">Delegate to execute when Execute is called on the command. This can be null to just hook up a CanExecute delegate.</param>
|
|
||||||
/// <remarks><seealso cref="CanExecute"/> will always return true.</remarks>
|
|
||||||
public RelayCommand(Action<T> execute)
|
|
||||||
: this(execute, null)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new command.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="execute">The execution logic.</param>
|
|
||||||
/// <param name="canExecute">The execution status logic.</param>
|
|
||||||
public RelayCommand(Action<T> execute, Predicate<T> canExecute)
|
|
||||||
{
|
|
||||||
if (execute == null)
|
|
||||||
throw new ArgumentNullException("execute");
|
|
||||||
|
|
||||||
_execute = execute;
|
|
||||||
_canExecute = canExecute;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region ICommand Members
|
|
||||||
|
|
||||||
///<summary>
|
|
||||||
///Defines the method that determines whether the command can execute in its current state.
|
|
||||||
///</summary>
|
|
||||||
///<param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
|
|
||||||
///<returns>
|
|
||||||
///true if this command can be executed; otherwise, false.
|
|
||||||
///</returns>
|
|
||||||
public bool CanExecute(object parameter)
|
|
||||||
{
|
|
||||||
return _canExecute == null ? true : _canExecute((T)parameter);
|
|
||||||
}
|
|
||||||
|
|
||||||
///<summary>
|
|
||||||
///Occurs when changes occur that affect whether or not the command should execute.
|
|
||||||
///</summary>
|
|
||||||
public event EventHandler CanExecuteChanged
|
|
||||||
{
|
|
||||||
add { CommandManager.RequerySuggested += value; }
|
|
||||||
remove { CommandManager.RequerySuggested -= value; }
|
|
||||||
}
|
|
||||||
|
|
||||||
///<summary>
|
|
||||||
///Defines the method to be called when the command is invoked.
|
|
||||||
///</summary>
|
|
||||||
///<param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to <see langword="null" />.</param>
|
|
||||||
public void Execute(object parameter)
|
|
||||||
{
|
|
||||||
_execute((T)parameter);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace FSI.Lib.MVVM.ViewModel
|
|
||||||
{
|
|
||||||
public class CurrentTimeViewModel : INotifyPropertyChanged
|
|
||||||
{
|
|
||||||
private string _currentTime;
|
|
||||||
|
|
||||||
public CurrentTimeViewModel()
|
|
||||||
{
|
|
||||||
UpdateTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void UpdateTime()
|
|
||||||
{
|
|
||||||
CurrentTime = DateTime.Now.ToString("G");
|
|
||||||
await Task.Delay(1000);
|
|
||||||
UpdateTime();
|
|
||||||
}
|
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
|
|
||||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
|
||||||
{
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
|
|
||||||
public string CurrentTime
|
|
||||||
{
|
|
||||||
get { return _currentTime; }
|
|
||||||
set { _currentTime = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
/* Example for use:
|
|
||||||
|
|
||||||
public class MyViewModel : ViewModelBase
|
|
||||||
{
|
|
||||||
private int myProperty;
|
|
||||||
public int MyProperty
|
|
||||||
{
|
|
||||||
get { return myProperty; }
|
|
||||||
set { SetProperty(ref myProperty, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
namespace FSI.Lib.MVVM
|
|
||||||
{
|
|
||||||
public class ViewModelBase : INotifyPropertyChanged
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Multicast event for property change notifications.
|
|
||||||
/// </summary>
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if a property already matches the desired value. Sets the property and
|
|
||||||
/// notifies listeners only when necessary.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">Type of the property.</typeparam>
|
|
||||||
/// <param name="storage">Reference to a property with both getter and setter.</param>
|
|
||||||
/// <param name="value">Desired value for the property.</param>
|
|
||||||
/// <param name="propertyName">Name of the property used to notify listeners.This
|
|
||||||
/// value is optional and can be provided automatically when invoked from compilers that
|
|
||||||
/// support CallerMemberName.</param>
|
|
||||||
/// <returns>True if the value was changed, false if the existing value matched the
|
|
||||||
/// desired value.</returns>
|
|
||||||
protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
|
|
||||||
{
|
|
||||||
if (object.Equals(storage, value)) return false;
|
|
||||||
storage = value;
|
|
||||||
// Log.DebugFormat("{0}.{1} = {2}", this.GetType().Name, propertyName, storage);
|
|
||||||
this.OnPropertyChanged(propertyName);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Notifies listeners that a property value has changed.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="propertyName">Name of the property used to notify listeners. This
|
|
||||||
/// value is optional and can be provided automatically when invoked from compilers
|
|
||||||
/// that support <see cref="CallerMemberNameAttribute"/>.</param>
|
|
||||||
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
|
||||||
{
|
|
||||||
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace FSI.Lib
|
|
||||||
{
|
|
||||||
public static class TimeStamp
|
|
||||||
{
|
|
||||||
public static string Get(string format)
|
|
||||||
{
|
|
||||||
return DateTime.Now.ToString(format);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,90 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace FSI.Lib.WinSettings
|
|
||||||
{
|
|
||||||
internal static class ArrayToString
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Represents the given array as a single string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="array">String array to encode.</param>
|
|
||||||
/// <returns>The encoded string.</returns>
|
|
||||||
public static string Encode(string[] array)
|
|
||||||
{
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
|
|
||||||
if (array == null)
|
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
for (int i = 0; i < array.Length; i++)
|
|
||||||
{
|
|
||||||
if (i > 0)
|
|
||||||
builder.Append(',');
|
|
||||||
if (array[i].IndexOfAny(new[] { ',', '"', '\r', '\n' }) >= 0)
|
|
||||||
builder.Append(string.Format("\"{0}\"", array[i].Replace("\"", "\"\"")));
|
|
||||||
else
|
|
||||||
builder.Append(array[i]);
|
|
||||||
}
|
|
||||||
return builder.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Decodes a string created with <see cref="Encode"></see> back to an array.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="s">String to decode.</param>
|
|
||||||
/// <returns>The decoded array.</returns>
|
|
||||||
public static string[] Decode(string s)
|
|
||||||
{
|
|
||||||
List<string> list = new List<string>();
|
|
||||||
int pos = 0;
|
|
||||||
|
|
||||||
if (s == null)
|
|
||||||
return Array.Empty<string>();
|
|
||||||
|
|
||||||
while (pos < s.Length)
|
|
||||||
{
|
|
||||||
if (s[pos] == '\"')
|
|
||||||
{
|
|
||||||
// Parse quoted value
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
|
|
||||||
// Skip starting quote
|
|
||||||
pos++;
|
|
||||||
while (pos < s.Length)
|
|
||||||
{
|
|
||||||
if (s[pos] == '"')
|
|
||||||
{
|
|
||||||
// Skip quote
|
|
||||||
pos++;
|
|
||||||
// One quote signifies end of value
|
|
||||||
// Two quote signifies single quote literal
|
|
||||||
if (pos >= s.Length || s[pos] != '"')
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
builder.Append(s[pos++]);
|
|
||||||
}
|
|
||||||
list.Add(builder.ToString());
|
|
||||||
// Skip delimiter
|
|
||||||
pos = s.IndexOf(',', pos);
|
|
||||||
if (pos == -1)
|
|
||||||
pos = s.Length;
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Parse value
|
|
||||||
int start = pos;
|
|
||||||
pos = s.IndexOf(',', pos);
|
|
||||||
if (pos == -1)
|
|
||||||
pos = s.Length;
|
|
||||||
list.Add(s.Substring(start, pos - start));
|
|
||||||
// Skip delimiter
|
|
||||||
pos++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list.ToArray();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace FSI.Lib.WinSettings
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// This attribute specifies that this property should be encrypted
|
|
||||||
/// when it is saved.
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
|
||||||
public class EncryptedSettingAttribute : Attribute
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace FSI.Lib.WinSettings
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Attribute specifies that this property does not represent a setting and
|
|
||||||
/// should not be saved.
|
|
||||||
/// </summary>
|
|
||||||
[AttributeUsage(AttributeTargets.Property)]
|
|
||||||
public class ExcludedSettingAttribute : Attribute
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,337 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace FSI.Lib.WinSettings
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Represents one name/value pair in an INI file.
|
|
||||||
/// </summary>
|
|
||||||
internal class IniSetting
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The name of this INI setting.
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The value of this INI setting.
|
|
||||||
/// </summary>
|
|
||||||
public string Value { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Class to create and read INI files.
|
|
||||||
/// </summary>
|
|
||||||
internal class IniFile
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Section used for settings not under any section header (within [])
|
|
||||||
/// </summary>
|
|
||||||
public const string DefaultSectionName = "General";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Represents an entire INI file section.
|
|
||||||
/// </summary>
|
|
||||||
private class IniSection
|
|
||||||
{
|
|
||||||
public string Name { get; set; }
|
|
||||||
public Dictionary<string, IniSetting> Settings { get; private set; }
|
|
||||||
|
|
||||||
public IniSection()
|
|
||||||
{
|
|
||||||
Name = string.Empty;
|
|
||||||
Settings = new Dictionary<string, IniSetting>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Dictionary<string, IniSection> Sections = new Dictionary<string, IniSection>(StringComparer.OrdinalIgnoreCase);
|
|
||||||
|
|
||||||
#region File functions
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Loads an INI settings file.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">Path of file to load.</param>
|
|
||||||
public void Load(string filename)
|
|
||||||
{
|
|
||||||
Sections.Clear();
|
|
||||||
|
|
||||||
// Default section
|
|
||||||
IniSection section = new IniSection { Name = DefaultSectionName };
|
|
||||||
Sections.Add(section.Name, section);
|
|
||||||
|
|
||||||
string line;
|
|
||||||
using StreamReader file = new StreamReader(filename);
|
|
||||||
|
|
||||||
while ((line = file.ReadLine()) != null)
|
|
||||||
{
|
|
||||||
line = line.TrimStart();
|
|
||||||
if (line.Length > 0)
|
|
||||||
{
|
|
||||||
if (line[0] == ';')
|
|
||||||
{
|
|
||||||
// Ignore comments
|
|
||||||
}
|
|
||||||
else if (line[0] == '[')
|
|
||||||
{
|
|
||||||
// Parse section header
|
|
||||||
int pos = line.IndexOf(']', 1);
|
|
||||||
if (pos == -1)
|
|
||||||
pos = line.Length;
|
|
||||||
#if NETSTANDARD2_0
|
|
||||||
string name = line.Substring(1, pos - 1).Trim();
|
|
||||||
#else
|
|
||||||
string name = line[1..pos].Trim();
|
|
||||||
#endif
|
|
||||||
if (name.Length > 0)
|
|
||||||
{
|
|
||||||
if (!Sections.TryGetValue(name, out section))
|
|
||||||
{
|
|
||||||
section = new IniSection { Name = name };
|
|
||||||
Sections.Add(section.Name, section);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Parse setting name and value
|
|
||||||
string name, value;
|
|
||||||
|
|
||||||
int pos = line.IndexOf('=');
|
|
||||||
if (pos == -1)
|
|
||||||
{
|
|
||||||
name = line.Trim();
|
|
||||||
value = string.Empty;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
name = line.Substring(0, pos).Trim();
|
|
||||||
#if NETSTANDARD2_0
|
|
||||||
value = line.Substring(pos + 1);
|
|
||||||
#else
|
|
||||||
value = line[(pos + 1)..];
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name.Length > 0)
|
|
||||||
{
|
|
||||||
if (section.Settings.TryGetValue(name, out IniSetting setting))
|
|
||||||
{
|
|
||||||
setting.Value = value;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setting = new IniSetting { Name = name, Value = value };
|
|
||||||
section.Settings.Add(name, setting);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Writes the current settings to an INI file. If the file already exists, it is overwritten.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">Path of file to write to.</param>
|
|
||||||
public void Save(string filename)
|
|
||||||
{
|
|
||||||
using StreamWriter file = new StreamWriter(filename, false);
|
|
||||||
|
|
||||||
bool firstLine = true;
|
|
||||||
foreach (IniSection section in Sections.Values)
|
|
||||||
{
|
|
||||||
if (firstLine)
|
|
||||||
firstLine = false;
|
|
||||||
else
|
|
||||||
file.WriteLine();
|
|
||||||
|
|
||||||
if (section.Settings.Any())
|
|
||||||
{
|
|
||||||
file.WriteLine("[{0}]", section.Name);
|
|
||||||
foreach (IniSetting setting in section.Settings.Values)
|
|
||||||
file.WriteLine("{0}={1}", setting.Name, setting.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Read values
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the value of an INI setting.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="section">The INI file section.</param>
|
|
||||||
/// <param name="setting">The INI setting name.</param>
|
|
||||||
/// <param name="defaultValue">The value to return if the setting was not found.</param>
|
|
||||||
/// <returns>Returns the specified setting value.</returns>
|
|
||||||
public string GetSetting(string section, string setting, string defaultValue = null)
|
|
||||||
{
|
|
||||||
if (Sections.TryGetValue(section, out IniSection iniSection))
|
|
||||||
{
|
|
||||||
if (iniSection.Settings.TryGetValue(setting, out IniSetting iniSetting))
|
|
||||||
return iniSetting.Value;
|
|
||||||
}
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the value of an INI setting as an integer value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="section">The INI file section.</param>
|
|
||||||
/// <param name="setting">The INI setting name.</param>
|
|
||||||
/// <param name="defaultValue">The value to return if the setting was not found,
|
|
||||||
/// or if it could not be converted to a integer value.</param>
|
|
||||||
/// <returns>Returns the specified setting value as an integer value.</returns>
|
|
||||||
public int GetSetting(string section, string setting, int defaultValue)
|
|
||||||
{
|
|
||||||
if (int.TryParse(GetSetting(section, setting), out int value))
|
|
||||||
return value;
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the value of an INI setting as a double value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="section">The INI file section.</param>
|
|
||||||
/// <param name="setting">The INI setting name.</param>
|
|
||||||
/// <param name="defaultValue">The value to return if the setting was not found,
|
|
||||||
/// or if it could not be converted to a double value.</param>
|
|
||||||
/// <returns>Returns the specified setting value as a double value.</returns>
|
|
||||||
public double GetSetting(string section, string setting, double defaultValue)
|
|
||||||
{
|
|
||||||
if (double.TryParse(GetSetting(section, setting), out double value))
|
|
||||||
return value;
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the value of an INI setting as a Boolean value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="section">The INI file section.</param>
|
|
||||||
/// <param name="setting">The INI setting name.</param>
|
|
||||||
/// <param name="defaultValue">The value to return if the setting was not found,
|
|
||||||
/// or if it could not be converted to a Boolean value.</param>
|
|
||||||
/// <returns>Returns the specified setting value as a Boolean.</returns>
|
|
||||||
public bool GetSetting(string section, string setting, bool defaultValue)
|
|
||||||
{
|
|
||||||
if (ConvertToBool(GetSetting(section, setting), out bool value))
|
|
||||||
return value;
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns all settings in the given INI section.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="section">The section that contains the settings to be retrieved.</param>
|
|
||||||
/// <returns>Returns the settings in the given INI section.</returns>
|
|
||||||
public IEnumerable<IniSetting> GetSectionSettings(string section)
|
|
||||||
{
|
|
||||||
if (Sections.TryGetValue(section, out IniSection iniSection))
|
|
||||||
{
|
|
||||||
foreach (var setting in iniSection.Settings)
|
|
||||||
yield return setting.Value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Write values
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets an INI file setting. The setting is not written to disk until
|
|
||||||
/// <see cref="Save"/> is called.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="section">The INI-file section.</param>
|
|
||||||
/// <param name="setting">The name of the INI-file setting.</param>
|
|
||||||
/// <param name="value">The value of the INI-file setting</param>
|
|
||||||
public void SetSetting(string section, string setting, string value)
|
|
||||||
{
|
|
||||||
if (!Sections.TryGetValue(section, out IniSection iniSection))
|
|
||||||
{
|
|
||||||
iniSection = new IniSection { Name = section };
|
|
||||||
Sections.Add(iniSection.Name, iniSection);
|
|
||||||
}
|
|
||||||
if (!iniSection.Settings.TryGetValue(setting, out IniSetting iniSetting))
|
|
||||||
{
|
|
||||||
iniSetting = new IniSetting { Name = setting };
|
|
||||||
iniSection.Settings.Add(iniSetting.Name, iniSetting);
|
|
||||||
}
|
|
||||||
iniSetting.Value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets an INI file setting with an integer value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="section">The INI-file section.</param>
|
|
||||||
/// <param name="setting">The name of the INI-file setting.</param>
|
|
||||||
/// <param name="value">The value of the INI-file setting</param>
|
|
||||||
public void SetSetting(string section, string setting, int value)
|
|
||||||
{
|
|
||||||
SetSetting(section, setting, value.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets an INI file setting with a double value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="section">The INI-file section.</param>
|
|
||||||
/// <param name="setting">The name of the INI-file setting.</param>
|
|
||||||
/// <param name="value">The value of the INI-file setting</param>
|
|
||||||
public void SetSetting(string section, string setting, double value)
|
|
||||||
{
|
|
||||||
SetSetting(section, setting, value.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets an INI file setting with a Boolean value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="section">The INI-file section.</param>
|
|
||||||
/// <param name="setting">The name of the INI-file setting.</param>
|
|
||||||
/// <param name="value">The value of the INI-file setting</param>
|
|
||||||
public void SetSetting(string section, string setting, bool value)
|
|
||||||
{
|
|
||||||
SetSetting(section, setting, value.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Boolean parsing
|
|
||||||
|
|
||||||
private readonly string[] TrueStrings = { "true", "yes", "on" };
|
|
||||||
private readonly string[] FalseStrings = { "false", "no", "off" };
|
|
||||||
|
|
||||||
private bool ConvertToBool(string s, out bool value)
|
|
||||||
{
|
|
||||||
if (s == null)
|
|
||||||
value = false;
|
|
||||||
if (TrueStrings.Any(s2 => string.Compare(s, s2, true) == 0))
|
|
||||||
value = true;
|
|
||||||
else if (FalseStrings.Any(s2 => string.Compare(s, s2, true) == 0))
|
|
||||||
value = false;
|
|
||||||
else if (int.TryParse(s, out int i))
|
|
||||||
value = i != 0;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
value = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
//public void Dump()
|
|
||||||
//{
|
|
||||||
// foreach (IniSection section in Sections.Values)
|
|
||||||
// {
|
|
||||||
// Debug.WriteLine(string.Format("[{0}]", section.Name));
|
|
||||||
// foreach (IniSetting setting in section.Settings.Values)
|
|
||||||
// Debug.WriteLine("[{0}]=[{1}]", setting.Name, setting.Value);
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,142 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace FSI.Lib.WinSettings
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="IniSettings"/> class makes it very easy to save your application
|
|
||||||
/// settings to an INI file.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// <para>
|
|
||||||
/// To use the class, simply derive your own settings class from
|
|
||||||
/// <see cref="IniSettings" /> and add the public properties that you want to be
|
|
||||||
/// saved as settings. You can then call the <see cref="Settings.Load"/> and
|
|
||||||
/// <see cref="Settings.Save"/> methods to read or write those settings to an INI
|
|
||||||
/// file.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// Your derived class' constructor should initialize your settings properties to
|
|
||||||
/// their default values.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// Two attributes are available for public properties in your derived class. The
|
|
||||||
/// first is <see cref="EncryptedSettingAttribute" />. Use this attribute if you
|
|
||||||
/// want the setting to be encrypted when saved to file. When using this attribute on
|
|
||||||
/// any property, you must provide a valid encryption password to the
|
|
||||||
/// <see cref="IniSettings" /> constructor.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// The second is the <see cref="ExcludedSettingAttribute"/>. Use this attribute
|
|
||||||
/// on any properties that are used internally by your code and should not saved to
|
|
||||||
/// file.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// All public properties without the <see cref="ExcludedSettingAttribute"></see>
|
|
||||||
/// attribute must be of one of the supported data types. This includes all the basic
|
|
||||||
/// data types as well as <see cref="string[]"></see> and <see cref="byte[]"></see>.
|
|
||||||
/// All other types will raise an exception. In addition, INI files do not support
|
|
||||||
/// strings that contain newlines unless those strings are encrypted.
|
|
||||||
/// </para>
|
|
||||||
/// </remarks>
|
|
||||||
/// <example>
|
|
||||||
/// The following example creates a settings class called <c>MySettings</c> with
|
|
||||||
/// several properties, two of which are encrypted when saved to file.
|
|
||||||
/// <code>
|
|
||||||
/// public class MySettings : IniSettings
|
|
||||||
/// {
|
|
||||||
/// // Define properties to be saved to file
|
|
||||||
/// public string EmailHost { get; set; }
|
|
||||||
/// public int EmailPort { get; set; }
|
|
||||||
///
|
|
||||||
/// // The following properties will be encrypted
|
|
||||||
/// [EncryptedSetting]
|
|
||||||
/// public string UserName { get; set; }
|
|
||||||
/// [EncryptedSetting]
|
|
||||||
/// public string Password { get; set; }
|
|
||||||
///
|
|
||||||
/// // The following property will not be saved to file
|
|
||||||
/// // Non-public properties are also not saved to file
|
|
||||||
/// [ExcludedSetting]
|
|
||||||
/// public DateTime Created { get; set; }
|
|
||||||
///
|
|
||||||
/// public MySettings(string filename)
|
|
||||||
/// : base(filename, "Password123")
|
|
||||||
/// {
|
|
||||||
/// // Set initial, default property values
|
|
||||||
/// EmailHost = string.Empty;
|
|
||||||
/// EmailPort = 0;
|
|
||||||
/// UserName = string.Empty;
|
|
||||||
/// Password = string.Empty;
|
|
||||||
///
|
|
||||||
/// Created = DateTime.Now;
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// </code>
|
|
||||||
/// </example>
|
|
||||||
/// <seealso cref="RegistrySettings"/>
|
|
||||||
/// <seealso cref="XmlSettings"/>
|
|
||||||
public abstract class IniSettings : Settings
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the name of the INI settings file.
|
|
||||||
/// </summary>
|
|
||||||
[ExcludedSetting]
|
|
||||||
public string FileName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs an instance of the <c>XmlSettings</c> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">Name of the settings file.</param>
|
|
||||||
/// <param name="password">Encryption password. May be <c>null</c>
|
|
||||||
/// if no settings use the <see cref="EncryptedSettingAttribute" />
|
|
||||||
/// attribute.</param>
|
|
||||||
public IniSettings(string filename, string password = null)
|
|
||||||
: base(password)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(filename))
|
|
||||||
throw new ArgumentException("A valid path and file name is required.", nameof(filename));
|
|
||||||
FileName = filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Performs internal load operations.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="settings">Settings to be loaded.</param>
|
|
||||||
public override void OnLoadSettings(IEnumerable<Setting> settings)
|
|
||||||
{
|
|
||||||
if (File.Exists(FileName))
|
|
||||||
{
|
|
||||||
// Load INI file
|
|
||||||
IniFile iniFile = new IniFile();
|
|
||||||
iniFile.Load(FileName);
|
|
||||||
// Read settings
|
|
||||||
foreach (Setting setting in settings)
|
|
||||||
{
|
|
||||||
string value = iniFile.GetSetting(IniFile.DefaultSectionName, setting.Name, null);
|
|
||||||
if (value != null)
|
|
||||||
setting.SetValueFromString(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Performs internal save operations.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="settings">Settings to be saved.</param>
|
|
||||||
public override void OnSaveSettings(IEnumerable<Setting> settings)
|
|
||||||
{
|
|
||||||
// Create INI file
|
|
||||||
IniFile iniFile = new IniFile();
|
|
||||||
// Write settings
|
|
||||||
foreach (Setting setting in settings)
|
|
||||||
{
|
|
||||||
string value = setting.GetValueAsString();
|
|
||||||
if (value != null)
|
|
||||||
iniFile.SetSetting(IniFile.DefaultSectionName, setting.Name, value);
|
|
||||||
}
|
|
||||||
iniFile.Save(FileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
# WinSettings
|
|
||||||
|
|
||||||
[](https://www.nuget.org/packages/SoftCircuits.WinSettings/)
|
|
||||||
|
|
||||||
```
|
|
||||||
Install-Package SoftCircuits.WinSettings
|
|
||||||
```
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
WinSettings is a .NET class library that makes it easy to save and retrieve application settings on Windows. It includes three settings classes: `IniSettings`, which stores the settings to an INI file; `XmlSettings`, which stores the settings to an XML file, and `RegistrySettings`, which stores the settings to the Windows registry. In addition, it makes it easy to define your own settings type.
|
|
||||||
|
|
||||||
Settings can be encrypted just by adding a property attribute. There is also an attribute to exclude a particular property when the property is used internally and does not represent an application setting.
|
|
||||||
|
|
||||||
To use a settings class, simply derive your own settings class from one of the ones described above and add public properties that you want to be saved. Your class' constructor should set any default values. Then call the `Save()` and `Load()` methods to save the settings in your class.
|
|
||||||
|
|
||||||
## IniSettings Class
|
|
||||||
|
|
||||||
The <see cref="IniSettings"/> class makes it very easy to save your application settings to an INI file.
|
|
||||||
|
|
||||||
To use the class, simply derive your own settings class from `IniSettings` and add the public properties that you want to be saved as settings. You can then call the `Load()` and `Save()` methods to read or write those settings to an INI file.
|
|
||||||
|
|
||||||
Your derived class' constructor should initialize your settings properties to their default values.
|
|
||||||
|
|
||||||
Two attributes are available for public properties in your derived class. The first is `EncryptedSettingAttribute`. Use this attribute if you want the setting to be encrypted when saved to file. When using this attribute on any property, you must provide a valid encryption password to the `IniSettings` constructor.
|
|
||||||
|
|
||||||
The second is the `ExcludedSettingAttribute`. Use this attribute on any properties that are used internally by your code and should not saved to file.
|
|
||||||
|
|
||||||
All public properties without the `ExcludedSettingAttribute` attribute must be of one of the supported data types. This includes all the basic data types as well as `string[]` and `byte[]`. All other types will raise an exception. In addition, INI files do not support strings that contain newlines unless those strings are encrypted.
|
|
||||||
|
|
||||||
#### Example
|
|
||||||
|
|
||||||
The following example creates a settings class called `MySettings` with several properties, two of which are encrypted when saved to file.
|
|
||||||
|
|
||||||
```cs
|
|
||||||
public class MySettings : IniSettings
|
|
||||||
{
|
|
||||||
// Define properties to be saved to file
|
|
||||||
public string EmailHost { get; set; }
|
|
||||||
public int EmailPort { get; set; }
|
|
||||||
|
|
||||||
// The following properties will be encrypted
|
|
||||||
[EncryptedSetting]
|
|
||||||
public string UserName { get; set; }
|
|
||||||
[EncryptedSetting]
|
|
||||||
public string Password { get; set; }
|
|
||||||
|
|
||||||
// The following property will not be saved to file
|
|
||||||
// Non-public properties are also not saved to file
|
|
||||||
[ExcludedSetting]
|
|
||||||
public DateTime Created { get; set; }
|
|
||||||
|
|
||||||
public MySettings(string filename)
|
|
||||||
: base(filename, "Password123")
|
|
||||||
{
|
|
||||||
// Set initial, default property values
|
|
||||||
EmailHost = string.Empty;
|
|
||||||
EmailPort = 0;
|
|
||||||
UserName = string.Empty;
|
|
||||||
Password = string.Empty;
|
|
||||||
|
|
||||||
Created = DateTime.Now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## XmlSettings Class
|
|
||||||
|
|
||||||
The <see `XmlSettings` class makes it very easy to save your application settings to an XML file.
|
|
||||||
|
|
||||||
To use the class, simply derive your own settings class from `XmlSettings` and add the public properties that you want to be saved as settings. You can then call the `Load()` and `Save()` methods to read or write those settings to an XML file.
|
|
||||||
|
|
||||||
Your derived class' constructor should initialize your settings properties to their default values.
|
|
||||||
|
|
||||||
Two attributes are available for public properties in your derived class. The first is `EncryptedSettingAttribute`. Use this attribute if you want the setting to be encrypted when saved to file. When using this attribute on any property, you must provide a valid encryption password to the `XmlSettings` constructor.
|
|
||||||
|
|
||||||
The second is the `ExcludedSettingAttribute` Use this attribute on any properties that are used internally by your code and should not saved to file.
|
|
||||||
|
|
||||||
All public properties without the `ExcludedSettingAttribute` attribute must be of one of the supported data types. This includes all the basic data types `string[]` and `byte[]`. All other types will raise an exception.
|
|
||||||
|
|
||||||
#### Example
|
|
||||||
|
|
||||||
The following example creates a settings class called `MySettings` with several properties, two of which are encrypted when saved to file.
|
|
||||||
|
|
||||||
```cs
|
|
||||||
public class MySettings : XmlSettings
|
|
||||||
{
|
|
||||||
// Define properties to be saved to file
|
|
||||||
public string EmailHost { get; set; }
|
|
||||||
public int EmailPort { get; set; }
|
|
||||||
|
|
||||||
// The following properties will be encrypted
|
|
||||||
[EncryptedSetting]
|
|
||||||
public string UserName { get; set; }
|
|
||||||
[EncryptedSetting]
|
|
||||||
public string Password { get; set; }
|
|
||||||
|
|
||||||
// The following property will not be saved to file
|
|
||||||
// Non-public properties are also not saved to file
|
|
||||||
[ExcludedSetting]
|
|
||||||
public DateTime Created { get; set; }
|
|
||||||
|
|
||||||
public MySettings(string filename)
|
|
||||||
: base(filename, "Password123")
|
|
||||||
{
|
|
||||||
// Set initial, default property values
|
|
||||||
EmailHost = string.Empty;
|
|
||||||
EmailPort = 0;
|
|
||||||
UserName = string.Empty;
|
|
||||||
Password = string.Empty;
|
|
||||||
|
|
||||||
Created = DateTime.Now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## RegistrySettings Class
|
|
||||||
|
|
||||||
The `RegistrySettings` class makes it very easy to save your application settings to the system registry.
|
|
||||||
|
|
||||||
To use the class, simply derive your own settings class from `RegistrySettings` and add the public properties that you want to be
|
|
||||||
saved as settings. You can then call the `Load()` and `Save()` methods to read or write those settings to the system registry.
|
|
||||||
|
|
||||||
Your derived class' constructor should initialize your settings properties to their default values.
|
|
||||||
|
|
||||||
Two attributes are available for public properties in your derived class. The first is `EncryptedSettingAttribute`. Use this attribute if you want the setting to be encrypted when saved to file. When using this attribute on any property, you must provide a valid encryption password to the `RegistrySettings` constructor.
|
|
||||||
|
|
||||||
The second is the `ExcludedSettingAttribute`. Use this attribute on any properties that are used internally by your code and should not saved to the registry.
|
|
||||||
|
|
||||||
All public properties without the `ExcludedSettingAttribute` attribute must be of one of the supported data types. This includes all the basic data types as well as `string[]` and `byte[]`. All other types will raise an exception.
|
|
||||||
|
|
||||||
#### Example
|
|
||||||
|
|
||||||
The following example creates a settings class called `MySettings` with several properties, two of which are encrypted when saved to file.
|
|
||||||
|
|
||||||
```cs
|
|
||||||
public class MySettings : RegistrySettings
|
|
||||||
{
|
|
||||||
// Define properties to be saved to file
|
|
||||||
public string EmailHost { get; set; }
|
|
||||||
public int EmailPort { get; set; }
|
|
||||||
|
|
||||||
// The following properties will be encrypted
|
|
||||||
[EncryptedSetting]
|
|
||||||
public string UserName { get; set; }
|
|
||||||
[EncryptedSetting]
|
|
||||||
public string Password { get; set; }
|
|
||||||
|
|
||||||
// The following property will not be saved to file
|
|
||||||
// Non-public properties are also not saved to file
|
|
||||||
[ExcludedSetting]
|
|
||||||
public DateTime Created { get; set; }
|
|
||||||
|
|
||||||
public MySettings(string companyName, string applicationName, RegistrySettingsType settingsType)
|
|
||||||
: base(companyName, applicationName, settingsType, "Password123")
|
|
||||||
{
|
|
||||||
// Set initial, default property values
|
|
||||||
EmailHost = string.Empty;
|
|
||||||
EmailPort = 0;
|
|
||||||
UserName = string.Empty;
|
|
||||||
Password = string.Empty;
|
|
||||||
|
|
||||||
Created = DateTime.Now;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Settings Class
|
|
||||||
|
|
||||||
The `Settings` class is the base class for the `IniSettings`, `XmlSettings` and `RegistrySettings` classes. You don't need this class but you could use it to create your own type of custom settings class.
|
|
||||||
|
|
||||||
To do this, create your own `static`, `abstract` class that derives from `Settings` and override the virtual `OnSaveSettings()` and `OnLoadSettings()` methods.
|
|
||||||
|
|
||||||
As the name suggests, `OnSaveSettings()` is called when the settings are being saved. This method is passed a collection of `Setting` objects. Your handler needs to write these settings to your custom data store. The `Setting.Name` property contains the setting name. Use the `Setting.GetValue()` method to get the value. Or use the `Setting.GetValueAsString()` instead if your data store only supports string values.
|
|
||||||
|
|
||||||
The steps to override `OnLoadSettings()` is similar. This method is also passed a collection of `Setting` objects. Your handler needs to read each named setting from your custom data store. You can then set that value using the `Setting.SetValue()` or `Setting.SetValueFromString()` methods.
|
|
||||||
|
|
||||||
## Dependencies
|
|
||||||
|
|
||||||
This project requires the NuGet packages [SoftCircuits.EasyEncryption](https://www.nuget.org/packages/SoftCircuits.EasyEncryption/) and Microsoft.Win32.Registry.
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
using Microsoft.Win32;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace FSI.Lib.WinSettings
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Specifies the location within the registry where <see cref="RegistrySettings"/> stores
|
|
||||||
/// settings.
|
|
||||||
/// </summary>
|
|
||||||
public enum RegistrySettingsType
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Stores settings in the Windows registry base key HKEY_CURRENT_USER, normally
|
|
||||||
/// used for storing information about the current user preferences.
|
|
||||||
/// </summary>
|
|
||||||
CurrentUser,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Stores settings in thee Windows registry base key HKEY_LOCAL_MACHINE, normally
|
|
||||||
/// use for storing configuration data for the local machine.
|
|
||||||
/// </summary>
|
|
||||||
LocalMachine
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="RegistrySettings"/> class makes it very easy to save your application
|
|
||||||
/// settings to the system registry.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// <para>
|
|
||||||
/// To use the class, simply derive your own settings class from
|
|
||||||
/// <see cref="RegistrySettings" /> and add the public properties that you want to be
|
|
||||||
/// saved as settings. You can then call the <see cref="Settings.Load"/> and
|
|
||||||
/// <see cref="Settings.Save"/> methods to read or write those settings to the
|
|
||||||
/// system registry.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// Your derived class' constructor should initialize your settings properties to
|
|
||||||
/// their default values.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// Two attributes are available for public properties in your derived class. The
|
|
||||||
/// first is <see cref="EncryptedSettingAttribute" />. Use this attribute if you
|
|
||||||
/// want the setting to be encrypted when saved to file. When using this attribute on
|
|
||||||
/// any property, you must provide a valid encryption password to the
|
|
||||||
/// <see cref="RegistrySettings" /> constructor.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// The second is the <see cref="ExcludedSettingAttribute"/>. Use this attribute
|
|
||||||
/// on any properties that are used internally by your code and should not saved to
|
|
||||||
/// the registry.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// All public properties without the <see cref="ExcludedSettingAttribute"></see>
|
|
||||||
/// attribute must be of one of the supported data types. This includes all the basic
|
|
||||||
/// data types as well as <see cref="string[]"></see> and <see cref="byte[]"></see>.
|
|
||||||
/// All other types will raise an exception.
|
|
||||||
/// </para>
|
|
||||||
/// </remarks>
|
|
||||||
/// <example>
|
|
||||||
/// The following example creates a settings class called <c>MySettings</c> with
|
|
||||||
/// several properties, two of which are encrypted when saved to file.
|
|
||||||
/// <code>
|
|
||||||
/// public class MySettings : RegistrySettings
|
|
||||||
/// {
|
|
||||||
/// // Define properties to be saved to file
|
|
||||||
/// public string EmailHost { get; set; }
|
|
||||||
/// public int EmailPort { get; set; }
|
|
||||||
///
|
|
||||||
/// // The following properties will be encrypted
|
|
||||||
/// [EncryptedSetting]
|
|
||||||
/// public string UserName { get; set; }
|
|
||||||
/// [EncryptedSetting]
|
|
||||||
/// public string Password { get; set; }
|
|
||||||
///
|
|
||||||
/// // The following property will not be saved to file
|
|
||||||
/// // Non-public properties are also not saved to file
|
|
||||||
/// [ExcludedSetting]
|
|
||||||
/// public DateTime Created { get; set; }
|
|
||||||
///
|
|
||||||
/// public MySettings(string companyName, string applicationName, RegistrySettingsType settingsType)
|
|
||||||
/// : base(companyName, applicationName, settingsType, "Password123")
|
|
||||||
/// {
|
|
||||||
/// // Set initial, default property values
|
|
||||||
/// EmailHost = string.Empty;
|
|
||||||
/// EmailPort = 0;
|
|
||||||
/// UserName = string.Empty;
|
|
||||||
/// Password = string.Empty;
|
|
||||||
///
|
|
||||||
/// Created = DateTime.Now;
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// </code>
|
|
||||||
/// </example>
|
|
||||||
/// <seealso cref="IniSettings"/>
|
|
||||||
/// <seealso cref="XmlSettings"/>
|
|
||||||
public abstract class RegistrySettings : Settings
|
|
||||||
{
|
|
||||||
private readonly string SubKeyPath;
|
|
||||||
private readonly RegistryKey RegistryKey;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a new <c>RegistrySettings</c> instance.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="companyName">Company name entry in registry.</param>
|
|
||||||
/// <param name="applicationName">Application name entry in registration.</param>
|
|
||||||
/// <param name="settingsType">Section to store entries in registry.</param>
|
|
||||||
/// <param name="password">Encryption password. May be <c>null</c> if no settings
|
|
||||||
/// use the <see cref="EncryptedSettingAttribute" /> attribute.</param>
|
|
||||||
public RegistrySettings(string companyName, string applicationName, RegistrySettingsType settingsType, string password = null)
|
|
||||||
: base(password)
|
|
||||||
{
|
|
||||||
SubKeyPath = string.Format("Software\\{0}\\{1}", companyName, applicationName);
|
|
||||||
RegistryKey = settingsType == RegistrySettingsType.CurrentUser ? Registry.CurrentUser : Registry.LocalMachine;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Performs internal save operations.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="settings">Settings to be saved.</param>
|
|
||||||
public override void OnSaveSettings(IEnumerable<Setting> settings)
|
|
||||||
{
|
|
||||||
using (RegistryKey registryKey = RegistryKey.CreateSubKey(SubKeyPath, RegistryKeyPermissionCheck.ReadWriteSubTree))
|
|
||||||
{
|
|
||||||
foreach (var setting in settings)
|
|
||||||
{
|
|
||||||
var value = setting.GetValue();
|
|
||||||
if (value != null)
|
|
||||||
registryKey.SetValue(setting.Name, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Performs internal load operations.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="settings">Settings to be loaded.</param>
|
|
||||||
public override void OnLoadSettings(IEnumerable<Setting> settings)
|
|
||||||
{
|
|
||||||
using (RegistryKey registryKey = RegistryKey.OpenSubKey(SubKeyPath))
|
|
||||||
{
|
|
||||||
if (registryKey != null)
|
|
||||||
{
|
|
||||||
foreach (var setting in settings)
|
|
||||||
{
|
|
||||||
object value = registryKey.GetValue(setting.Name);
|
|
||||||
if (value != null)
|
|
||||||
setting.SetValue(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,117 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace FSI.Lib.WinSettings
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Represents a single setting for <see cref="Settings"></see>-derived classes.
|
|
||||||
/// </summary>
|
|
||||||
public class Setting
|
|
||||||
{
|
|
||||||
private readonly Settings Settings;
|
|
||||||
private readonly PropertyInfo PropertyInfo;
|
|
||||||
private readonly bool Encrypted;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a new instance of the <see cref="Setting"></see> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="settings">The <see cref="Settings"/> class that contains
|
|
||||||
/// this property (setting).</param>
|
|
||||||
/// <param name="propertyInfo">The <see cref="PropertyInfo"></see> for this
|
|
||||||
/// property.</param>
|
|
||||||
/// <param name="encrypted">Indicates whether or not this setting is
|
|
||||||
/// encrypted.</param>
|
|
||||||
public Setting(Settings settings, PropertyInfo propertyInfo, bool encrypted)
|
|
||||||
{
|
|
||||||
Settings = settings;
|
|
||||||
PropertyInfo = propertyInfo;
|
|
||||||
Encrypted = encrypted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the name of this setting.
|
|
||||||
/// </summary>
|
|
||||||
public string Name => PropertyInfo.Name;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the type of this setting.
|
|
||||||
/// </summary>
|
|
||||||
public Type Type => Encrypted ? typeof(string) : PropertyInfo.PropertyType;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the value of this setting.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Returns the value of this setting.</returns>
|
|
||||||
public object GetValue()
|
|
||||||
{
|
|
||||||
object value = PropertyInfo.GetValue(Settings);
|
|
||||||
if (value != null && Encrypted && Settings.Encryption != null)
|
|
||||||
return Settings.Encryption.Encrypt(value);
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the value of this setting.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The value this setting should be set to.</param>
|
|
||||||
public void SetValue(object value)
|
|
||||||
{
|
|
||||||
// Leave property value unmodified if no value or error
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Encrypted && Settings.Encryption != null)
|
|
||||||
{
|
|
||||||
// Ecrypted values stored as string
|
|
||||||
if (value is string s)
|
|
||||||
PropertyInfo.SetValue(Settings, Settings.Encryption.Decrypt(s, PropertyInfo.PropertyType));
|
|
||||||
}
|
|
||||||
else PropertyInfo.SetValue(Settings, Convert.ChangeType(value, Type));
|
|
||||||
}
|
|
||||||
catch (Exception) { Debug.Assert(false); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets this setting's value as a string.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Returns this setting's value as a string.</returns>
|
|
||||||
public string GetValueAsString()
|
|
||||||
{
|
|
||||||
object value = GetValue();
|
|
||||||
|
|
||||||
if (value == null)
|
|
||||||
return string.Empty;
|
|
||||||
else if (value is byte[] byteArray)
|
|
||||||
return ArrayToString.Encode(byteArray.Select(b => b.ToString()).ToArray());
|
|
||||||
else if (value is string[] stringArray)
|
|
||||||
return ArrayToString.Encode(stringArray);
|
|
||||||
else
|
|
||||||
return value?.ToString() ?? string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets this setting's value from a string.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">A string that represents the value this setting should be set to.</param>
|
|
||||||
public void SetValueFromString(string value)
|
|
||||||
{
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Type == typeof(byte[]))
|
|
||||||
SetValue(ArrayToString.Decode(value).Select(s => byte.Parse(s)).ToArray());
|
|
||||||
else if (Type == typeof(string[]))
|
|
||||||
SetValue(ArrayToString.Decode(value));
|
|
||||||
else
|
|
||||||
SetValue(value);
|
|
||||||
}
|
|
||||||
catch (Exception) { Debug.Assert(false); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
using FSI.Lib.EasyEncryption;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
namespace FSI.Lib.WinSettings
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Provides an abstract base class for specialized settings classes.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// <para>
|
|
||||||
/// Specialized classes should inherit from this class and implement specific storage and
|
|
||||||
/// retrieval logic for each settings by overriding the
|
|
||||||
/// <see cref="OnSaveSettings(IEnumerable{Setting})"/> and
|
|
||||||
/// <see cref="OnLoadSettings(IEnumerable{Setting})"/> methods.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// Ultimately, the specialized classes will then be overridden by each application's
|
|
||||||
/// settings class. The public properties in that class will become the settings that
|
|
||||||
/// are saved by classes that derive from this class.
|
|
||||||
/// </para>
|
|
||||||
/// </remarks>
|
|
||||||
public abstract class Settings
|
|
||||||
{
|
|
||||||
private IEnumerable<Setting> SettingsList { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Abstract method called when the settings should be saved. Allows
|
|
||||||
/// the derived class to save those settings in a specialized way.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="settings">The list of settings to be saved.</param>
|
|
||||||
public abstract void OnSaveSettings(IEnumerable<Setting> settings);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Abstract method called when the settings sould be loaded. Allows
|
|
||||||
/// the derived class to load those settings in a specialized way.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="settings">The list of settings to be loaded.</param>
|
|
||||||
public abstract void OnLoadSettings(IEnumerable<Setting> settings);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the <c>Encryption</c> instance associated with this <c>Settings</c>
|
|
||||||
/// instance.
|
|
||||||
/// </summary>
|
|
||||||
[ExcludedSetting]
|
|
||||||
public Encryption? Encryption { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs a new <see cref="Settings"></see> instance.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// An exception is thrown if password is null but one or more properties have the
|
|
||||||
/// <see cref="EncryptedSettingAttribute"></see> attribute.
|
|
||||||
/// </remarks>
|
|
||||||
/// <param name="password">Encryption password. Can be <c>null</c> if no
|
|
||||||
/// properties have the <see cref="EncryptedSettingAttribute"></see>
|
|
||||||
/// attribute.</param>
|
|
||||||
public Settings(string password = null)
|
|
||||||
{
|
|
||||||
if (password == null)
|
|
||||||
password = GetType().Namespace.ToString();
|
|
||||||
|
|
||||||
SettingsList = BuildSettingsList();
|
|
||||||
Encryption = password != null ?
|
|
||||||
new Encryption(password, EncryptionAlgorithm.TripleDes) :
|
|
||||||
null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Saves all settings.
|
|
||||||
/// </summary>
|
|
||||||
public void Save()
|
|
||||||
{
|
|
||||||
OnSaveSettings(SettingsList);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Loads all settings.
|
|
||||||
/// </summary>
|
|
||||||
public void Load()
|
|
||||||
{
|
|
||||||
OnLoadSettings(SettingsList);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<Setting> BuildSettingsList()
|
|
||||||
{
|
|
||||||
// Iterate through all public instance properties
|
|
||||||
foreach (PropertyInfo prop in GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public))
|
|
||||||
{
|
|
||||||
// Ignore properties with ExcludedSetting attribute
|
|
||||||
if (!Attribute.IsDefined(prop, typeof(ExcludedSettingAttribute)))
|
|
||||||
{
|
|
||||||
// Test for supported data type (same types as for Encryption class)
|
|
||||||
if (!Encryption.IsTypeSupported(prop.PropertyType))
|
|
||||||
throw new Exception(string.Format("Settings property '{0}' is an unsupported data type '{1}'. Change property type or use ExcludedSetting attribute.",
|
|
||||||
prop.Name, prop.PropertyType.ToString()));
|
|
||||||
bool encrypted = Attribute.IsDefined(prop, typeof(EncryptedSettingAttribute));
|
|
||||||
if (encrypted && Encryption == null)
|
|
||||||
throw new InvalidOperationException("Encryption password cannot be null if any settings have the EncryptedSetting attribute.");
|
|
||||||
yield return new Setting(this, prop, encrypted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Xml;
|
|
||||||
|
|
||||||
namespace FSI.Lib.WinSettings;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The <see cref="XmlSettings"/> class makes it very easy to save your application
|
|
||||||
/// settings to an XML file.
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>
|
|
||||||
/// <para>
|
|
||||||
/// To use the class, simply derive your own settings class from
|
|
||||||
/// <see cref="XmlSettings" /> and add the public properties that you want to be
|
|
||||||
/// saved as settings. You can then call the <see cref="Settings.Load"/> and
|
|
||||||
/// <see cref="Settings.Save"/> methods to read or write those settings to an XML
|
|
||||||
/// file.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// Your derived class' constructor should initialize your settings properties to
|
|
||||||
/// their default values.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// Two attributes are available for public properties in your derived class. The
|
|
||||||
/// first is <see cref="EncryptedSettingAttribute" />. Use this attribute if you
|
|
||||||
/// want the setting to be encrypted when saved to file. When using this attribute on
|
|
||||||
/// any property, you must provide a valid encryption password to the
|
|
||||||
/// <see cref="XmlSettings" /> constructor.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// The second is the <see cref="ExcludedSettingAttribute"/>. Use this attribute
|
|
||||||
/// on any properties that are used internally by your code and should not saved to
|
|
||||||
/// file.
|
|
||||||
/// </para>
|
|
||||||
/// <para>
|
|
||||||
/// All public properties without the <see cref="ExcludedSettingAttribute"></see>
|
|
||||||
/// attribute must be of one of the supported data types. This includes all the basic
|
|
||||||
/// data types as well as <see cref="string[]"></see> and <see cref="byte[]"></see>.
|
|
||||||
/// All other types will raise an exception.
|
|
||||||
/// </para>
|
|
||||||
/// </remarks>
|
|
||||||
/// <example>
|
|
||||||
/// The following example creates a settings class called <c>MySettings</c> with
|
|
||||||
/// several properties, two of which are encrypted when saved to file.
|
|
||||||
/// <code>
|
|
||||||
/// public class MySettings : XmlSettings
|
|
||||||
/// {
|
|
||||||
/// // Define properties to be saved to file
|
|
||||||
/// public string EmailHost { get; set; }
|
|
||||||
/// public int EmailPort { get; set; }
|
|
||||||
///
|
|
||||||
/// // The following properties will be encrypted
|
|
||||||
/// [EncryptedSetting]
|
|
||||||
/// public string UserName { get; set; }
|
|
||||||
/// [EncryptedSetting]
|
|
||||||
/// public string Password { get; set; }
|
|
||||||
///
|
|
||||||
/// // The following property will not be saved to file
|
|
||||||
/// // Non-public properties are also not saved to file
|
|
||||||
/// [ExcludedSetting]
|
|
||||||
/// public DateTime Created { get; set; }
|
|
||||||
///
|
|
||||||
/// public MySettings(string filename)
|
|
||||||
/// : base(filename, "Password123")
|
|
||||||
/// {
|
|
||||||
/// // Set initial, default property values
|
|
||||||
/// EmailHost = string.Empty;
|
|
||||||
/// EmailPort = 0;
|
|
||||||
/// UserName = string.Empty;
|
|
||||||
/// Password = string.Empty;
|
|
||||||
///
|
|
||||||
/// Created = DateTime.Now;
|
|
||||||
/// }
|
|
||||||
/// }
|
|
||||||
/// </code>
|
|
||||||
/// </example>
|
|
||||||
/// <seealso cref="IniSettings"/>
|
|
||||||
/// <seealso cref="RegistrySettings"/>
|
|
||||||
public abstract class XmlSettings : Settings
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the name of the XML settings file.
|
|
||||||
/// </summary>
|
|
||||||
[ExcludedSetting]
|
|
||||||
public string FileName { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Constructs an instance of the <see cref="XmlSettings"></see> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filename">Name of the settings file.</param>
|
|
||||||
/// <param name="password">Encryption password. May be <c>null</c> if
|
|
||||||
/// no settings use the <see cref="EncryptedSettingAttribute" />
|
|
||||||
/// attribute.</param>
|
|
||||||
public XmlSettings(string filename, string password = null)
|
|
||||||
: base(password)
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(filename))
|
|
||||||
throw new ArgumentException("A valid file name is required.", nameof(filename));
|
|
||||||
FileName = filename;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Performs internal load operations.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="settings">Settings to be loaded.</param>
|
|
||||||
public override void OnLoadSettings(IEnumerable<Setting> settings)
|
|
||||||
{
|
|
||||||
if (File.Exists(FileName))
|
|
||||||
{
|
|
||||||
// Load XML document
|
|
||||||
XmlDocument doc = new XmlDocument();
|
|
||||||
doc.Load(FileName);
|
|
||||||
// Read settings
|
|
||||||
foreach (Setting setting in settings)
|
|
||||||
{
|
|
||||||
XmlNode node = doc.DocumentElement?.SelectSingleNode(setting.Name);
|
|
||||||
if (node != null)
|
|
||||||
setting.SetValueFromString(node.InnerText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Performs internal save operations.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="settings">Settings to be saved.</param>
|
|
||||||
public override void OnSaveSettings(IEnumerable<Setting> settings)
|
|
||||||
{
|
|
||||||
// Create settings document
|
|
||||||
XmlDocument doc = new XmlDocument();
|
|
||||||
doc.AppendChild(doc.CreateXmlDeclaration("1.0", "UTF-8", null));
|
|
||||||
doc.AppendChild(doc.CreateElement("Settings"));
|
|
||||||
// Write settings
|
|
||||||
foreach (Setting setting in settings)
|
|
||||||
{
|
|
||||||
string value = setting.GetValueAsString();
|
|
||||||
if (value != null)
|
|
||||||
{
|
|
||||||
XmlElement element = doc.CreateElement(setting.Name);
|
|
||||||
element.InnerText = value;
|
|
||||||
doc.DocumentElement!.AppendChild(element);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
doc.Save(FileName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Text;
|
|
||||||
using System.Windows.Data;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Wpf.Converter
|
|
||||||
{
|
|
||||||
public class BooleanConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
return !((bool)value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ProvideValue(IServiceProvider serviceProvider)
|
|
||||||
{
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Windows.Data;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Wpf.Converters
|
|
||||||
{
|
|
||||||
|
|
||||||
public class InvertedBoolenConverter : IValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
return !(bool)value;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
return (bool)value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<UserControl x:Class="FSI.Lib.Wpf.Ctrls.ChbWindowsTopMost"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:local="clr-namespace:FSI.Lib.Wpf.Ctrls"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Width="Auto"
|
|
||||||
Height="Auto">
|
|
||||||
<StackPanel>
|
|
||||||
<CheckBox Name="chbTopMost"
|
|
||||||
Content="Fenster immer im Vordergrund"
|
|
||||||
Checked="CheckBox_Checked"
|
|
||||||
Unchecked="CheckBox_Unchecked" />
|
|
||||||
</StackPanel>
|
|
||||||
</UserControl>
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Interop;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Wpf.Ctrls
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interaktionslogik für ChbWindowsTopMost.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class ChbWindowsTopMost : UserControl
|
|
||||||
{
|
|
||||||
private Window _window;
|
|
||||||
|
|
||||||
//A window receives this message when the user chooses a command from the Window menu, or when the user chooses the maximize button, minimize button, restore button, or close button.
|
|
||||||
public const Int32 WM_SYSCOMMAND = 0x112;
|
|
||||||
|
|
||||||
//Draws a horizontal dividing line.This flag is used only in a drop-down menu, submenu, or shortcut menu.The line cannot be grayed, disabled, or highlighted.
|
|
||||||
public const Int32 MF_SEPARATOR = 0x800;
|
|
||||||
|
|
||||||
//Specifies that an ID is a position index into the menu and not a command ID.
|
|
||||||
public const Int32 MF_BYPOSITION = 0x400;
|
|
||||||
|
|
||||||
//Specifies that the menu item is a text string.
|
|
||||||
public const Int32 MF_STRING = 0x0;
|
|
||||||
|
|
||||||
//Menu Ids for our custom menu items
|
|
||||||
public const Int32 _ItemTopMostId = 1000;
|
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
|
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
private static extern bool InsertMenu(IntPtr hMenu, Int32 wPosition, Int32 wFlags, Int32 wIDNewItem, string lpNewItem);
|
|
||||||
|
|
||||||
public ChbWindowsTopMost()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
Loaded += ChbWindowsTopMost_Loaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ChbWindowsTopMost_Loaded(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
_window = Window.GetWindow(this);
|
|
||||||
|
|
||||||
IntPtr windowhandle = new WindowInteropHelper(_window).Handle;
|
|
||||||
HwndSource hwndSource = HwndSource.FromHwnd(windowhandle);
|
|
||||||
|
|
||||||
//Get the handle for the system menu
|
|
||||||
IntPtr systemMenuHandle = GetSystemMenu(windowhandle, false);
|
|
||||||
|
|
||||||
//Insert our custom menu items
|
|
||||||
InsertMenu(systemMenuHandle, 5, MF_BYPOSITION | MF_SEPARATOR, 0, string.Empty); //Add a menu seperator
|
|
||||||
InsertMenu(systemMenuHandle, 6, MF_BYPOSITION, _ItemTopMostId, "immer im Vordergrund"); //Add a setting menu item
|
|
||||||
|
|
||||||
hwndSource.AddHook(new HwndSourceHook(WndProc));
|
|
||||||
}
|
|
||||||
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
|
||||||
{
|
|
||||||
// Check if the SystemCommand message has been executed
|
|
||||||
if (msg == WM_SYSCOMMAND)
|
|
||||||
{
|
|
||||||
//check which menu item was clicked
|
|
||||||
switch (wParam.ToInt32())
|
|
||||||
{
|
|
||||||
case _ItemTopMostId:
|
|
||||||
_window.Topmost = !_window.Topmost;
|
|
||||||
chbTopMost.IsChecked = _window.Topmost;
|
|
||||||
handled = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return IntPtr.Zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CheckBox_Checked(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
_window.Topmost = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CheckBox_Unchecked(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
_window.Topmost = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
using System.Windows;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Wpf.Ctrls.FilterDataGrid
|
|
||||||
{
|
|
||||||
public sealed class DataGridTemplateColumn : System.Windows.Controls.DataGridTemplateColumn
|
|
||||||
{
|
|
||||||
#region Public Fields
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// FieldName Dependency Property.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty FieldNameProperty =
|
|
||||||
DependencyProperty.Register("FieldName", typeof(string), typeof(DataGridTemplateColumn),
|
|
||||||
new PropertyMetadata(""));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// IsColumnFiltered Dependency Property.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty IsColumnFilteredProperty =
|
|
||||||
DependencyProperty.Register("IsColumnFiltered", typeof(bool), typeof(DataGridTemplateColumn),
|
|
||||||
new PropertyMetadata(false));
|
|
||||||
|
|
||||||
#endregion Public Fields
|
|
||||||
|
|
||||||
#region Public Properties
|
|
||||||
|
|
||||||
public string FieldName
|
|
||||||
{
|
|
||||||
get => (string)GetValue(FieldNameProperty);
|
|
||||||
set => SetValue(FieldNameProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsColumnFiltered
|
|
||||||
{
|
|
||||||
get => (bool)GetValue(IsColumnFilteredProperty);
|
|
||||||
set => SetValue(IsColumnFilteredProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Public Properties
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class DataGridTextColumn : System.Windows.Controls.DataGridTextColumn
|
|
||||||
{
|
|
||||||
#region Public Fields
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// FieldName Dependency Property.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty FieldNameProperty =
|
|
||||||
DependencyProperty.Register("FieldName", typeof(string), typeof(DataGridTextColumn),
|
|
||||||
new PropertyMetadata(""));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// IsColumnFiltered Dependency Property.
|
|
||||||
/// </summary>
|
|
||||||
public static readonly DependencyProperty IsColumnFilteredProperty =
|
|
||||||
DependencyProperty.Register("IsColumnFiltered", typeof(bool), typeof(DataGridTextColumn),
|
|
||||||
new PropertyMetadata(false));
|
|
||||||
|
|
||||||
#endregion Public Fields
|
|
||||||
|
|
||||||
#region Public Properties
|
|
||||||
|
|
||||||
public string FieldName
|
|
||||||
{
|
|
||||||
get => (string)GetValue(FieldNameProperty);
|
|
||||||
set => SetValue(FieldNameProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsColumnFiltered
|
|
||||||
{
|
|
||||||
get => (bool)GetValue(IsColumnFilteredProperty);
|
|
||||||
set => SetValue(IsColumnFilteredProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Public Properties
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,319 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Wpf.Ctrls.FilterDataGrid
|
|
||||||
{
|
|
||||||
public sealed class FilterCommon : NotifyProperty
|
|
||||||
{
|
|
||||||
#region Public Constructors
|
|
||||||
|
|
||||||
public FilterCommon()
|
|
||||||
{
|
|
||||||
PreviouslyFilteredItems = new HashSet<object>(EqualityComparer<object>.Default);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Public Constructors
|
|
||||||
|
|
||||||
#region Public Properties
|
|
||||||
|
|
||||||
public string FieldName { get; set; }
|
|
||||||
public Type FieldType { get; set; }
|
|
||||||
public bool IsFiltered { get; set; }
|
|
||||||
public HashSet<object> PreviouslyFilteredItems { get; set; }
|
|
||||||
|
|
||||||
// Treeview
|
|
||||||
public List<FilterItem> Tree { get; set; }
|
|
||||||
|
|
||||||
public Loc Translate { get; set; }
|
|
||||||
|
|
||||||
#endregion Public Properties
|
|
||||||
|
|
||||||
#region Private Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Recursive call for check/uncheck all items in tree
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="state"></param>
|
|
||||||
/// <param name="updateChildren"></param>
|
|
||||||
/// <param name="updateParent"></param>
|
|
||||||
private void SetIsChecked(FilterItem item, bool? state, bool updateChildren, bool updateParent)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (state == item.IsChecked) return;
|
|
||||||
item.SetState = state;
|
|
||||||
|
|
||||||
// select all / unselect all
|
|
||||||
if (item.Level == 0)
|
|
||||||
Tree.Where(t => t.Level != 0).ToList().ForEach(c => { SetIsChecked(c, state, true, true); });
|
|
||||||
|
|
||||||
// update children
|
|
||||||
if (updateChildren && item.IsChecked.HasValue)
|
|
||||||
item.Children?.ForEach(c => { SetIsChecked(c, state, true, false); });
|
|
||||||
|
|
||||||
// update parent
|
|
||||||
if (updateParent && item.Parent != null)
|
|
||||||
VerifyCheckedState(item.Parent);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Debug.WriteLine($"FilterCommon.SetState : {ex.Message}");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update the tree when the state of the IsChecked property changes
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="o">item</param>
|
|
||||||
/// <param name="e">state</param>
|
|
||||||
public void UpdateTree(object o, bool? e)
|
|
||||||
{
|
|
||||||
if (o == null) return;
|
|
||||||
var item = (FilterItem)o;
|
|
||||||
SetIsChecked(item, e, true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Check or uncheck parents or children
|
|
||||||
/// </summary>
|
|
||||||
private void VerifyCheckedState(FilterItem item)
|
|
||||||
{
|
|
||||||
bool? state = null;
|
|
||||||
|
|
||||||
for (var i = 0; i < item.Children?.Count; ++i)
|
|
||||||
{
|
|
||||||
var current = item.Children[i].IsChecked;
|
|
||||||
|
|
||||||
if (i == 0)
|
|
||||||
{
|
|
||||||
state = current;
|
|
||||||
}
|
|
||||||
else if (state != current)
|
|
||||||
{
|
|
||||||
state = null;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SetIsChecked(item, state, false, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Private Methods
|
|
||||||
|
|
||||||
#region Public Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Add the filter to the predicate dictionary
|
|
||||||
/// </summary>
|
|
||||||
public void AddFilter(Dictionary<string, Predicate<object>> criteria)
|
|
||||||
{
|
|
||||||
if (IsFiltered) return;
|
|
||||||
|
|
||||||
// predicate of filter
|
|
||||||
bool Predicate(object o)
|
|
||||||
{
|
|
||||||
var value = o.GetType().GetProperty(FieldName)?.GetValue(o, null);
|
|
||||||
return !PreviouslyFilteredItems.Contains(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// add to list of predicates
|
|
||||||
criteria.Add(FieldName, Predicate);
|
|
||||||
|
|
||||||
IsFiltered = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Any Date IsChecked, check if any tree item is checked (can apply filter)
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool AnyDateIsChecked()
|
|
||||||
{
|
|
||||||
// any IsChecked is true or null
|
|
||||||
// IsDate Checked has three states, isChecked: null and true
|
|
||||||
return Tree != null && Tree.Skip(1).Any(t => t.IsChecked != false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Any state of Date Changed, check if at least one date is checked and another is changed
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool AnyDateChanged()
|
|
||||||
{
|
|
||||||
// any (year, month, day) status changed
|
|
||||||
return Tree != null &&
|
|
||||||
Tree.Skip(1)
|
|
||||||
.Any(year => year.Changed || year.Children
|
|
||||||
.Any(month => month.Changed || month.Children
|
|
||||||
.Any(day => day.Changed))) && AnyDateIsChecked();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Build the item tree
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dates"></param>
|
|
||||||
/// <param name="currentFilter"></param>
|
|
||||||
/// <param name="uncheckPrevious"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IEnumerable<FilterItem> BuildTree(IEnumerable<object> dates, string lastFilter = null)
|
|
||||||
{
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var uncheckPrevious = FieldName == lastFilter;
|
|
||||||
var type = typeof(DateTime);
|
|
||||||
|
|
||||||
Tree = new List<FilterItem>
|
|
||||||
{
|
|
||||||
new FilterItem(this)
|
|
||||||
{
|
|
||||||
Label = Translate.All, CurrentFilter = this, Content = 0, Level = 0, SetState = true, FieldType = type
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (dates == null) return Tree;
|
|
||||||
// iterate over all items that are not null
|
|
||||||
// INFO:
|
|
||||||
// SetState : does not raise OnDateStatusChanged event
|
|
||||||
// IsChecked : raise OnDateStatusChanged event
|
|
||||||
// (see the FilterItem class for more informations)
|
|
||||||
|
|
||||||
var dateTimes = dates.ToList();
|
|
||||||
|
|
||||||
foreach (var y in from date in dateTimes.Where(d => d != null)
|
|
||||||
.Select(d => (DateTime)d).OrderBy(o => o.Year)
|
|
||||||
group date by date.Year into year
|
|
||||||
select new FilterItem(this)
|
|
||||||
{
|
|
||||||
// YEAR
|
|
||||||
Level = 1,
|
|
||||||
CurrentFilter = this,
|
|
||||||
Content = year.Key,
|
|
||||||
Label = year.First().ToString("yyyy", Translate.Culture),
|
|
||||||
SetState = true, // default state
|
|
||||||
FieldType = type,
|
|
||||||
|
|
||||||
Children = (from date in year
|
|
||||||
group date by date.Month into month
|
|
||||||
select new FilterItem(this)
|
|
||||||
{
|
|
||||||
// MOUNTH
|
|
||||||
Level = 2,
|
|
||||||
CurrentFilter = this,
|
|
||||||
Content = month.Key,
|
|
||||||
Label = month.First().ToString("MMMM", Translate.Culture),
|
|
||||||
SetState = true, // default state
|
|
||||||
FieldType = type,
|
|
||||||
|
|
||||||
Children = (from day in month
|
|
||||||
select new FilterItem(this)
|
|
||||||
{
|
|
||||||
// DAY
|
|
||||||
Level = 3,
|
|
||||||
CurrentFilter = this,
|
|
||||||
Content = day.Day,
|
|
||||||
Label = day.ToString("dd", Translate.Culture),
|
|
||||||
SetState = true, // default state
|
|
||||||
FieldType = type,
|
|
||||||
Children = new List<FilterItem>()
|
|
||||||
}).ToList()
|
|
||||||
}).ToList()
|
|
||||||
})
|
|
||||||
{
|
|
||||||
// set parent and IsChecked property if uncheckPrevious items
|
|
||||||
y.Children.ForEach(m =>
|
|
||||||
{
|
|
||||||
m.Parent = y;
|
|
||||||
|
|
||||||
m.Children.ForEach(d =>
|
|
||||||
{
|
|
||||||
d.Parent = m;
|
|
||||||
|
|
||||||
// set the state of the ischecked property based on the items already filtered (unchecked)
|
|
||||||
if (PreviouslyFilteredItems != null && uncheckPrevious)
|
|
||||||
d.IsChecked = PreviouslyFilteredItems
|
|
||||||
.Any(u => u != null && u.Equals(new DateTime((int)y.Content, (int)m.Content, (int)d.Content))) == false;
|
|
||||||
|
|
||||||
// reset initialization with new state
|
|
||||||
d.InitialState = d.IsChecked;
|
|
||||||
});
|
|
||||||
|
|
||||||
// reset initialization with new state
|
|
||||||
m.InitialState = m.IsChecked;
|
|
||||||
});
|
|
||||||
|
|
||||||
// reset initialization with new state
|
|
||||||
y.InitialState = y.IsChecked;
|
|
||||||
|
|
||||||
Tree.Add(y);
|
|
||||||
}
|
|
||||||
|
|
||||||
// last empty item if exist in collection
|
|
||||||
if (dateTimes.Any(d => d == null))
|
|
||||||
Tree.Add(
|
|
||||||
new FilterItem(this)
|
|
||||||
{
|
|
||||||
Label = Translate.Empty, // translation
|
|
||||||
CurrentFilter = this,
|
|
||||||
Content = null,
|
|
||||||
Level = -1,
|
|
||||||
FieldType = type,
|
|
||||||
SetState = PreviouslyFilteredItems?.Any(u => u == null) == false,
|
|
||||||
Children = new List<FilterItem>()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Debug.WriteLine($"FilterCommon.BuildTree : {ex.Message}");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Tree;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get all the items from the tree (checked or unchecked)
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public IEnumerable<FilterItem> GetAllItemsTree()
|
|
||||||
{
|
|
||||||
var filterCommon = new List<FilterItem>();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// skip first item (select all)
|
|
||||||
foreach (var y in Tree.Skip(1))
|
|
||||||
if (y.Level > 0) // year :1, mounth : 2, day : 3
|
|
||||||
filterCommon.AddRange(
|
|
||||||
from m in y.Children
|
|
||||||
from d in m.Children
|
|
||||||
select new FilterItem
|
|
||||||
{
|
|
||||||
Content = new DateTime((int)y.Content, (int)m.Content, (int)d.Content),
|
|
||||||
IsChecked = d.IsChecked ?? false,
|
|
||||||
});
|
|
||||||
else // null date (Level -1)
|
|
||||||
filterCommon.Add(new FilterItem
|
|
||||||
{
|
|
||||||
Content = null,
|
|
||||||
IsChecked = y.IsChecked ?? false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Debug.WriteLine($"FilterCommon.GetAllItemsTree : {ex.Message}");
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
return filterCommon;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Public Methods
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,20 +0,0 @@
|
|||||||
namespace FSI.Lib.Wpf.Ctrls.FilterDataGrid
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// ResourceDictionary
|
|
||||||
/// </summary>
|
|
||||||
public partial class FilterDataGridDictionary
|
|
||||||
{
|
|
||||||
#region Public Constructors
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// FilterDataGrid Dictionary
|
|
||||||
/// </summary>
|
|
||||||
public FilterDataGridDictionary()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Public Constructors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,396 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Controls.Primitives;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Wpf.Ctrls.FilterDataGrid
|
|
||||||
{
|
|
||||||
public static class Extensions
|
|
||||||
{
|
|
||||||
#region Public Methods
|
|
||||||
|
|
||||||
public static HashSet<T> ToHashSet<T>(this IEnumerable<T> source, IEqualityComparer<T> comparer = null)
|
|
||||||
{
|
|
||||||
return new HashSet<T>(source, comparer);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Public Methods
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Helpers
|
|
||||||
{
|
|
||||||
#region Public Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Print elapsed time
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="label"></param>
|
|
||||||
/// <param name="start"></param>
|
|
||||||
public static void Elapsed(string label, DateTime start)
|
|
||||||
{
|
|
||||||
var span = DateTime.Now - start;
|
|
||||||
Debug.WriteLine($"{label,-20}{span:mm\\:ss\\.ff}");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Public Methods
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class VisualTreeHelpers
|
|
||||||
{
|
|
||||||
#region Private Methods
|
|
||||||
|
|
||||||
private static T FindVisualChild<T>(this DependencyObject dependencyObject, string name)
|
|
||||||
where T : DependencyObject
|
|
||||||
{
|
|
||||||
// Search immediate children first (breadth-first)
|
|
||||||
var childrenCount = VisualTreeHelper.GetChildrenCount(dependencyObject);
|
|
||||||
|
|
||||||
//http://stackoverflow.com/questions/12304904/why-visualtreehelper-getchildrencount-returns-0-for-popup
|
|
||||||
|
|
||||||
if (childrenCount == 0 && dependencyObject is Popup)
|
|
||||||
{
|
|
||||||
var popup = dependencyObject as Popup;
|
|
||||||
return popup.Child?.FindVisualChild<T>(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var i = 0; i < childrenCount; i++)
|
|
||||||
{
|
|
||||||
var child = VisualTreeHelper.GetChild(dependencyObject, i);
|
|
||||||
var nameOfChild = child.GetValue(FrameworkElement.NameProperty) as string;
|
|
||||||
|
|
||||||
if (child is T && (name == string.Empty || name == nameOfChild))
|
|
||||||
return (T)child;
|
|
||||||
var childOfChild = child.FindVisualChild<T>(name);
|
|
||||||
if (childOfChild != null)
|
|
||||||
return childOfChild;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<T> GetChildrenOf<T>(this DependencyObject obj, bool recursive) where T : DependencyObject
|
|
||||||
{
|
|
||||||
var count = VisualTreeHelper.GetChildrenCount(obj);
|
|
||||||
for (var i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
var child = VisualTreeHelper.GetChild(obj, i);
|
|
||||||
if (child is T) yield return (T)child;
|
|
||||||
|
|
||||||
if (recursive)
|
|
||||||
foreach (var item in child.GetChildrenOf<T>())
|
|
||||||
yield return item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<T> GetChildrenOf<T>(this DependencyObject obj) where T : DependencyObject
|
|
||||||
{
|
|
||||||
return obj.GetChildrenOf<T>(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This method is an alternative to WPF's
|
|
||||||
/// <see cref="VisualTreeHelper.GetParent" /> method, which also
|
|
||||||
/// supports content elements. Keep in mind that for content element,
|
|
||||||
/// this method falls back to the logical tree of the element!
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="child">The item to be processed.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// The submitted item's parent, if available. Otherwise
|
|
||||||
/// null.
|
|
||||||
/// </returns>
|
|
||||||
private static DependencyObject GetParentObject(this DependencyObject child)
|
|
||||||
{
|
|
||||||
if (child == null) return null;
|
|
||||||
|
|
||||||
//handle content elements separately
|
|
||||||
var contentElement = child as ContentElement;
|
|
||||||
if (contentElement != null)
|
|
||||||
{
|
|
||||||
var parent = ContentOperations.GetParent(contentElement);
|
|
||||||
if (parent != null) return parent;
|
|
||||||
|
|
||||||
var fce = contentElement as FrameworkContentElement;
|
|
||||||
return fce?.Parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
//also try searching for parent in framework elements (such as DockPanel, etc)
|
|
||||||
var frameworkElement = child as FrameworkElement;
|
|
||||||
if (frameworkElement != null)
|
|
||||||
{
|
|
||||||
var parent = frameworkElement.Parent;
|
|
||||||
if (parent != null) return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
//if it's not a ContentElement/FrameworkElement, rely on VisualTreeHelper
|
|
||||||
return VisualTreeHelper.GetParent(child);
|
|
||||||
}
|
|
||||||
#endregion Private Methods
|
|
||||||
|
|
||||||
#region Public Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the first ancester of specified type
|
|
||||||
/// </summary>
|
|
||||||
public static T FindAncestor<T>(DependencyObject current)
|
|
||||||
where T : DependencyObject
|
|
||||||
{
|
|
||||||
current = VisualTreeHelper.GetParent(current);
|
|
||||||
|
|
||||||
while (current != null)
|
|
||||||
{
|
|
||||||
if (current is T) return (T)current;
|
|
||||||
|
|
||||||
current = VisualTreeHelper.GetParent(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a specific ancester of an object
|
|
||||||
/// </summary>
|
|
||||||
public static T FindAncestor<T>(DependencyObject current, T lookupItem)
|
|
||||||
where T : DependencyObject
|
|
||||||
{
|
|
||||||
while (current != null)
|
|
||||||
{
|
|
||||||
if (current is T && current == lookupItem) return (T)current;
|
|
||||||
|
|
||||||
current = VisualTreeHelper.GetParent(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Finds an ancestor object by name and type
|
|
||||||
/// </summary>
|
|
||||||
public static T FindAncestor<T>(DependencyObject current, string parentName)
|
|
||||||
where T : DependencyObject
|
|
||||||
{
|
|
||||||
while (current != null)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(parentName))
|
|
||||||
{
|
|
||||||
var frameworkElement = current as FrameworkElement;
|
|
||||||
if (current is T && frameworkElement != null && frameworkElement.Name == parentName)
|
|
||||||
return (T)current;
|
|
||||||
}
|
|
||||||
else if (current is T)
|
|
||||||
{
|
|
||||||
return (T)current;
|
|
||||||
}
|
|
||||||
|
|
||||||
current = VisualTreeHelper.GetParent(current);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks for a child control within a parent by name
|
|
||||||
/// </summary>
|
|
||||||
public static T FindChild<T>(DependencyObject parent, string childName) where T : DependencyObject
|
|
||||||
{
|
|
||||||
// Confirm parent and childName are valid.
|
|
||||||
if (parent == null) return null;
|
|
||||||
|
|
||||||
T foundChild = null;
|
|
||||||
|
|
||||||
var childrenCount = VisualTreeHelper.GetChildrenCount(parent);
|
|
||||||
for (var i = 0; i < childrenCount; i++)
|
|
||||||
{
|
|
||||||
var child = VisualTreeHelper.GetChild(parent, i);
|
|
||||||
// If the child is not of the request child type child
|
|
||||||
var childType = child as T;
|
|
||||||
if (childType == null)
|
|
||||||
{
|
|
||||||
// recursively drill down the tree
|
|
||||||
foundChild = FindChild<T>(child, childName);
|
|
||||||
|
|
||||||
// If the child is found, break so we do not overwrite the found child.
|
|
||||||
if (foundChild != null) break;
|
|
||||||
}
|
|
||||||
else if (!string.IsNullOrEmpty(childName))
|
|
||||||
{
|
|
||||||
var frameworkElement = child as FrameworkElement;
|
|
||||||
// If the child's name is set for search
|
|
||||||
if (frameworkElement != null && frameworkElement.Name == childName)
|
|
||||||
{
|
|
||||||
// if the child's name is of the request name
|
|
||||||
foundChild = (T)child;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// recursively drill down the tree
|
|
||||||
foundChild = FindChild<T>(child, childName);
|
|
||||||
|
|
||||||
// If the child is found, break so we do not overwrite the found child.
|
|
||||||
if (foundChild != null) break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// child element found.
|
|
||||||
foundChild = (T)child;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return foundChild;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks for a child control within a parent by type
|
|
||||||
/// </summary>
|
|
||||||
public static T FindChild<T>(DependencyObject parent)
|
|
||||||
where T : DependencyObject
|
|
||||||
{
|
|
||||||
// Confirm parent is valid.
|
|
||||||
if (parent == null) return null;
|
|
||||||
|
|
||||||
T foundChild = null;
|
|
||||||
|
|
||||||
var childrenCount = VisualTreeHelper.GetChildrenCount(parent);
|
|
||||||
for (var i = 0; i < childrenCount; i++)
|
|
||||||
{
|
|
||||||
var child = VisualTreeHelper.GetChild(parent, i);
|
|
||||||
// If the child is not of the request child type child
|
|
||||||
var childType = child as T;
|
|
||||||
if (childType == null)
|
|
||||||
{
|
|
||||||
// recursively drill down the tree
|
|
||||||
foundChild = FindChild<T>(child);
|
|
||||||
|
|
||||||
// If the child is found, break so we do not overwrite the found child.
|
|
||||||
if (foundChild != null) break;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// child element found.
|
|
||||||
foundChild = (T)child;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return foundChild;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T FindVisualChild<T>(this DependencyObject dependencyObject) where T : DependencyObject
|
|
||||||
{
|
|
||||||
return dependencyObject.FindVisualChild<T>(string.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Visual GetDescendantByType(Visual element, Type type)
|
|
||||||
{
|
|
||||||
if (element == null) return null;
|
|
||||||
if (element.GetType() == type) return element;
|
|
||||||
Visual foundElement = null;
|
|
||||||
if (element is FrameworkElement frameworkElement) frameworkElement.ApplyTemplate();
|
|
||||||
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
|
|
||||||
{
|
|
||||||
var visual = VisualTreeHelper.GetChild(element, i) as Visual;
|
|
||||||
foundElement = GetDescendantByType(visual, type);
|
|
||||||
if (foundElement != null) break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return foundElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DataGridColumnHeader GetHeader(DataGridColumn column, DependencyObject reference)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(reference); i++)
|
|
||||||
{
|
|
||||||
var child = VisualTreeHelper.GetChild(reference, i);
|
|
||||||
|
|
||||||
if (child is DataGridColumnHeader colHeader && colHeader.Column == column) return colHeader;
|
|
||||||
|
|
||||||
colHeader = GetHeader(column, child);
|
|
||||||
if (colHeader != null) return colHeader;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Finds a parent of a given item on the visual tree.
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">The type of the queried item.</typeparam>
|
|
||||||
/// <param name="child">
|
|
||||||
/// A direct or indirect child of the
|
|
||||||
/// queried item.
|
|
||||||
/// </param>
|
|
||||||
/// <returns>
|
|
||||||
/// The first parent item that matches the submitted
|
|
||||||
/// type parameter. If not matching item can be found, a null
|
|
||||||
/// reference is being returned.
|
|
||||||
/// </returns>
|
|
||||||
public static T TryFindParent<T>(this DependencyObject child) where T : DependencyObject
|
|
||||||
{
|
|
||||||
//get parent item
|
|
||||||
var parentObject = GetParentObject(child);
|
|
||||||
|
|
||||||
//we've reached the end of the tree
|
|
||||||
if (parentObject == null) return null;
|
|
||||||
|
|
||||||
//check if the parent matches the type we're looking for
|
|
||||||
var parent = parentObject as T;
|
|
||||||
if (parent != null)
|
|
||||||
return parent;
|
|
||||||
return TryFindParent<T>(parentObject);
|
|
||||||
}
|
|
||||||
#endregion Public Methods
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Base class for all ViewModel classes in the application. Provides support for
|
|
||||||
/// property changes notification.
|
|
||||||
/// </summary>
|
|
||||||
[Serializable]
|
|
||||||
public abstract class NotifyProperty : INotifyPropertyChanged
|
|
||||||
{
|
|
||||||
#region Public Events
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raised when a property on this object has a new value.
|
|
||||||
/// </summary>
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
|
|
||||||
#endregion Public Events
|
|
||||||
|
|
||||||
#region Private Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Warns the developer if this object does not have a public property with
|
|
||||||
/// the specified name. This method does not exist in a Release build.
|
|
||||||
/// </summary>
|
|
||||||
[Conditional("DEBUG")]
|
|
||||||
[DebuggerStepThrough]
|
|
||||||
private void VerifyPropertyName(string propertyName)
|
|
||||||
{
|
|
||||||
// verify that the property name matches a real,
|
|
||||||
// public, instance property on this object.
|
|
||||||
if (TypeDescriptor.GetProperties(this)[propertyName] == null)
|
|
||||||
Debug.Fail("Invalid property name: " + propertyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Private Methods
|
|
||||||
|
|
||||||
#region Public Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raises this object's PropertyChanged event.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="propertyName">The name of the property that has a new value.</param>
|
|
||||||
public void OnPropertyChanged(string propertyName)
|
|
||||||
{
|
|
||||||
VerifyPropertyName(propertyName);
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Public Methods
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Wpf.Ctrls.FilterDataGrid
|
|
||||||
{
|
|
||||||
public class FilterItem : NotifyProperty
|
|
||||||
{
|
|
||||||
#region Public Events
|
|
||||||
|
|
||||||
private event EventHandler<bool?> OnDateStatusChanged;
|
|
||||||
|
|
||||||
#endregion Public Events
|
|
||||||
|
|
||||||
#region Constructor
|
|
||||||
|
|
||||||
public FilterItem(FilterCommon action = null)
|
|
||||||
{
|
|
||||||
// event subscription
|
|
||||||
if (action != null)
|
|
||||||
OnDateStatusChanged += action.UpdateTree;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Constructor
|
|
||||||
|
|
||||||
#region Private Fields
|
|
||||||
|
|
||||||
private bool? isChecked;
|
|
||||||
private bool initialized;
|
|
||||||
|
|
||||||
#endregion Private Fields
|
|
||||||
|
|
||||||
#region Public Properties
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
///Children higher levels (years, months)
|
|
||||||
/// </summary>
|
|
||||||
public List<FilterItem> Children { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Raw value of the item (not displayed, see Label property)
|
|
||||||
/// </summary>
|
|
||||||
public object Content { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Content length
|
|
||||||
/// </summary>
|
|
||||||
public int ContentLength { get; set; }
|
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Current filter
|
|
||||||
/// </summary>
|
|
||||||
public FilterCommon CurrentFilter { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Field type
|
|
||||||
/// </summary>
|
|
||||||
public Type FieldType { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initial state
|
|
||||||
/// </summary>
|
|
||||||
public bool? InitialState { get; set; }
|
|
||||||
|
|
||||||
public int Id { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// State of checkbox
|
|
||||||
/// </summary>
|
|
||||||
public bool? IsChecked
|
|
||||||
{
|
|
||||||
get => isChecked;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (!initialized)
|
|
||||||
{
|
|
||||||
InitialState = value;
|
|
||||||
initialized = true;
|
|
||||||
isChecked = value; // don't remove
|
|
||||||
|
|
||||||
// the iteration over an Collection triggers the notification
|
|
||||||
// of the "IsChecked" property and slows the performance of the loop,
|
|
||||||
// the return prevents the OnPropertyChanged
|
|
||||||
// notification at initialization
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// raise event to update the date tree, see FilterCommon class
|
|
||||||
// only type date type fields are subscribed to the OnDateStatusChanged event
|
|
||||||
// OnDateStatusChanged is not triggered at tree initialization
|
|
||||||
if (FieldType == typeof(DateTime))
|
|
||||||
{
|
|
||||||
OnDateStatusChanged?.Invoke(this, value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
isChecked = value;
|
|
||||||
OnPropertyChanged("IsChecked");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Content displayed
|
|
||||||
/// </summary>
|
|
||||||
public string Label { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hierarchical level for the date
|
|
||||||
/// </summary>
|
|
||||||
public int Level { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Parent of lower levels (days, months)
|
|
||||||
/// </summary>
|
|
||||||
public FilterItem Parent { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Set the state of the IsChecked property for date, does not invoke the update of the tree
|
|
||||||
/// </summary>
|
|
||||||
public bool? SetState
|
|
||||||
{
|
|
||||||
get => isChecked;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
isChecked = value;
|
|
||||||
|
|
||||||
if (!initialized)
|
|
||||||
{
|
|
||||||
InitialState = value;
|
|
||||||
initialized = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
OnPropertyChanged("IsChecked");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Checks if the initial state has changed
|
|
||||||
/// </summary>
|
|
||||||
public bool Changed => isChecked != InitialState;
|
|
||||||
|
|
||||||
#endregion Public Properties
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,235 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Globalization;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Wpf.Ctrls.FilterDataGrid
|
|
||||||
{
|
|
||||||
public enum Local
|
|
||||||
{
|
|
||||||
Chinese,
|
|
||||||
Dutch,
|
|
||||||
English,
|
|
||||||
French,
|
|
||||||
German,
|
|
||||||
Italian,
|
|
||||||
Russian,
|
|
||||||
}
|
|
||||||
|
|
||||||
public class Loc
|
|
||||||
{
|
|
||||||
#region Private Fields
|
|
||||||
|
|
||||||
private Local language;
|
|
||||||
|
|
||||||
// culture name(used for dates)
|
|
||||||
private static readonly Dictionary<Local, string> CultureNames = new Dictionary<Local, string>
|
|
||||||
{
|
|
||||||
{ Local.Chinese, "zh-Hans" },
|
|
||||||
{ Local.Dutch, "nl-NL" },
|
|
||||||
{ Local.English, "en-US" },
|
|
||||||
{ Local.French, "fr-FR" },
|
|
||||||
{ Local.German, "de-DE" },
|
|
||||||
{ Local.Italian, "it-IT" },
|
|
||||||
{ Local.Russian, "ru-RU" },
|
|
||||||
};
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Translation dictionary
|
|
||||||
/// </summary>
|
|
||||||
private static readonly Dictionary<string, Dictionary<Local, string>> Translation =
|
|
||||||
new Dictionary<string, Dictionary<Local, string>>
|
|
||||||
{
|
|
||||||
{
|
|
||||||
"All", new Dictionary<Local, string>
|
|
||||||
{
|
|
||||||
{ Local.Chinese, "(全选)" },
|
|
||||||
{ Local.Dutch, "(Alles selecteren)" },
|
|
||||||
{ Local.English, "(Select all)" },
|
|
||||||
{ Local.French, "(Sélectionner tout)" },
|
|
||||||
{ Local.German, "(Alle auswählen)" },
|
|
||||||
{ Local.Italian, "(Seleziona tutto)" },
|
|
||||||
{ Local.Russian, "(Выбрать все)" },
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Empty", new Dictionary<Local, string>
|
|
||||||
{
|
|
||||||
{ Local.Chinese, "(空白)" },
|
|
||||||
{ Local.Dutch, "(Leeg)" },
|
|
||||||
{ Local.English, "(Blank)" },
|
|
||||||
{ Local.French, "(Vides)" },
|
|
||||||
{ Local.German, "(Leer)" },
|
|
||||||
{ Local.Italian, "(Vuoto)" },
|
|
||||||
{ Local.Russian, "(Заготовки)" },
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Clear", new Dictionary<Local, string>
|
|
||||||
{
|
|
||||||
{ Local.Chinese, "清除过滤器 \"{0}\"" },
|
|
||||||
{ Local.Dutch, "Filter \"{0}\" verwijderen" },
|
|
||||||
{ Local.English, "Clear filter \"{0}\"" },
|
|
||||||
{ Local.French, "Effacer le filtre \"{0}\"" },
|
|
||||||
{ Local.German, "Filter löschen \"{0}\"" },
|
|
||||||
{ Local.Italian, "Cancella filtro \"{0}\"" },
|
|
||||||
{ Local.Russian, "Очистить фильтр \"{0}\"" },
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"Contains", new Dictionary<Local, string>
|
|
||||||
{
|
|
||||||
{ Local.Chinese, "搜索(包含)" },
|
|
||||||
{ Local.Dutch, "Zoek (bevat)" },
|
|
||||||
{ Local.English, "Search (contains)" },
|
|
||||||
{ Local.French, "Rechercher (contient)" },
|
|
||||||
{ Local.German, "Suche (enthält)" },
|
|
||||||
{ Local.Italian, "Cerca (contiene)" },
|
|
||||||
{ Local.Russian, "Искать (содержит)" },
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"StartsWith", new Dictionary<Local, string>
|
|
||||||
{
|
|
||||||
{ Local.Chinese, "搜索 (来自)" },
|
|
||||||
{ Local.Dutch, "Zoek (beginnen met)" },
|
|
||||||
{ Local.English, "Search (startswith)" },
|
|
||||||
{ Local.French, "Rechercher (commence par)" },
|
|
||||||
{ Local.German, "Suche (beginnen mit)" },
|
|
||||||
{ Local.Italian, "Cerca (inizia con)" },
|
|
||||||
{ Local.Russian, "Искать (hачни с)" },
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"Toggle", new Dictionary<Local, string>
|
|
||||||
{
|
|
||||||
{ Local.Chinese, "切換包含/開始於" },
|
|
||||||
{ Local.Dutch, "Toggle bevat/begint met" },
|
|
||||||
{ Local.English, "Toggle contains/startswith" },
|
|
||||||
{ Local.French, "Basculer contient/commence par" },
|
|
||||||
{ Local.German, "Toggle enthält/beginnt mit" },
|
|
||||||
{ Local.Italian, "Toggle contiene/inizia con" },
|
|
||||||
{ Local.Russian, "Переключить содержит/начинается с" },
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"Ok", new Dictionary<Local, string>
|
|
||||||
{
|
|
||||||
{ Local.Chinese, "确定" },
|
|
||||||
{ Local.Dutch, "Ok" },
|
|
||||||
{ Local.English, "Ok" },
|
|
||||||
{ Local.French, "Ok" },
|
|
||||||
{ Local.German, "Ok" },
|
|
||||||
{ Local.Italian, "Ok" },
|
|
||||||
{ Local.Russian, "Ok" },
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Cancel", new Dictionary<Local, string>
|
|
||||||
{
|
|
||||||
{ Local.Chinese, "取消" },
|
|
||||||
{ Local.Dutch, "Annuleren" },
|
|
||||||
{ Local.English, "Cancel" },
|
|
||||||
{ Local.French, "Annuler" },
|
|
||||||
{ Local.German, "Abbrechen" },
|
|
||||||
{ Local.Italian, "Annulla" },
|
|
||||||
{ Local.Russian, "Отмена" },
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Status", new Dictionary<Local, string>
|
|
||||||
{
|
|
||||||
{ Local.Chinese, "{0:n0} 找到了 {1:n0} 条记录" },
|
|
||||||
{ Local.Dutch, "{0:n0} rij(en) gevonden op {1:n0}" },
|
|
||||||
{ Local.English, "{0:n0} record(s) found on {1:n0}" },
|
|
||||||
{ Local.French, "{0:n0} enregistrement(s) trouvé(s) sur {1:n0}" },
|
|
||||||
{ Local.German, "{0:n0} zeilen angezeigt von {1:n0}" },
|
|
||||||
{ Local.Italian, "{0:n0} oggetti trovati su {1:n0}" },
|
|
||||||
{ Local.Russian, "{0:n0} записей найдено на {1:n0}" },
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ElapsedTime", new Dictionary<Local, string>
|
|
||||||
{
|
|
||||||
{ Local.Chinese, "经过时间{0:mm}:{0:ss}.{0:ff}" },
|
|
||||||
{ Local.Dutch, "Verstreken tijd {0:mm}:{0:ss}.{0:ff}" },
|
|
||||||
{ Local.English, "Elapsed time {0:mm}:{0:ss}.{0:ff}" },
|
|
||||||
{ Local.French, "Temps écoulé {0:mm}:{0:ss}.{0:ff}" },
|
|
||||||
{ Local.German, "Verstrichene Zeit {0:mm}:{0:ss}.{0:ff}" },
|
|
||||||
{ Local.Italian, "Tempo trascorso {0:mm}:{0:ss}.{0:ff}" },
|
|
||||||
{ Local.Russian, "Пройденное время {0:mm}:{0:ss}.{0:ff}" },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endregion Private Fields
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
|
|
||||||
public Loc()
|
|
||||||
{
|
|
||||||
Language = Local.English;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Constructors
|
|
||||||
|
|
||||||
#region Public Properties
|
|
||||||
|
|
||||||
public Local Language
|
|
||||||
{
|
|
||||||
get => language;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
language = value;
|
|
||||||
Culture = new CultureInfo(CultureNames[value]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public CultureInfo Culture { get; private set; }
|
|
||||||
|
|
||||||
public string CultureName => CultureNames[Language];
|
|
||||||
|
|
||||||
public string LanguageName => Enum.GetName(typeof(Local), Language);
|
|
||||||
|
|
||||||
public string All => Translate("All");
|
|
||||||
|
|
||||||
public string Cancel => Translate("Cancel");
|
|
||||||
|
|
||||||
public string Clear => Translate("Clear");
|
|
||||||
|
|
||||||
public string Contains => Translate("Contains");
|
|
||||||
|
|
||||||
public string ElapsedTime => Translate("ElapsedTime");
|
|
||||||
|
|
||||||
public string Empty => Translate("Empty");
|
|
||||||
|
|
||||||
public string Ok => Translate("Ok");
|
|
||||||
|
|
||||||
public string StartsWith => Translate("StartsWith");
|
|
||||||
|
|
||||||
public string Status => Translate("Status");
|
|
||||||
|
|
||||||
public string Toggle => Translate("Toggle");
|
|
||||||
|
|
||||||
#endregion Public Properties
|
|
||||||
|
|
||||||
#region Private Methods
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Translated into the language
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="key"></param>
|
|
||||||
/// <returns></returns>
|
|
||||||
private string Translate(string key)
|
|
||||||
{
|
|
||||||
return Translation.ContainsKey(key) && Translation[key].ContainsKey(Language)
|
|
||||||
? Translation[key][Language]
|
|
||||||
: "unknow";
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Private Methods
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
https://github.com/macgile/DataGridFilter
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Globalization;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Data;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Wpf.Ctrls.FilterDataGrid
|
|
||||||
{
|
|
||||||
public class StringFormatConverter : IMultiValueConverter
|
|
||||||
{
|
|
||||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// values [0] contains the format
|
|
||||||
if (values[0] == DependencyProperty.UnsetValue || string.IsNullOrEmpty(values[0]?.ToString()))
|
|
||||||
return string.Empty;
|
|
||||||
|
|
||||||
var stringFormat = values[0].ToString();
|
|
||||||
|
|
||||||
return string.Format(stringFormat, values.Skip(1).ToArray());
|
|
||||||
}
|
|
||||||
catch (FormatException ex)
|
|
||||||
{
|
|
||||||
Debug.WriteLine($"StringFormatConverter.Convert error: {ex.Message}");
|
|
||||||
return string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,880 +0,0 @@
|
|||||||
<ResourceDictionary x:Class="FSI.Lib.Wpf.Ctrls.FilterDataGrid.FilterDataGridDictionary"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:control="clr-namespace:FSI.Lib.Wpf.Ctrls.FilterDataGrid"
|
|
||||||
xmlns:sys="clr-namespace:System;assembly=mscorlib">
|
|
||||||
|
|
||||||
<!-- STRING FORMAT CONVERTER -->
|
|
||||||
<control:StringFormatConverter x:Key="StringFormatConverter" />
|
|
||||||
|
|
||||||
<!-- INITIAL POPUP SIZE -->
|
|
||||||
<sys:Double x:Key="PopupHeight">420</sys:Double>
|
|
||||||
<sys:Double x:Key="PopupWidth">262</sys:Double>
|
|
||||||
<sys:Boolean x:Key="StayOpen">False</sys:Boolean>
|
|
||||||
|
|
||||||
<!-- https://yqnn.github.io/svg-path-editor/ -->
|
|
||||||
|
|
||||||
<!-- FILTER SET ICON -->
|
|
||||||
<Geometry x:Key="FilterSet">
|
|
||||||
M 0 17 H 12 L 6 25 Z M 6 0 H 29 L 29 3 L 20 10 L 20 21 H 15 L 15 10 L 6 3 Z
|
|
||||||
</Geometry>
|
|
||||||
|
|
||||||
<!-- FILTER BUTTON ICON -->
|
|
||||||
<Geometry x:Key="Filter">
|
|
||||||
M 7 10 L 12 15 L 17 10 H 7 Z
|
|
||||||
</Geometry>
|
|
||||||
|
|
||||||
<!-- DELETE FILTER ICON -->
|
|
||||||
<Geometry x:Key="FilterDelete">
|
|
||||||
M11.1 11.4L8.5 8.9L9.8 7.6L12.3 10.1L14.8 7.6L16.1 8.9L13.6 11.4L16.1 13.9L14.8 15.2L12.3 12.6L9.8 15.2L8.5 13.9ZM0 0H13L13 2L8 6V14L5 11V6L0 2Z
|
|
||||||
</Geometry>
|
|
||||||
|
|
||||||
<!-- BOX CHECKED ICON -->
|
|
||||||
<Geometry x:Key="FilterChecked">
|
|
||||||
M 125 125 L 0 125 V 0 H 125 Z M 1 124 H 124 V 1 H 1 Z M 20 68 L 29 57 L 56 80 L 98 25 L 110 35 L 59 101 Z
|
|
||||||
</Geometry>
|
|
||||||
|
|
||||||
<!-- GRIPSIZE ICON -->
|
|
||||||
<Geometry x:Key="GripSizeIcon">
|
|
||||||
M0 9L2 9M4 9L6 9M8 9L10 9M1 8L1 10M5 8L5 10M9 8L9 10M4 5L6 5M8 5L10 5M5 4L5 6M9 4L9 6M8 1L10 1M9 0L9 2
|
|
||||||
</Geometry>
|
|
||||||
|
|
||||||
<!-- SEARCH MAGNIFIER ICON -->
|
|
||||||
<Geometry x:Key="Magnifier">
|
|
||||||
M9.6 8.5H9L8.7 8.2C9.6 7.4 10 6.2 10 5C10 2.2 7.8 0 5 0S0 2.2 0 5S2.2 10 5 10C6.2 10 7.4 9.6 8.2 8.7L8.5
|
|
||||||
9V9.6L12.3 13.5L13.5 12.3L9.6 8.5ZM5 8.5C3.1 8.5 1.5 6.9 1.5 5S3.1 1.5 5 1.5S8.5 3.1 8.5 5S6.9 8.5 5 8.5Z
|
|
||||||
</Geometry>
|
|
||||||
|
|
||||||
<!-- SEARCH DELETE ICON -->
|
|
||||||
<Geometry x:Key="Delete">
|
|
||||||
M 0 0 M 2 3 L 3 2 L 8 7 L 13 2 L 14 3 L 9 8 L 14 13 L 13 14 L 8 9 L 3 14 L 2 13 L 7 8 Z M 16 0 M 0 16 M 16 16
|
|
||||||
</Geometry>
|
|
||||||
|
|
||||||
<!-- SEARCH CONTAINS ICON -->
|
|
||||||
<Geometry x:Key="StartsWith">
|
|
||||||
M 0.6 1.3 V 0 C 1.1 -0.1 5.5 -1.7 6.2 1.6 V 7.2 H 5 V 6.2 C 4.5 6.7 4 7 3.5 7.2 H 1.4 C 0.4 6.8 0.1 6.1 0 5.2 C 0 4.7 0 3 3 2.8 H 4.9 V 1.7
|
|
||||||
C 4.4 0.2 2.3 0.6 1 1.1 Z M 4.9 5.1 V 3.8 H 2.6 V 3.8 C 1 3.9 0.9 6.2 2.6 6.2 C 3.5 6.2 4 5.9 4.7 5.3 Z M 9.3 0.9 L 9.5 3.5 L 7.4 2 L 6.9 2.9
|
|
||||||
L 9.2 4 L 6.9 5.1 L 7.3 6.1 L 9.5 4.7 L 9.3 7.2 H 10.4 L 10.2 4.6 L 12.3 6 L 12.8 5.1 L 10.5 4.1 L 12.8 2.9 L 12.3 2 L 10.2 3.5 L 10.4 0.9 Z
|
|
||||||
M 16.5 0.9 H 17.6 L 17.4 3.4 L 19.5 2 L 20 2.9 L 17.7 4 L 20 5.2 L 19.5 6 L 17.4 4.7 L 17.6 7.2 H 16.5 L 16.6 4.7 L 14.5 6 L 14 5.2 L 16.3 4
|
|
||||||
L 14 2.9 L 14.6 2 L 16.7 3.4 Z
|
|
||||||
</Geometry>
|
|
||||||
|
|
||||||
<!-- SEARCH STARTSWITH ICON -->
|
|
||||||
<Geometry x:Key="Contains">
|
|
||||||
M 7.2 1.3 V 0 C 7.7 -0.1 12.1 -1.7 12.8 1.6 V 7.2 H 11.6 V 6.2 C 11.1 6.7 10.6 7 10.1 7.2 H 8 C 7 6.8 6.7 6.1 6.6 5.2 C 6.6 4.7 6.6 3 9.6 2.8
|
|
||||||
H 11.5 V 1.7 C 11 0.2 8.9 0.6 7.6 1.1 Z M 11.5 5.1 V 3.8 H 9.2 C 7.5 4.1 8.1 6.2 9.2 6.2 C 10.1 6.2 10.6 5.9 11.3 5.3 Z M 2.4 1 L 2.6 3.5
|
|
||||||
L 0.5 2.1 L 0 3 L 2.2 4.1 L 0 5.3 L 0.4 6.1 L 2.6 4.7 L 2.4 7.2 H 3.5 L 3.3 4.7 L 5.4 6.1 L 5.9 5.2 L 3.6 4.1 L 5.9 3 L 5.4 2.1 L 3.3 3.5
|
|
||||||
L 3.5 1 Z M 16.5 0.9 H 17.6 L 17.4 3.5 L 19.5 2 L 20 3 L 17.7 4 L 20 5.2 L 19.5 6 L 17.4 4.7 L 17.6 7.2 H 16.5 L 16.6 4.7 L 14.5 6 L 14 5.2
|
|
||||||
L 16.3 4.1 L 14 2.9 L 14.6 2 L 16.6 3.4 Z
|
|
||||||
</Geometry>
|
|
||||||
|
|
||||||
<!-- PLACEHOLDER SEARCH BOX -->
|
|
||||||
<Style x:Key="PlaceHolder"
|
|
||||||
TargetType="{x:Type TextBox}">
|
|
||||||
<Setter Property="Background"
|
|
||||||
Value="Transparent" />
|
|
||||||
<Setter Property="BorderBrush"
|
|
||||||
Value="Transparent" />
|
|
||||||
<Setter Property="BorderThickness"
|
|
||||||
Value="0" />
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate x:Name="SearchControlTemplate"
|
|
||||||
TargetType="{x:Type TextBox}">
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<!-- SEARCH TEXTBOX -->
|
|
||||||
<TextBox x:Name="TextSource"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{TemplateBinding Margin}"
|
|
||||||
Padding="{TemplateBinding Padding}"
|
|
||||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
|
||||||
VerticalAlignment="{TemplateBinding VerticalAlignment}"
|
|
||||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
|
||||||
Panel.ZIndex="2"
|
|
||||||
Background="Transparent"
|
|
||||||
BorderBrush="Transparent"
|
|
||||||
BorderThickness="0"
|
|
||||||
Focusable="True"
|
|
||||||
FontSize="{TemplateBinding FontSize}"
|
|
||||||
FontWeight="{TemplateBinding FontWeight}"
|
|
||||||
MaxLength="{TemplateBinding MaxLength}"
|
|
||||||
Text="{Binding Path=Text, RelativeSource={RelativeSource TemplatedParent}, UpdateSourceTrigger=PropertyChanged}" />
|
|
||||||
<TextBox x:Name="TextBoxPlaceHolder"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="{TemplateBinding Margin}"
|
|
||||||
Padding="{TemplateBinding Padding}"
|
|
||||||
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
|
|
||||||
VerticalAlignment="{TemplateBinding VerticalAlignment}"
|
|
||||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
|
||||||
Panel.ZIndex="1"
|
|
||||||
Background="Transparent"
|
|
||||||
BorderBrush="Transparent"
|
|
||||||
BorderThickness="0"
|
|
||||||
FontSize="{TemplateBinding FontSize}"
|
|
||||||
FontWeight="{TemplateBinding FontWeight}"
|
|
||||||
MaxLength="{TemplateBinding MaxLength}"
|
|
||||||
Text="{TemplateBinding Tag}">
|
|
||||||
<TextBox.Style>
|
|
||||||
<Style TargetType="{x:Type TextBox}">
|
|
||||||
<Setter Property="Foreground"
|
|
||||||
Value="Transparent" />
|
|
||||||
<Style.Triggers>
|
|
||||||
<DataTrigger Binding="{Binding Path=Text, ElementName=TextSource}"
|
|
||||||
Value="">
|
|
||||||
<Setter Property="Foreground"
|
|
||||||
Value="LightGray" />
|
|
||||||
</DataTrigger>
|
|
||||||
</Style.Triggers>
|
|
||||||
</Style>
|
|
||||||
</TextBox.Style>
|
|
||||||
</TextBox>
|
|
||||||
|
|
||||||
<!-- BUTTON CLEAR FILTER -->
|
|
||||||
<Button x:Name="ClearSearchBoxBtn"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="2"
|
|
||||||
Background="Transparent"
|
|
||||||
Command="{x:Static control:FilterDataGrid.ClearSearchBox}"
|
|
||||||
SnapsToDevicePixels="True"
|
|
||||||
UseLayoutRounding="True">
|
|
||||||
<Button.Style>
|
|
||||||
<Style TargetType="{x:Type Button}">
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="Button">
|
|
||||||
<Border Background="Transparent"
|
|
||||||
SnapsToDevicePixels="True">
|
|
||||||
<!-- MAGNIFIER / DELETE ICON -->
|
|
||||||
<Path x:Name="PathButton"
|
|
||||||
Width="18"
|
|
||||||
Height="18"
|
|
||||||
Margin="0"
|
|
||||||
Data="{StaticResource Delete}"
|
|
||||||
Fill="DarkSlateGray"
|
|
||||||
SnapsToDevicePixels="True"
|
|
||||||
Stretch="Uniform"
|
|
||||||
UseLayoutRounding="True" />
|
|
||||||
</Border>
|
|
||||||
<ControlTemplate.Triggers>
|
|
||||||
<DataTrigger Binding="{Binding ElementName=TextSource, Path=Text}"
|
|
||||||
Value="">
|
|
||||||
<Setter Property="IsEnabled"
|
|
||||||
Value="False" />
|
|
||||||
<Setter TargetName="PathButton"
|
|
||||||
Property="Data"
|
|
||||||
Value="{StaticResource Magnifier}" />
|
|
||||||
</DataTrigger>
|
|
||||||
<Trigger Property="IsMouseOver"
|
|
||||||
Value="True">
|
|
||||||
<Setter Property="Cursor"
|
|
||||||
Value="Hand" />
|
|
||||||
<Setter TargetName="PathButton"
|
|
||||||
Property="Fill"
|
|
||||||
Value="Red" />
|
|
||||||
<Setter TargetName="PathButton"
|
|
||||||
Property="Stroke"
|
|
||||||
Value="Red" />
|
|
||||||
</Trigger>
|
|
||||||
</ControlTemplate.Triggers>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
</Button.Style>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<!-- SEPARATOR -->
|
|
||||||
<Border Grid.Column="2"
|
|
||||||
Width="1"
|
|
||||||
Margin="2,0,2,0"
|
|
||||||
Background="LightGray" />
|
|
||||||
|
|
||||||
<!-- TOGGLE BUTTON -->
|
|
||||||
<ToggleButton Name="SearchToggleButton"
|
|
||||||
Grid.Column="3"
|
|
||||||
Margin="2,0,2,0"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
Background="Transparent"
|
|
||||||
DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type control:FilterDataGrid}}}"
|
|
||||||
IsChecked="{Binding StartsWith, UpdateSourceTrigger=PropertyChanged}"
|
|
||||||
ToolTip="{Binding Translate.Toggle}">
|
|
||||||
<ToggleButton.Style>
|
|
||||||
<Style TargetType="{x:Type ToggleButton}">
|
|
||||||
<Setter Property="Cursor"
|
|
||||||
Value="Hand" />
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="ToggleButton">
|
|
||||||
<Border Padding="3"
|
|
||||||
Background="Transparent"
|
|
||||||
BorderBrush="LightGray"
|
|
||||||
BorderThickness="0">
|
|
||||||
<Path x:Name="PathToggle"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Data="{StaticResource Contains}"
|
|
||||||
Fill="DarkSlateGray"
|
|
||||||
Stretch="UniformToFill" />
|
|
||||||
</Border>
|
|
||||||
<ControlTemplate.Triggers>
|
|
||||||
<Trigger Property="IsChecked"
|
|
||||||
Value="True">
|
|
||||||
<Setter TargetName="PathToggle"
|
|
||||||
Property="Data"
|
|
||||||
Value="{StaticResource StartsWith}" />
|
|
||||||
</Trigger>
|
|
||||||
<Trigger Property="IsMouseOver"
|
|
||||||
Value="True">
|
|
||||||
<Setter TargetName="PathToggle"
|
|
||||||
Property="Fill"
|
|
||||||
Value="Black" />
|
|
||||||
</Trigger>
|
|
||||||
</ControlTemplate.Triggers>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
</ToggleButton.Style>
|
|
||||||
</ToggleButton>
|
|
||||||
</Grid>
|
|
||||||
<!-- PLACEHOLDER TEXT -->
|
|
||||||
<ControlTemplate.Triggers>
|
|
||||||
<Trigger Property="IsFocused"
|
|
||||||
Value="True">
|
|
||||||
<Setter TargetName="TextSource"
|
|
||||||
Property="FocusManager.FocusedElement"
|
|
||||||
Value="{Binding RelativeSource={RelativeSource Self}}" />
|
|
||||||
</Trigger>
|
|
||||||
<DataTrigger Binding="{Binding ElementName=SearchToggleButton, Path=IsChecked}"
|
|
||||||
Value="True">
|
|
||||||
<Setter TargetName="TextBoxPlaceHolder"
|
|
||||||
Property="Text"
|
|
||||||
Value="{Binding Translate.StartsWith, Mode=OneWay}" />
|
|
||||||
</DataTrigger>
|
|
||||||
<DataTrigger Binding="{Binding ElementName=SearchToggleButton, Path=IsChecked}"
|
|
||||||
Value="False">
|
|
||||||
<Setter TargetName="TextBoxPlaceHolder"
|
|
||||||
Property="Text"
|
|
||||||
Value="{Binding Translate.Contains, Mode=OneWay}" />
|
|
||||||
</DataTrigger>
|
|
||||||
</ControlTemplate.Triggers>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<!-- DEFAULT STYLE AND CONTROLTEMPLATE FOR DATAGRID -->
|
|
||||||
<Style BasedOn="{StaticResource {x:Type DataGrid}}"
|
|
||||||
TargetType="{x:Type control:FilterDataGrid}">
|
|
||||||
|
|
||||||
<!-- DISABLING CanUserAddRows : AggregateException when user can add row -->
|
|
||||||
<Setter Property="CanUserAddRows"
|
|
||||||
Value="False" />
|
|
||||||
|
|
||||||
<!-- ROWS COUNT TEMPLATE -->
|
|
||||||
<Setter Property="RowHeaderTemplate">
|
|
||||||
<Setter.Value>
|
|
||||||
<DataTemplate>
|
|
||||||
<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridRow}}, Path=Header}" />
|
|
||||||
</DataTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="{x:Type DataGrid}">
|
|
||||||
<Border Padding="{TemplateBinding Padding}"
|
|
||||||
Background="{TemplateBinding Background}"
|
|
||||||
BorderBrush="{TemplateBinding BorderBrush}"
|
|
||||||
BorderThickness="{TemplateBinding BorderThickness}"
|
|
||||||
SnapsToDevicePixels="True">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- CONTENT DATAGRID -->
|
|
||||||
<ScrollViewer x:Name="DG_ScrollViewer"
|
|
||||||
Grid.Row="0"
|
|
||||||
CanContentScroll="True"
|
|
||||||
Focusable="false">
|
|
||||||
<ScrollViewer.Template>
|
|
||||||
<ControlTemplate TargetType="{x:Type ScrollViewer}">
|
|
||||||
<Grid ShowGridLines="False">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<Button Width="{Binding CellsPanelHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
|
|
||||||
Command="{x:Static DataGrid.SelectAllCommand}"
|
|
||||||
Focusable="false"
|
|
||||||
Style="{DynamicResource {ComponentResourceKey ResourceId=DataGridSelectAllButtonStyle,
|
|
||||||
TypeInTargetAssembly={x:Type DataGrid}}}"
|
|
||||||
Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.All}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
|
|
||||||
<DataGridColumnHeadersPresenter x:Name="PART_ColumnHeadersPresenter"
|
|
||||||
Grid.Row="0"
|
|
||||||
Grid.Column="1"
|
|
||||||
Visibility="{Binding HeadersVisibility, ConverterParameter={x:Static DataGridHeadersVisibility.Column}, Converter={x:Static DataGrid.HeadersVisibilityConverter}, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
|
|
||||||
<ScrollContentPresenter x:Name="PART_ScrollContentPresenter"
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="0"
|
|
||||||
Grid.ColumnSpan="2"
|
|
||||||
CanContentScroll="{TemplateBinding CanContentScroll}" />
|
|
||||||
<ScrollBar x:Name="PART_VerticalScrollBar"
|
|
||||||
Grid.Row="1"
|
|
||||||
Grid.Column="2"
|
|
||||||
Maximum="{TemplateBinding ScrollableHeight}"
|
|
||||||
Orientation="Vertical"
|
|
||||||
ViewportSize="{TemplateBinding ViewportHeight}"
|
|
||||||
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
|
|
||||||
Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" />
|
|
||||||
<Grid Grid.Row="2"
|
|
||||||
Grid.Column="1">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="{Binding NonFrozenColumnsViewportHorizontalOffset, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<ScrollBar x:Name="PART_HorizontalScrollBar"
|
|
||||||
Grid.Column="1"
|
|
||||||
Maximum="{TemplateBinding ScrollableWidth}"
|
|
||||||
Orientation="Horizontal"
|
|
||||||
ViewportSize="{TemplateBinding ViewportWidth}"
|
|
||||||
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
|
|
||||||
Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" />
|
|
||||||
</Grid>
|
|
||||||
</Grid>
|
|
||||||
</ControlTemplate>
|
|
||||||
</ScrollViewer.Template>
|
|
||||||
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
|
|
||||||
</ScrollViewer>
|
|
||||||
|
|
||||||
<!-- STATUS BAR & RESULT FILTER -->
|
|
||||||
<Border x:Name="BorderStatusBar"
|
|
||||||
Grid.Row="1"
|
|
||||||
Padding="4,2"
|
|
||||||
Background="Transparent"
|
|
||||||
BorderBrush="LightGray"
|
|
||||||
BorderThickness="0,1">
|
|
||||||
<Border.Style>
|
|
||||||
<Style TargetType="Border">
|
|
||||||
<Setter Property="Visibility"
|
|
||||||
Value="Collapsed" />
|
|
||||||
<Style.Triggers>
|
|
||||||
<DataTrigger Binding="{Binding Path=ShowStatusBar, RelativeSource={RelativeSource AncestorType={x:Type control:FilterDataGrid}}}"
|
|
||||||
Value="True">
|
|
||||||
<Setter Property="Visibility"
|
|
||||||
Value="Visible" />
|
|
||||||
</DataTrigger>
|
|
||||||
</Style.Triggers>
|
|
||||||
</Style>
|
|
||||||
</Border.Style>
|
|
||||||
|
|
||||||
<UniformGrid Columns="2"
|
|
||||||
DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type control:FilterDataGrid}}}">
|
|
||||||
|
|
||||||
<!-- RESULT STATUS -->
|
|
||||||
<TextBlock HorizontalAlignment="Left">
|
|
||||||
<TextBlock.Text>
|
|
||||||
<MultiBinding Converter="{StaticResource StringFormatConverter}">
|
|
||||||
<Binding Path="Translate.Status" />
|
|
||||||
<Binding Path="Items.Count"
|
|
||||||
UpdateSourceTrigger="PropertyChanged" />
|
|
||||||
<Binding Path="ItemsSourceCount" />
|
|
||||||
</MultiBinding>
|
|
||||||
</TextBlock.Text>
|
|
||||||
</TextBlock>
|
|
||||||
|
|
||||||
<!-- ELAPSED TIME -->
|
|
||||||
<TextBlock HorizontalAlignment="Right">
|
|
||||||
<TextBlock.Text>
|
|
||||||
<MultiBinding Converter="{StaticResource StringFormatConverter}">
|
|
||||||
<Binding Path="Translate.ElapsedTime"
|
|
||||||
UpdateSourceTrigger="PropertyChanged" />
|
|
||||||
<Binding Path="ElapsedTime" />
|
|
||||||
</MultiBinding>
|
|
||||||
</TextBlock.Text>
|
|
||||||
<TextBlock.Style>
|
|
||||||
<Style TargetType="TextBlock">
|
|
||||||
<Setter Property="Visibility"
|
|
||||||
Value="Collapsed" />
|
|
||||||
<Style.Triggers>
|
|
||||||
<DataTrigger Binding="{Binding ShowElapsedTime}"
|
|
||||||
Value="True">
|
|
||||||
<Setter Property="Visibility"
|
|
||||||
Value="Visible" />
|
|
||||||
</DataTrigger>
|
|
||||||
</Style.Triggers>
|
|
||||||
</Style>
|
|
||||||
</TextBlock.Style>
|
|
||||||
</TextBlock>
|
|
||||||
</UniformGrid>
|
|
||||||
</Border>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<!-- DATAGRIDCOLUMNHEADER STYLE -->
|
|
||||||
<Style BasedOn="{StaticResource {x:Type DataGridColumnHeader}}"
|
|
||||||
TargetType="DataGridColumnHeader">
|
|
||||||
<Setter Property="HorizontalContentAlignment"
|
|
||||||
Value="Stretch" />
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<!-- DATATEMPLATE OF DATAGRIDCOLUMNHEADER -->
|
|
||||||
<DataTemplate x:Key="DataGridHeaderTemplate">
|
|
||||||
|
|
||||||
<!-- HEADER STRECH TO CONTENTPRESENTER OF DATAGRIDCOLUMNHEADER -->
|
|
||||||
<Grid x:Name="ContainerFilterGrid"
|
|
||||||
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}, Mode=FindAncestor, AncestorLevel=1}, Path=ActualWidth}"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Background="Transparent">
|
|
||||||
|
|
||||||
<!-- HEADER/BUTTON -->
|
|
||||||
<Grid x:Name="GridHeaderButton"
|
|
||||||
ShowGridLines="False">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<!-- RENDER THE HEADER TEXT -->
|
|
||||||
<TextBlock Grid.Column="0"
|
|
||||||
Text="{Binding}" />
|
|
||||||
|
|
||||||
<!-- FILTER BUTTON -->
|
|
||||||
<Button Name="filterButton"
|
|
||||||
Grid.Column="1"
|
|
||||||
Width="19"
|
|
||||||
Height="19"
|
|
||||||
Background="Transparent"
|
|
||||||
BorderBrush="DarkGray"
|
|
||||||
BorderThickness="1"
|
|
||||||
Command="{x:Static control:FilterDataGrid.ShowFilter}"
|
|
||||||
Cursor="Hand"
|
|
||||||
Opacity="0.5"
|
|
||||||
OverridesDefaultStyle="True"
|
|
||||||
SnapsToDevicePixels="True"
|
|
||||||
UseLayoutRounding="True">
|
|
||||||
<Button.Style>
|
|
||||||
<Style TargetType="{x:Type Button}">
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="{x:Type Button}">
|
|
||||||
<Border Padding="2"
|
|
||||||
Background="{TemplateBinding Background}"
|
|
||||||
BorderBrush="{TemplateBinding BorderBrush}"
|
|
||||||
BorderThickness="1"
|
|
||||||
SnapsToDevicePixels="True"
|
|
||||||
UseLayoutRounding="True">
|
|
||||||
<Path x:Name="PathFilterIcon"
|
|
||||||
Margin="0"
|
|
||||||
HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Data="{StaticResource Filter}"
|
|
||||||
Fill="DarkSlateGray"
|
|
||||||
Stretch="Uniform" />
|
|
||||||
</Border>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
</Button.Style>
|
|
||||||
</Button>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<!-- POPUP -->
|
|
||||||
<Popup Name="FilterPopup"
|
|
||||||
AllowsTransparency="True"
|
|
||||||
IsOpen="False"
|
|
||||||
PlacementTarget="{Binding ElementName=ContainerFilterGrid}"
|
|
||||||
StaysOpen="{StaticResource StayOpen}">
|
|
||||||
|
|
||||||
<Border x:Name="PopUpBorder"
|
|
||||||
Padding="0"
|
|
||||||
Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"
|
|
||||||
BorderBrush="LightGray"
|
|
||||||
BorderThickness="1">
|
|
||||||
|
|
||||||
<Grid x:Name="SizableContentGrid"
|
|
||||||
MinWidth="{StaticResource PopupWidth}"
|
|
||||||
MinHeight="{StaticResource PopupHeight}"
|
|
||||||
ShowGridLines="False"
|
|
||||||
ZIndex="1">
|
|
||||||
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto"
|
|
||||||
MinWidth="32" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="*" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
<RowDefinition Height="Auto" />
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- BUTTON CLEAR FILTER -->
|
|
||||||
<Button x:Name="ClearFilterBnt"
|
|
||||||
Grid.Row="2"
|
|
||||||
Grid.Column="0"
|
|
||||||
Grid.ColumnSpan="2"
|
|
||||||
Margin="2,10,2,2"
|
|
||||||
Padding="4"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Command="{x:Static control:FilterDataGrid.RemoveFilter}"
|
|
||||||
Content="{Binding Path=Content, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGridColumnHeader}}, UpdateSourceTrigger=PropertyChanged}"
|
|
||||||
FontSize="13"
|
|
||||||
OverridesDefaultStyle="True">
|
|
||||||
<Button.Style>
|
|
||||||
<Style TargetType="{x:Type Button}">
|
|
||||||
<Setter Property="Foreground"
|
|
||||||
Value="DarkSlateGray" />
|
|
||||||
<Setter Property="SnapsToDevicePixels"
|
|
||||||
Value="True" />
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="{x:Type Button}">
|
|
||||||
<Border x:Name="BorderContent"
|
|
||||||
Padding="{TemplateBinding Padding}"
|
|
||||||
BorderBrush="Transparent"
|
|
||||||
BorderThickness="0"
|
|
||||||
SnapsToDevicePixels="True"
|
|
||||||
UseLayoutRounding="True">
|
|
||||||
<Grid x:Name="ContentGrid"
|
|
||||||
Background="Transparent">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Path Grid.Column="0"
|
|
||||||
Width="16"
|
|
||||||
Margin="0,0,10,0"
|
|
||||||
Data="{StaticResource FilterDelete}"
|
|
||||||
Fill="{TemplateBinding Foreground}"
|
|
||||||
Stretch="Uniform" />
|
|
||||||
|
|
||||||
<TextBlock x:Name="ContentPresenter"
|
|
||||||
Grid.Column="1"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type control:FilterDataGrid}}}">
|
|
||||||
<TextBlock.Text>
|
|
||||||
<MultiBinding Converter="{StaticResource StringFormatConverter}">
|
|
||||||
<MultiBinding.Bindings>
|
|
||||||
<Binding Path="Translate.Clear"
|
|
||||||
TargetNullValue=""
|
|
||||||
UpdateSourceTrigger="PropertyChanged" />
|
|
||||||
<Binding ElementName="ClearFilterBnt"
|
|
||||||
Path="Content" />
|
|
||||||
</MultiBinding.Bindings>
|
|
||||||
</MultiBinding>
|
|
||||||
</TextBlock.Text>
|
|
||||||
</TextBlock>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
<ControlTemplate.Triggers>
|
|
||||||
<Trigger Property="IsMouseOver"
|
|
||||||
Value="True">
|
|
||||||
<Setter TargetName="BorderContent"
|
|
||||||
Property="Background"
|
|
||||||
Value="#F0F0F0" />
|
|
||||||
</Trigger>
|
|
||||||
<Trigger Property="IsPressed"
|
|
||||||
Value="True">
|
|
||||||
<Setter TargetName="BorderContent"
|
|
||||||
Property="Background">
|
|
||||||
<Setter.Value>
|
|
||||||
<SolidColorBrush Opacity="0.8"
|
|
||||||
Color="LightGray" />
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Trigger>
|
|
||||||
<Trigger Property="IsEnabled"
|
|
||||||
Value="False">
|
|
||||||
<Setter Property="Foreground">
|
|
||||||
<Setter.Value>
|
|
||||||
<SolidColorBrush Opacity="0.5"
|
|
||||||
Color="DarkSlateGray" />
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Trigger>
|
|
||||||
</ControlTemplate.Triggers>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
</Button.Style>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<!-- SEPARATOR -->
|
|
||||||
<Separator Grid.Row="3"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="0,2"
|
|
||||||
Background="LightGray" />
|
|
||||||
|
|
||||||
<!-- SEARCH BOX -->
|
|
||||||
<Border Grid.Row="4"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="0,4,4,2"
|
|
||||||
Padding="0,2"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
Background="Transparent"
|
|
||||||
BorderBrush="LightGray"
|
|
||||||
BorderThickness="1">
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<TextBox x:Name="SearchBox"
|
|
||||||
Grid.Column="0"
|
|
||||||
Margin="0"
|
|
||||||
Padding="2,0,0,0"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalContentAlignment="Center"
|
|
||||||
AcceptsReturn="False"
|
|
||||||
DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type control:FilterDataGrid}}}"
|
|
||||||
Focusable="True"
|
|
||||||
FontSize="13"
|
|
||||||
MaxLength="20"
|
|
||||||
Style="{StaticResource PlaceHolder}"
|
|
||||||
Tag="{Binding Translate.Contains}">
|
|
||||||
<TextBox.InputBindings>
|
|
||||||
<KeyBinding Key="Enter"
|
|
||||||
Command="{x:Static control:FilterDataGrid.ApplyFilter}" />
|
|
||||||
</TextBox.InputBindings>
|
|
||||||
</TextBox>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- ICON (current filter is set) -->
|
|
||||||
<Path x:Name="PathIsFiltered"
|
|
||||||
Grid.Row="5"
|
|
||||||
Grid.Column="0"
|
|
||||||
Width="19"
|
|
||||||
Height="20"
|
|
||||||
Margin="0,5,0,0"
|
|
||||||
VerticalAlignment="Top"
|
|
||||||
Data="{StaticResource FilterChecked}"
|
|
||||||
Fill="DarkSlateGray"
|
|
||||||
Stretch="Fill"
|
|
||||||
Stroke="DarkSlateGray"
|
|
||||||
StrokeThickness="0.2">
|
|
||||||
<Path.Style>
|
|
||||||
<Style TargetType="Path">
|
|
||||||
<Setter Property="Visibility"
|
|
||||||
Value="Hidden" />
|
|
||||||
<Style.Triggers>
|
|
||||||
<DataTrigger Binding="{Binding ElementName=ClearFilterBnt, Path=IsEnabled}"
|
|
||||||
Value="True">
|
|
||||||
<Setter Property="Visibility"
|
|
||||||
Value="Visible" />
|
|
||||||
</DataTrigger>
|
|
||||||
</Style.Triggers>
|
|
||||||
</Style>
|
|
||||||
</Path.Style>
|
|
||||||
</Path>
|
|
||||||
|
|
||||||
<!-- LISTBOX / TREEVIEW -->
|
|
||||||
<Border Grid.Row="5"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="0,4,4,4"
|
|
||||||
BorderThickness="0">
|
|
||||||
|
|
||||||
<Grid x:Name="GridItemControl">
|
|
||||||
|
|
||||||
<ListBox x:Name="PopupListBox"
|
|
||||||
Grid.Row="0"
|
|
||||||
Padding="2"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
VerticalAlignment="Stretch"
|
|
||||||
BorderBrush="LightGray"
|
|
||||||
BorderThickness="1"
|
|
||||||
ScrollViewer.HorizontalScrollBarVisibility="Auto"
|
|
||||||
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
|
||||||
Visibility="Collapsed">
|
|
||||||
<ListBox.ItemContainerStyle>
|
|
||||||
<Style BasedOn="{StaticResource {x:Type ListBoxItem}}"
|
|
||||||
TargetType="{x:Type ListBoxItem}">
|
|
||||||
<Setter Property="HorizontalContentAlignment"
|
|
||||||
Value="Left" />
|
|
||||||
<Setter Property="VerticalContentAlignment"
|
|
||||||
Value="Center" />
|
|
||||||
</Style>
|
|
||||||
</ListBox.ItemContainerStyle>
|
|
||||||
<ListBox.ItemTemplate>
|
|
||||||
<!--
|
|
||||||
ContentStringFormat="{}{0}"
|
|
||||||
Content="{Binding Label, ConverterCulture=en-US}"
|
|
||||||
ContentStringFormat="F2, en-US"
|
|
||||||
the value of the label is a string, so it cannot be formatted
|
|
||||||
-->
|
|
||||||
<DataTemplate DataType="{x:Type control:FilterItem}">
|
|
||||||
<CheckBox x:Name="CheckBox"
|
|
||||||
Width="Auto"
|
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
HorizontalContentAlignment="Stretch"
|
|
||||||
Command="{x:Static control:FilterDataGrid.IsChecked}"
|
|
||||||
CommandParameter="{Binding}"
|
|
||||||
Content="{Binding Label}"
|
|
||||||
FontWeight="Normal"
|
|
||||||
IsChecked="{Binding IsChecked}"
|
|
||||||
IsThreeState="False" />
|
|
||||||
<DataTemplate.Triggers>
|
|
||||||
<DataTrigger Binding="{Binding Level}"
|
|
||||||
Value="1">
|
|
||||||
<Setter TargetName="CheckBox"
|
|
||||||
Property="Margin"
|
|
||||||
Value="4,0,0,0" />
|
|
||||||
</DataTrigger>
|
|
||||||
</DataTemplate.Triggers>
|
|
||||||
</DataTemplate>
|
|
||||||
</ListBox.ItemTemplate>
|
|
||||||
</ListBox>
|
|
||||||
|
|
||||||
<TreeView x:Name="PopupTreeview"
|
|
||||||
Grid.Row="0"
|
|
||||||
BorderBrush="LightGray"
|
|
||||||
BorderThickness="1"
|
|
||||||
ScrollViewer.HorizontalScrollBarVisibility="Auto"
|
|
||||||
ScrollViewer.VerticalScrollBarVisibility="Auto"
|
|
||||||
Visibility="Collapsed">
|
|
||||||
<TreeView.ItemTemplate>
|
|
||||||
<HierarchicalDataTemplate DataType="control:FilterItem"
|
|
||||||
ItemsSource="{Binding Children}">
|
|
||||||
<StackPanel Orientation="Horizontal">
|
|
||||||
<CheckBox x:Name="CheckBoxTree"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
Focusable="False"
|
|
||||||
IsChecked="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}" />
|
|
||||||
<ContentPresenter Margin="2"
|
|
||||||
Content="{Binding Label}" />
|
|
||||||
</StackPanel>
|
|
||||||
<DataTemplate.Triggers>
|
|
||||||
<DataTrigger Binding="{Binding Level}"
|
|
||||||
Value="1">
|
|
||||||
<Setter TargetName="CheckBoxTree"
|
|
||||||
Property="Margin"
|
|
||||||
Value="4,0,0,0" />
|
|
||||||
</DataTrigger>
|
|
||||||
</DataTemplate.Triggers>
|
|
||||||
</HierarchicalDataTemplate>
|
|
||||||
</TreeView.ItemTemplate>
|
|
||||||
<TreeView.ItemContainerStyle>
|
|
||||||
<Style BasedOn="{StaticResource {x:Type TreeViewItem}}"
|
|
||||||
TargetType="{x:Type TreeViewItem}">
|
|
||||||
<Setter Property="OverridesDefaultStyle"
|
|
||||||
Value="True" />
|
|
||||||
<Setter Property="IsExpanded"
|
|
||||||
Value="False" />
|
|
||||||
<Setter Property="HorizontalContentAlignment"
|
|
||||||
Value="Stretch" />
|
|
||||||
<Setter Property="VerticalContentAlignment"
|
|
||||||
Value="Stretch" />
|
|
||||||
<Setter Property="Visibility"
|
|
||||||
Value="Visible" />
|
|
||||||
</Style>
|
|
||||||
</TreeView.ItemContainerStyle>
|
|
||||||
</TreeView>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- OK/CANCEL BUTTON -->
|
|
||||||
<UniformGrid Grid.Row="6"
|
|
||||||
Grid.Column="1"
|
|
||||||
Margin="0,6,4,6"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Background="Transparent"
|
|
||||||
Columns="2"
|
|
||||||
DataContext="{Binding RelativeSource={RelativeSource AncestorType={x:Type control:FilterDataGrid}}}">
|
|
||||||
|
|
||||||
<Button Width="100"
|
|
||||||
Margin="0"
|
|
||||||
HorizontalAlignment="Left"
|
|
||||||
Command="{x:Static control:FilterDataGrid.ApplyFilter}"
|
|
||||||
Content="{Binding Translate.Ok}" />
|
|
||||||
|
|
||||||
<Button Width="100"
|
|
||||||
Margin="6,0,0,0"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
Command="{x:Static control:FilterDataGrid.CancelFilter}"
|
|
||||||
Content="{Binding Translate.Cancel}" />
|
|
||||||
</UniformGrid>
|
|
||||||
|
|
||||||
<!-- RESIZE GRIP -->
|
|
||||||
<Thumb x:Name="PopupThumb"
|
|
||||||
Grid.Row="7"
|
|
||||||
Grid.Column="0"
|
|
||||||
Grid.ColumnSpan="2"
|
|
||||||
Width="20"
|
|
||||||
Height="Auto"
|
|
||||||
Margin="0,0,2,2"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
VerticalAlignment="Bottom"
|
|
||||||
SnapsToDevicePixels="True"
|
|
||||||
UseLayoutRounding="True">
|
|
||||||
<Thumb.Style>
|
|
||||||
<Style TargetType="{x:Type Thumb}">
|
|
||||||
<Style.Setters>
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate>
|
|
||||||
<Grid x:Name="resizeVisual"
|
|
||||||
HorizontalAlignment="Right"
|
|
||||||
VerticalAlignment="Bottom"
|
|
||||||
Background="Transparent"
|
|
||||||
DockPanel.Dock="Right"
|
|
||||||
SnapsToDevicePixels="True"
|
|
||||||
UseLayoutRounding="True">
|
|
||||||
<Path Width="12"
|
|
||||||
Height="12"
|
|
||||||
Margin="0"
|
|
||||||
Data="{StaticResource GripSizeIcon}"
|
|
||||||
Stretch="None"
|
|
||||||
Stroke="LightSlateGray"
|
|
||||||
StrokeThickness="1" />
|
|
||||||
<Grid.Style>
|
|
||||||
<Style TargetType="{x:Type Grid}">
|
|
||||||
<Style.Triggers>
|
|
||||||
<Trigger Property="IsMouseOver"
|
|
||||||
Value="True">
|
|
||||||
<Setter Property="Cursor"
|
|
||||||
Value="SizeNWSE" />
|
|
||||||
</Trigger>
|
|
||||||
</Style.Triggers>
|
|
||||||
</Style>
|
|
||||||
</Grid.Style>
|
|
||||||
</Grid>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style.Setters>
|
|
||||||
</Style>
|
|
||||||
</Thumb.Style>
|
|
||||||
</Thumb>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
</Popup>
|
|
||||||
</Grid>
|
|
||||||
</DataTemplate>
|
|
||||||
</ResourceDictionary>
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:control="clr-namespace:FSI.Lib.Wpf.Ctrls.FilterDataGrid">
|
|
||||||
|
|
||||||
|
|
||||||
<ResourceDictionary.MergedDictionaries>
|
|
||||||
<ResourceDictionary Source="/FilterDataGrid;component/Themes/FilterDataGrid.xaml" />
|
|
||||||
</ResourceDictionary.MergedDictionaries>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
EXTERNAL ACCESS FOR CUSTOMIZE DEFAULT STYLE
|
|
||||||
SEE FILTERDATAGRID DEFAULT STYLE
|
|
||||||
-->
|
|
||||||
<Style x:Key="{ComponentResourceKey {x:Type control:FilterDataGrid},
|
|
||||||
FilterDataGridStyle}"
|
|
||||||
BasedOn="{StaticResource {x:Type control:FilterDataGrid}}"
|
|
||||||
TargetType="{x:Type control:FilterDataGrid}" />
|
|
||||||
</ResourceDictionary>
|
|
||||||
@@ -1,138 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Windows;
|
|
||||||
|
|
||||||
namespace FSI.Lib.Wpf.ExtensionMethods
|
|
||||||
{
|
|
||||||
public static class WindowExtensions
|
|
||||||
{
|
|
||||||
#region Public Methods
|
|
||||||
|
|
||||||
public static bool ActivateCenteredToMouse(this Window window)
|
|
||||||
{
|
|
||||||
ComputeTopLeft(ref window);
|
|
||||||
return window.Activate();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void ShowCenteredToMouse(this Window window)
|
|
||||||
{
|
|
||||||
// in case the default start-up location isn't set to Manual
|
|
||||||
WindowStartupLocation oldLocation = window.WindowStartupLocation;
|
|
||||||
// set location to manual -> window will be placed by Top and Left property
|
|
||||||
window.WindowStartupLocation = WindowStartupLocation.Manual;
|
|
||||||
ComputeTopLeft(ref window);
|
|
||||||
window.Show();
|
|
||||||
window.WindowStartupLocation = oldLocation;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Methods
|
|
||||||
|
|
||||||
private static void ComputeTopLeft(ref Window window)
|
|
||||||
{
|
|
||||||
W32Point pt = new W32Point();
|
|
||||||
if (!GetCursorPos(ref pt))
|
|
||||||
{
|
|
||||||
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0x00000002: return nearest monitor if pt is not contained in any monitor.
|
|
||||||
IntPtr monHandle = MonitorFromPoint(pt, 0x00000002);
|
|
||||||
W32MonitorInfo monInfo = new W32MonitorInfo();
|
|
||||||
monInfo.Size = Marshal.SizeOf(typeof(W32MonitorInfo));
|
|
||||||
|
|
||||||
if (!GetMonitorInfo(monHandle, ref monInfo))
|
|
||||||
{
|
|
||||||
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
|
|
||||||
}
|
|
||||||
|
|
||||||
// use WorkArea struct to include the taskbar position.
|
|
||||||
W32Rect monitor = monInfo.WorkArea;
|
|
||||||
double offsetX = Math.Round(window.Width / 2);
|
|
||||||
double offsetY = Math.Round(window.Height / 2);
|
|
||||||
|
|
||||||
double top = pt.Y - offsetY;
|
|
||||||
double left = pt.X - offsetX;
|
|
||||||
|
|
||||||
Rect screen = new Rect(
|
|
||||||
new Point(monitor.Left, monitor.Top),
|
|
||||||
new Point(monitor.Right, monitor.Bottom));
|
|
||||||
Rect wnd = new Rect(
|
|
||||||
new Point(left, top),
|
|
||||||
new Point(left + window.Width, top + window.Height));
|
|
||||||
|
|
||||||
window.Top = wnd.Top;
|
|
||||||
window.Left = wnd.Left;
|
|
||||||
|
|
||||||
if (!screen.Contains(wnd))
|
|
||||||
{
|
|
||||||
if (wnd.Top < screen.Top)
|
|
||||||
{
|
|
||||||
double diff = Math.Abs(screen.Top - wnd.Top);
|
|
||||||
window.Top = wnd.Top + diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wnd.Bottom > screen.Bottom)
|
|
||||||
{
|
|
||||||
double diff = wnd.Bottom - screen.Bottom;
|
|
||||||
window.Top = wnd.Top - diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wnd.Left < screen.Left)
|
|
||||||
{
|
|
||||||
double diff = Math.Abs(screen.Left - wnd.Left);
|
|
||||||
window.Left = wnd.Left + diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wnd.Right > screen.Right)
|
|
||||||
{
|
|
||||||
double diff = wnd.Right - screen.Right;
|
|
||||||
window.Left = wnd.Left - diff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region W32 API
|
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
|
||||||
private static extern bool GetCursorPos(ref W32Point pt);
|
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
|
||||||
private static extern bool GetMonitorInfo(IntPtr hMonitor, ref W32MonitorInfo lpmi);
|
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
private static extern IntPtr MonitorFromPoint(W32Point pt, uint dwFlags);
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public struct W32Point
|
|
||||||
{
|
|
||||||
public int X;
|
|
||||||
public int Y;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
internal struct W32MonitorInfo
|
|
||||||
{
|
|
||||||
public int Size;
|
|
||||||
public W32Rect Monitor;
|
|
||||||
public W32Rect WorkArea;
|
|
||||||
public uint Flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
internal struct W32Rect
|
|
||||||
{
|
|
||||||
public int Left;
|
|
||||||
public int Top;
|
|
||||||
public int Right;
|
|
||||||
public int Bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
# FSI.Lib
|
|
||||||
|
|
||||||
Fondium Singen Library
|
|
||||||
400
NHotkey/.gitignore
vendored
400
NHotkey/.gitignore
vendored
@@ -1,400 +0,0 @@
|
|||||||
# ---> VisualStudio
|
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
|
||||||
## files generated by popular Visual Studio add-ons.
|
|
||||||
##
|
|
||||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
|
||||||
|
|
||||||
# User-specific files
|
|
||||||
*.rsuser
|
|
||||||
*.suo
|
|
||||||
*.user
|
|
||||||
*.userosscache
|
|
||||||
*.sln.docstates
|
|
||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
|
||||||
*.userprefs
|
|
||||||
|
|
||||||
# Mono auto generated files
|
|
||||||
mono_crash.*
|
|
||||||
|
|
||||||
# Build results
|
|
||||||
[Dd]ebug/
|
|
||||||
[Dd]ebugPublic/
|
|
||||||
[Rr]elease/
|
|
||||||
[Rr]eleases/
|
|
||||||
x64/
|
|
||||||
x86/
|
|
||||||
[Ww][Ii][Nn]32/
|
|
||||||
[Aa][Rr][Mm]/
|
|
||||||
[Aa][Rr][Mm]64/
|
|
||||||
bld/
|
|
||||||
[Bb]in/
|
|
||||||
[Oo]bj/
|
|
||||||
[Ll]og/
|
|
||||||
[Ll]ogs/
|
|
||||||
|
|
||||||
# Visual Studio 2015/2017 cache/options directory
|
|
||||||
.vs/
|
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
|
||||||
#wwwroot/
|
|
||||||
|
|
||||||
# Visual Studio 2017 auto generated files
|
|
||||||
Generated\ Files/
|
|
||||||
|
|
||||||
# MSTest test Results
|
|
||||||
[Tt]est[Rr]esult*/
|
|
||||||
[Bb]uild[Ll]og.*
|
|
||||||
|
|
||||||
# NUnit
|
|
||||||
*.VisualState.xml
|
|
||||||
TestResult.xml
|
|
||||||
nunit-*.xml
|
|
||||||
|
|
||||||
# Build Results of an ATL Project
|
|
||||||
[Dd]ebugPS/
|
|
||||||
[Rr]eleasePS/
|
|
||||||
dlldata.c
|
|
||||||
|
|
||||||
# Benchmark Results
|
|
||||||
BenchmarkDotNet.Artifacts/
|
|
||||||
|
|
||||||
# .NET Core
|
|
||||||
project.lock.json
|
|
||||||
project.fragment.lock.json
|
|
||||||
artifacts/
|
|
||||||
|
|
||||||
# ASP.NET Scaffolding
|
|
||||||
ScaffoldingReadMe.txt
|
|
||||||
|
|
||||||
# StyleCop
|
|
||||||
StyleCopReport.xml
|
|
||||||
|
|
||||||
# Files built by Visual Studio
|
|
||||||
*_i.c
|
|
||||||
*_p.c
|
|
||||||
*_h.h
|
|
||||||
*.ilk
|
|
||||||
*.meta
|
|
||||||
*.obj
|
|
||||||
*.iobj
|
|
||||||
*.pch
|
|
||||||
*.pdb
|
|
||||||
*.ipdb
|
|
||||||
*.pgc
|
|
||||||
*.pgd
|
|
||||||
*.rsp
|
|
||||||
*.sbr
|
|
||||||
*.tlb
|
|
||||||
*.tli
|
|
||||||
*.tlh
|
|
||||||
*.tmp
|
|
||||||
*.tmp_proj
|
|
||||||
*_wpftmp.csproj
|
|
||||||
*.log
|
|
||||||
*.tlog
|
|
||||||
*.vspscc
|
|
||||||
*.vssscc
|
|
||||||
.builds
|
|
||||||
*.pidb
|
|
||||||
*.svclog
|
|
||||||
*.scc
|
|
||||||
|
|
||||||
# Chutzpah Test files
|
|
||||||
_Chutzpah*
|
|
||||||
|
|
||||||
# Visual C++ cache files
|
|
||||||
ipch/
|
|
||||||
*.aps
|
|
||||||
*.ncb
|
|
||||||
*.opendb
|
|
||||||
*.opensdf
|
|
||||||
*.sdf
|
|
||||||
*.cachefile
|
|
||||||
*.VC.db
|
|
||||||
*.VC.VC.opendb
|
|
||||||
|
|
||||||
# Visual Studio profiler
|
|
||||||
*.psess
|
|
||||||
*.vsp
|
|
||||||
*.vspx
|
|
||||||
*.sap
|
|
||||||
|
|
||||||
# Visual Studio Trace Files
|
|
||||||
*.e2e
|
|
||||||
|
|
||||||
# TFS 2012 Local Workspace
|
|
||||||
$tf/
|
|
||||||
|
|
||||||
# Guidance Automation Toolkit
|
|
||||||
*.gpState
|
|
||||||
|
|
||||||
# ReSharper is a .NET coding add-in
|
|
||||||
_ReSharper*/
|
|
||||||
*.[Rr]e[Ss]harper
|
|
||||||
*.DotSettings.user
|
|
||||||
|
|
||||||
# TeamCity is a build add-in
|
|
||||||
_TeamCity*
|
|
||||||
|
|
||||||
# DotCover is a Code Coverage Tool
|
|
||||||
*.dotCover
|
|
||||||
|
|
||||||
# AxoCover is a Code Coverage Tool
|
|
||||||
.axoCover/*
|
|
||||||
!.axoCover/settings.json
|
|
||||||
|
|
||||||
# Coverlet is a free, cross platform Code Coverage Tool
|
|
||||||
coverage*.json
|
|
||||||
coverage*.xml
|
|
||||||
coverage*.info
|
|
||||||
|
|
||||||
# Visual Studio code coverage results
|
|
||||||
*.coverage
|
|
||||||
*.coveragexml
|
|
||||||
|
|
||||||
# NCrunch
|
|
||||||
_NCrunch_*
|
|
||||||
.*crunch*.local.xml
|
|
||||||
nCrunchTemp_*
|
|
||||||
|
|
||||||
# MightyMoose
|
|
||||||
*.mm.*
|
|
||||||
AutoTest.Net/
|
|
||||||
|
|
||||||
# Web workbench (sass)
|
|
||||||
.sass-cache/
|
|
||||||
|
|
||||||
# Installshield output folder
|
|
||||||
[Ee]xpress/
|
|
||||||
|
|
||||||
# DocProject is a documentation generator add-in
|
|
||||||
DocProject/buildhelp/
|
|
||||||
DocProject/Help/*.HxT
|
|
||||||
DocProject/Help/*.HxC
|
|
||||||
DocProject/Help/*.hhc
|
|
||||||
DocProject/Help/*.hhk
|
|
||||||
DocProject/Help/*.hhp
|
|
||||||
DocProject/Help/Html2
|
|
||||||
DocProject/Help/html
|
|
||||||
|
|
||||||
# Click-Once directory
|
|
||||||
publish/
|
|
||||||
|
|
||||||
# Publish Web Output
|
|
||||||
*.[Pp]ublish.xml
|
|
||||||
*.azurePubxml
|
|
||||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
|
||||||
# but database connection strings (with potential passwords) will be unencrypted
|
|
||||||
*.pubxml
|
|
||||||
*.publishproj
|
|
||||||
|
|
||||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
|
||||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
|
||||||
# in these scripts will be unencrypted
|
|
||||||
PublishScripts/
|
|
||||||
|
|
||||||
# NuGet Packages
|
|
||||||
*.nupkg
|
|
||||||
# NuGet Symbol Packages
|
|
||||||
*.snupkg
|
|
||||||
# The packages folder can be ignored because of Package Restore
|
|
||||||
**/[Pp]ackages/*
|
|
||||||
# except build/, which is used as an MSBuild target.
|
|
||||||
!**/[Pp]ackages/build/
|
|
||||||
# Uncomment if necessary however generally it will be regenerated when needed
|
|
||||||
#!**/[Pp]ackages/repositories.config
|
|
||||||
# NuGet v3's project.json files produces more ignorable files
|
|
||||||
*.nuget.props
|
|
||||||
*.nuget.targets
|
|
||||||
|
|
||||||
# Microsoft Azure Build Output
|
|
||||||
csx/
|
|
||||||
*.build.csdef
|
|
||||||
|
|
||||||
# Microsoft Azure Emulator
|
|
||||||
ecf/
|
|
||||||
rcf/
|
|
||||||
|
|
||||||
# Windows Store app package directories and files
|
|
||||||
AppPackages/
|
|
||||||
BundleArtifacts/
|
|
||||||
Package.StoreAssociation.xml
|
|
||||||
_pkginfo.txt
|
|
||||||
*.appx
|
|
||||||
*.appxbundle
|
|
||||||
*.appxupload
|
|
||||||
|
|
||||||
# Visual Studio cache files
|
|
||||||
# files ending in .cache can be ignored
|
|
||||||
*.[Cc]ache
|
|
||||||
# but keep track of directories ending in .cache
|
|
||||||
!?*.[Cc]ache/
|
|
||||||
|
|
||||||
# Others
|
|
||||||
ClientBin/
|
|
||||||
~$*
|
|
||||||
*~
|
|
||||||
*.dbmdl
|
|
||||||
*.dbproj.schemaview
|
|
||||||
*.jfm
|
|
||||||
*.pfx
|
|
||||||
*.publishsettings
|
|
||||||
orleans.codegen.cs
|
|
||||||
|
|
||||||
# Including strong name files can present a security risk
|
|
||||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
|
||||||
#*.snk
|
|
||||||
|
|
||||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
|
||||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
|
||||||
#bower_components/
|
|
||||||
|
|
||||||
# RIA/Silverlight projects
|
|
||||||
Generated_Code/
|
|
||||||
|
|
||||||
# Backup & report files from converting an old project file
|
|
||||||
# to a newer Visual Studio version. Backup files are not needed,
|
|
||||||
# because we have git ;-)
|
|
||||||
_UpgradeReport_Files/
|
|
||||||
Backup*/
|
|
||||||
UpgradeLog*.XML
|
|
||||||
UpgradeLog*.htm
|
|
||||||
ServiceFabricBackup/
|
|
||||||
*.rptproj.bak
|
|
||||||
|
|
||||||
# SQL Server files
|
|
||||||
*.mdf
|
|
||||||
*.ldf
|
|
||||||
*.ndf
|
|
||||||
|
|
||||||
# Business Intelligence projects
|
|
||||||
*.rdl.data
|
|
||||||
*.bim.layout
|
|
||||||
*.bim_*.settings
|
|
||||||
*.rptproj.rsuser
|
|
||||||
*- [Bb]ackup.rdl
|
|
||||||
*- [Bb]ackup ([0-9]).rdl
|
|
||||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
|
||||||
|
|
||||||
# Microsoft Fakes
|
|
||||||
FakesAssemblies/
|
|
||||||
|
|
||||||
# GhostDoc plugin setting file
|
|
||||||
*.GhostDoc.xml
|
|
||||||
|
|
||||||
# Node.js Tools for Visual Studio
|
|
||||||
.ntvs_analysis.dat
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# Visual Studio 6 build log
|
|
||||||
*.plg
|
|
||||||
|
|
||||||
# Visual Studio 6 workspace options file
|
|
||||||
*.opt
|
|
||||||
|
|
||||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
|
||||||
*.vbw
|
|
||||||
|
|
||||||
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
|
||||||
*.vbp
|
|
||||||
|
|
||||||
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
|
||||||
*.dsw
|
|
||||||
*.dsp
|
|
||||||
|
|
||||||
# Visual Studio 6 technical files
|
|
||||||
*.ncb
|
|
||||||
*.aps
|
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/ModelManifest.xml
|
|
||||||
**/*.Server/GeneratedArtifacts
|
|
||||||
**/*.Server/ModelManifest.xml
|
|
||||||
_Pvt_Extensions
|
|
||||||
|
|
||||||
# Paket dependency manager
|
|
||||||
.paket/paket.exe
|
|
||||||
paket-files/
|
|
||||||
|
|
||||||
# FAKE - F# Make
|
|
||||||
.fake/
|
|
||||||
|
|
||||||
# CodeRush personal settings
|
|
||||||
.cr/personal
|
|
||||||
|
|
||||||
# Python Tools for Visual Studio (PTVS)
|
|
||||||
__pycache__/
|
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# Cake - Uncomment if you are using it
|
|
||||||
# tools/**
|
|
||||||
# !tools/packages.config
|
|
||||||
|
|
||||||
# Tabs Studio
|
|
||||||
*.tss
|
|
||||||
|
|
||||||
# Telerik's JustMock configuration file
|
|
||||||
*.jmconfig
|
|
||||||
|
|
||||||
# BizTalk build output
|
|
||||||
*.btp.cs
|
|
||||||
*.btm.cs
|
|
||||||
*.odx.cs
|
|
||||||
*.xsd.cs
|
|
||||||
|
|
||||||
# OpenCover UI analysis results
|
|
||||||
OpenCover/
|
|
||||||
|
|
||||||
# Azure Stream Analytics local run output
|
|
||||||
ASALocalRun/
|
|
||||||
|
|
||||||
# MSBuild Binary and Structured Log
|
|
||||||
*.binlog
|
|
||||||
|
|
||||||
# NVidia Nsight GPU debugger configuration file
|
|
||||||
*.nvuser
|
|
||||||
|
|
||||||
# MFractors (Xamarin productivity tool) working folder
|
|
||||||
.mfractor/
|
|
||||||
|
|
||||||
# Local History for Visual Studio
|
|
||||||
.localhistory/
|
|
||||||
|
|
||||||
# Visual Studio History (VSHistory) files
|
|
||||||
.vshistory/
|
|
||||||
|
|
||||||
# BeatPulse healthcheck temp database
|
|
||||||
healthchecksdb
|
|
||||||
|
|
||||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
|
||||||
MigrationBackup/
|
|
||||||
|
|
||||||
# Ionide (cross platform F# VS Code tools) working folder
|
|
||||||
.ionide/
|
|
||||||
|
|
||||||
# Fody - auto-generated XML schema
|
|
||||||
FodyWeavers.xsd
|
|
||||||
|
|
||||||
# VS Code files for those working on multiple tools
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/settings.json
|
|
||||||
!.vscode/tasks.json
|
|
||||||
!.vscode/launch.json
|
|
||||||
!.vscode/extensions.json
|
|
||||||
*.code-workspace
|
|
||||||
|
|
||||||
# Local History for Visual Studio Code
|
|
||||||
.history/
|
|
||||||
|
|
||||||
# Windows Installer files from build outputs
|
|
||||||
*.cab
|
|
||||||
*.msi
|
|
||||||
*.msix
|
|
||||||
*.msm
|
|
||||||
*.msp
|
|
||||||
|
|
||||||
# JetBrains Rider
|
|
||||||
*.sln.iml
|
|
||||||
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
<Project>
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)NHotkey.snk</AssemblyOriginatorKeyFile>
|
|
||||||
<SignAssembly>true</SignAssembly>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Label="Package properties">
|
|
||||||
<Authors>Thomas Levesque</Authors>
|
|
||||||
<PackageProjectUrl>https://github.com/thomaslevesque/NHotkey</PackageProjectUrl>
|
|
||||||
<PackageLicenseExpression>Apache-2.0</PackageLicenseExpression>
|
|
||||||
<PackageTags>global;hotkey;windows</PackageTags>
|
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
|
||||||
<AllowedOutputExtensionsInPackageBuildOutputFolder>$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb</AllowedOutputExtensionsInPackageBuildOutputFolder>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="MinVer" Version="2.3.0" PrivateAssets="all" />
|
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
// ReSharper disable once CheckNamespace
|
|
||||||
namespace System.Runtime.CompilerServices
|
|
||||||
{
|
|
||||||
// Enables extension methods in assembly that targets .NET 2.0
|
|
||||||
|
|
||||||
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Method)]
|
|
||||||
internal sealed class ExtensionAttribute : Attribute
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace NHotkey.WindowsForms
|
|
||||||
{
|
|
||||||
static class Extensions
|
|
||||||
{
|
|
||||||
public static bool HasFlag(this Keys keys, Keys flag)
|
|
||||||
{
|
|
||||||
return (keys & flag) == flag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
|
|
||||||
namespace NHotkey.WindowsForms
|
|
||||||
{
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage(
|
|
||||||
"Microsoft.Design",
|
|
||||||
"CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable",
|
|
||||||
Justification = "This is a singleton; disposing it would break it")]
|
|
||||||
public class HotkeyManager : HotkeyManagerBase
|
|
||||||
{
|
|
||||||
#region Singleton implementation
|
|
||||||
|
|
||||||
public static HotkeyManager Current { get { return LazyInitializer.Instance; } }
|
|
||||||
|
|
||||||
private static class LazyInitializer
|
|
||||||
{
|
|
||||||
static LazyInitializer() { }
|
|
||||||
public static readonly HotkeyManager Instance = new HotkeyManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
|
||||||
private readonly MessageWindow _messageWindow;
|
|
||||||
|
|
||||||
private HotkeyManager()
|
|
||||||
{
|
|
||||||
_messageWindow = new MessageWindow(this);
|
|
||||||
SetHwnd(_messageWindow.Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddOrReplace(string name, Keys keys, bool noRepeat, EventHandler<HotkeyEventArgs> handler)
|
|
||||||
{
|
|
||||||
var flags = GetFlags(keys, noRepeat);
|
|
||||||
var vk = unchecked((uint)(keys & ~Keys.Modifiers));
|
|
||||||
AddOrReplace(name, vk, flags, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddOrReplace(string name, Keys keys, EventHandler<HotkeyEventArgs> handler)
|
|
||||||
{
|
|
||||||
AddOrReplace(name, keys, false, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static HotkeyFlags GetFlags(Keys hotkey, bool noRepeat)
|
|
||||||
{
|
|
||||||
var noMod = hotkey & ~Keys.Modifiers;
|
|
||||||
var flags = HotkeyFlags.None;
|
|
||||||
if (hotkey.HasFlag(Keys.Alt))
|
|
||||||
flags |= HotkeyFlags.Alt;
|
|
||||||
if (hotkey.HasFlag(Keys.Control))
|
|
||||||
flags |= HotkeyFlags.Control;
|
|
||||||
if (hotkey.HasFlag(Keys.Shift))
|
|
||||||
flags |= HotkeyFlags.Shift;
|
|
||||||
if (noMod == Keys.LWin || noMod == Keys.RWin)
|
|
||||||
flags |= HotkeyFlags.Windows;
|
|
||||||
if (noRepeat)
|
|
||||||
flags |= HotkeyFlags.NoRepeat;
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
class MessageWindow : ContainerControl
|
|
||||||
{
|
|
||||||
private readonly HotkeyManager _hotkeyManager;
|
|
||||||
|
|
||||||
public MessageWindow(HotkeyManager hotkeyManager)
|
|
||||||
{
|
|
||||||
_hotkeyManager = hotkeyManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override CreateParams CreateParams
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var parameters = base.CreateParams;
|
|
||||||
parameters.Parent = HwndMessage;
|
|
||||||
return parameters;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void WndProc(ref Message m)
|
|
||||||
{
|
|
||||||
bool handled = false;
|
|
||||||
Hotkey hotkey;
|
|
||||||
m.Result = _hotkeyManager.HandleHotkeyMessage(Handle, m.Msg, m.WParam, m.LParam, ref handled, out hotkey);
|
|
||||||
if (!handled)
|
|
||||||
base.WndProc(ref m);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFrameworks>net40;net45;netcoreapp3.0</TargetFrameworks>
|
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Label="Package properties">
|
|
||||||
<Description>A managed library to handle global hotkeys in Windows Forms applications. This package contains the concrete HotkeyManager implementation for Windows Forms.</Description>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\NHotkey\NHotkey.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
using System.Windows.Input;
|
|
||||||
|
|
||||||
namespace NHotkey.Wpf
|
|
||||||
{
|
|
||||||
static class Extensions
|
|
||||||
{
|
|
||||||
public static bool HasFlag(this ModifierKeys modifiers, ModifierKeys flag)
|
|
||||||
{
|
|
||||||
return (modifiers & flag) == flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool HasFlag(this HotkeyFlags flags, HotkeyFlags flag)
|
|
||||||
{
|
|
||||||
return (flags & flag) == flag;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace NHotkey.Wpf
|
|
||||||
{
|
|
||||||
public class HotkeyAlreadyRegisteredEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
private readonly string _name;
|
|
||||||
|
|
||||||
public HotkeyAlreadyRegisteredEventArgs(string name)
|
|
||||||
{
|
|
||||||
_name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get { return _name; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,249 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Interop;
|
|
||||||
|
|
||||||
namespace NHotkey.Wpf
|
|
||||||
{
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessage(
|
|
||||||
"Microsoft.Design",
|
|
||||||
"CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable",
|
|
||||||
Justification = "This is a singleton; disposing it would break it")]
|
|
||||||
public class HotkeyManager : HotkeyManagerBase
|
|
||||||
{
|
|
||||||
#region Singleton implementation
|
|
||||||
|
|
||||||
public static HotkeyManager Current { get { return LazyInitializer.Instance; } }
|
|
||||||
|
|
||||||
private static class LazyInitializer
|
|
||||||
{
|
|
||||||
static LazyInitializer() { }
|
|
||||||
public static readonly HotkeyManager Instance = new HotkeyManager();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddOrReplace(string v, object incrementKeys, object onIncrement)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Attached property for KeyBindings
|
|
||||||
|
|
||||||
[AttachedPropertyBrowsableForType(typeof(KeyBinding))]
|
|
||||||
public static bool GetRegisterGlobalHotkey(KeyBinding binding)
|
|
||||||
{
|
|
||||||
return (bool)binding.GetValue(RegisterGlobalHotkeyProperty);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SetRegisterGlobalHotkey(KeyBinding binding, bool value)
|
|
||||||
{
|
|
||||||
binding.SetValue(RegisterGlobalHotkeyProperty, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static readonly DependencyProperty RegisterGlobalHotkeyProperty =
|
|
||||||
DependencyProperty.RegisterAttached(
|
|
||||||
"RegisterGlobalHotkey",
|
|
||||||
typeof(bool),
|
|
||||||
typeof(HotkeyManager),
|
|
||||||
new PropertyMetadata(
|
|
||||||
false,
|
|
||||||
RegisterGlobalHotkeyPropertyChanged));
|
|
||||||
|
|
||||||
private static void RegisterGlobalHotkeyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
var keyBinding = d as KeyBinding;
|
|
||||||
if (keyBinding == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool oldValue = (bool) e.OldValue;
|
|
||||||
bool newValue = (bool) e.NewValue;
|
|
||||||
|
|
||||||
if (DesignerProperties.GetIsInDesignMode(d))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (oldValue && !newValue)
|
|
||||||
{
|
|
||||||
Current.RemoveKeyBinding(keyBinding);
|
|
||||||
}
|
|
||||||
else if (newValue && !oldValue)
|
|
||||||
{
|
|
||||||
Current.AddKeyBinding(keyBinding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region HotkeyAlreadyRegistered event
|
|
||||||
|
|
||||||
public static event EventHandler<HotkeyAlreadyRegisteredEventArgs> HotkeyAlreadyRegistered;
|
|
||||||
|
|
||||||
private static void OnHotkeyAlreadyRegistered(string name)
|
|
||||||
{
|
|
||||||
var handler = HotkeyAlreadyRegistered;
|
|
||||||
if (handler != null)
|
|
||||||
handler(null, new HotkeyAlreadyRegisteredEventArgs(name));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
// ReSharper disable once PrivateFieldCanBeConvertedToLocalVariable
|
|
||||||
private readonly HwndSource _source;
|
|
||||||
private readonly WeakReferenceCollection<KeyBinding> _keyBindings;
|
|
||||||
|
|
||||||
private HotkeyManager()
|
|
||||||
{
|
|
||||||
_keyBindings = new WeakReferenceCollection<KeyBinding>();
|
|
||||||
|
|
||||||
var parameters = new HwndSourceParameters("Hotkey sink")
|
|
||||||
{
|
|
||||||
HwndSourceHook = HandleMessage,
|
|
||||||
ParentWindow = HwndMessage
|
|
||||||
};
|
|
||||||
_source = new HwndSource(parameters);
|
|
||||||
SetHwnd(_source.Handle);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddOrReplace(string name, KeyGesture gesture, EventHandler<HotkeyEventArgs> handler)
|
|
||||||
{
|
|
||||||
AddOrReplace(name, gesture, false, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddOrReplace(string name, KeyGesture gesture, bool noRepeat, EventHandler<HotkeyEventArgs> handler)
|
|
||||||
{
|
|
||||||
AddOrReplace(name, gesture.Key, gesture.Modifiers, noRepeat, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddOrReplace(string name, Key key, ModifierKeys modifiers, EventHandler<HotkeyEventArgs> handler)
|
|
||||||
{
|
|
||||||
AddOrReplace(name, key, modifiers, false, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddOrReplace(string name, Key key, ModifierKeys modifiers, bool noRepeat, EventHandler<HotkeyEventArgs> handler)
|
|
||||||
{
|
|
||||||
var flags = GetFlags(modifiers, noRepeat);
|
|
||||||
var vk = (uint)KeyInterop.VirtualKeyFromKey(key);
|
|
||||||
AddOrReplace(name, vk, flags, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static HotkeyFlags GetFlags(ModifierKeys modifiers, bool noRepeat)
|
|
||||||
{
|
|
||||||
var flags = HotkeyFlags.None;
|
|
||||||
if (modifiers.HasFlag(ModifierKeys.Shift))
|
|
||||||
flags |= HotkeyFlags.Shift;
|
|
||||||
if (modifiers.HasFlag(ModifierKeys.Control))
|
|
||||||
flags |= HotkeyFlags.Control;
|
|
||||||
if (modifiers.HasFlag(ModifierKeys.Alt))
|
|
||||||
flags |= HotkeyFlags.Alt;
|
|
||||||
if (modifiers.HasFlag(ModifierKeys.Windows))
|
|
||||||
flags |= HotkeyFlags.Windows;
|
|
||||||
if (noRepeat)
|
|
||||||
flags |= HotkeyFlags.NoRepeat;
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ModifierKeys GetModifiers(HotkeyFlags flags)
|
|
||||||
{
|
|
||||||
var modifiers = ModifierKeys.None;
|
|
||||||
if (flags.HasFlag(HotkeyFlags.Shift))
|
|
||||||
modifiers |= ModifierKeys.Shift;
|
|
||||||
if (flags.HasFlag(HotkeyFlags.Control))
|
|
||||||
modifiers |= ModifierKeys.Control;
|
|
||||||
if (flags.HasFlag(HotkeyFlags.Alt))
|
|
||||||
modifiers |= ModifierKeys.Alt;
|
|
||||||
if (flags.HasFlag(HotkeyFlags.Windows))
|
|
||||||
modifiers |= ModifierKeys.Windows;
|
|
||||||
return modifiers;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddKeyBinding(KeyBinding keyBinding)
|
|
||||||
{
|
|
||||||
var gesture = (KeyGesture)keyBinding.Gesture;
|
|
||||||
string name = GetNameForKeyBinding(gesture);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
AddOrReplace(name, gesture.Key, gesture.Modifiers, null);
|
|
||||||
_keyBindings.Add(keyBinding);
|
|
||||||
}
|
|
||||||
catch (HotkeyAlreadyRegisteredException)
|
|
||||||
{
|
|
||||||
OnHotkeyAlreadyRegistered(name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveKeyBinding(KeyBinding keyBinding)
|
|
||||||
{
|
|
||||||
var gesture = (KeyGesture)keyBinding.Gesture;
|
|
||||||
string name = GetNameForKeyBinding(gesture);
|
|
||||||
Remove(name);
|
|
||||||
_keyBindings.Remove(keyBinding);
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly KeyGestureConverter _gestureConverter = new KeyGestureConverter();
|
|
||||||
private string GetNameForKeyBinding(KeyGesture gesture)
|
|
||||||
{
|
|
||||||
string name = gesture.DisplayString;
|
|
||||||
if (string.IsNullOrEmpty(name))
|
|
||||||
name = _gestureConverter.ConvertToString(gesture);
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IntPtr HandleMessage(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled)
|
|
||||||
{
|
|
||||||
Hotkey hotkey;
|
|
||||||
var result = HandleHotkeyMessage(hwnd, msg, wparam, lparam, ref handled, out hotkey);
|
|
||||||
if (handled)
|
|
||||||
return result;
|
|
||||||
|
|
||||||
if (hotkey != null)
|
|
||||||
handled = ExecuteBoundCommand(hotkey);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool ExecuteBoundCommand(Hotkey hotkey)
|
|
||||||
{
|
|
||||||
var key = KeyInterop.KeyFromVirtualKey((int)hotkey.VirtualKey);
|
|
||||||
var modifiers = GetModifiers(hotkey.Flags);
|
|
||||||
bool handled = false;
|
|
||||||
foreach (var binding in _keyBindings)
|
|
||||||
{
|
|
||||||
if (binding.Key == key && binding.Modifiers == modifiers)
|
|
||||||
{
|
|
||||||
handled |= ExecuteCommand(binding);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return handled;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static bool ExecuteCommand(InputBinding binding)
|
|
||||||
{
|
|
||||||
var command = binding.Command;
|
|
||||||
var parameter = binding.CommandParameter;
|
|
||||||
var target = binding.CommandTarget;
|
|
||||||
|
|
||||||
if (command == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
var routedCommand = command as RoutedCommand;
|
|
||||||
if (routedCommand != null)
|
|
||||||
{
|
|
||||||
if (routedCommand.CanExecute(parameter, target))
|
|
||||||
{
|
|
||||||
routedCommand.Execute(parameter, target);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (command.CanExecute(parameter))
|
|
||||||
{
|
|
||||||
command.Execute(parameter);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFrameworks>net40;net45;net472;netcoreapp3.0;net6.0-windows</TargetFrameworks>
|
|
||||||
<UseWPF>true</UseWPF>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Label="Package properties">
|
|
||||||
<Description>A managed library to handle global hotkeys in WPF applications. This package contains the concrete HotkeyManager implementation for WPF.</Description>
|
|
||||||
</PropertyGroup>
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\NHotkey\NHotkey.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
</Project>
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
using System.Windows.Markup;
|
|
||||||
|
|
||||||
// Mapping a custom namespace to the standard WPF namespace is usually something to avoid,
|
|
||||||
// however in this case we're only importing one type (HotkeyManager), and it's unlikely to
|
|
||||||
// collide with another type in a future version of WPF. So in this case, we do it for the
|
|
||||||
// sake of simplicity, so that the user doesn't need to map the namespace manually.
|
|
||||||
[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation", "NHotkey.Wpf")]
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace NHotkey.Wpf
|
|
||||||
{
|
|
||||||
class WeakReferenceCollection<T> : IEnumerable<T>
|
|
||||||
where T : class
|
|
||||||
{
|
|
||||||
private readonly List<WeakReference> _references = new List<WeakReference>();
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
|
||||||
{
|
|
||||||
var references = _references.ToList();
|
|
||||||
foreach (var reference in references)
|
|
||||||
{
|
|
||||||
var target = reference.Target;
|
|
||||||
if (target != null)
|
|
||||||
yield return (T) target;
|
|
||||||
}
|
|
||||||
Trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Add(T item)
|
|
||||||
{
|
|
||||||
_references.Add(new WeakReference(item));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Remove(T item)
|
|
||||||
{
|
|
||||||
_references.RemoveAll(r => (r.Target ?? item) == item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Trim()
|
|
||||||
{
|
|
||||||
_references.RemoveAll(r => !r.IsAlive);
|
|
||||||
}
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 17
|
|
||||||
VisualStudioVersion = 17.0.32112.339
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHotkey", "NHotkey\NHotkey.csproj", "{6CAB99C4-6F21-4508-9160-CE4DBF540840}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHotkey.WindowsForms", "NHotkey.WindowsForms\NHotkey.WindowsForms.csproj", "{F0D5CDB4-B74A-419B-9AD6-2A438A268837}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NHotkey.Wpf", "NHotkey.Wpf\NHotkey.Wpf.csproj", "{FC92233F-6F08-45B7-B3EE-7C557582236B}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{6CAB99C4-6F21-4508-9160-CE4DBF540840}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{6CAB99C4-6F21-4508-9160-CE4DBF540840}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{6CAB99C4-6F21-4508-9160-CE4DBF540840}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{6CAB99C4-6F21-4508-9160-CE4DBF540840}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{F0D5CDB4-B74A-419B-9AD6-2A438A268837}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{F0D5CDB4-B74A-419B-9AD6-2A438A268837}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{F0D5CDB4-B74A-419B-9AD6-2A438A268837}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{F0D5CDB4-B74A-419B-9AD6-2A438A268837}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{FC92233F-6F08-45B7-B3EE-7C557582236B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{FC92233F-6F08-45B7-B3EE-7C557582236B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{FC92233F-6F08-45B7-B3EE-7C557582236B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{FC92233F-6F08-45B7-B3EE-7C557582236B}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {67220BE9-A1D5-41B9-9D16-177606E9D4D5}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
||||||
Binary file not shown.
Binary file not shown.
@@ -1,71 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace NHotkey
|
|
||||||
{
|
|
||||||
internal class Hotkey
|
|
||||||
{
|
|
||||||
private static int _nextId;
|
|
||||||
|
|
||||||
private readonly int _id;
|
|
||||||
private readonly uint _virtualKey;
|
|
||||||
private readonly HotkeyFlags _flags;
|
|
||||||
private readonly EventHandler<HotkeyEventArgs> _handler;
|
|
||||||
|
|
||||||
public Hotkey(uint virtualKey, HotkeyFlags flags, EventHandler<HotkeyEventArgs> handler)
|
|
||||||
{
|
|
||||||
_id = ++_nextId;
|
|
||||||
_virtualKey = virtualKey;
|
|
||||||
_flags = flags;
|
|
||||||
_handler = handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Id
|
|
||||||
{
|
|
||||||
get { return _id; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint VirtualKey
|
|
||||||
{
|
|
||||||
get { return _virtualKey; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public HotkeyFlags Flags
|
|
||||||
{
|
|
||||||
get { return _flags; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public EventHandler<HotkeyEventArgs> Handler
|
|
||||||
{
|
|
||||||
get { return _handler; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private IntPtr _hwnd;
|
|
||||||
|
|
||||||
public void Register(IntPtr hwnd, string name)
|
|
||||||
{
|
|
||||||
if (!NativeMethods.RegisterHotKey(hwnd, _id, _flags, _virtualKey))
|
|
||||||
{
|
|
||||||
var hr = Marshal.GetHRForLastWin32Error();
|
|
||||||
var ex = Marshal.GetExceptionForHR(hr);
|
|
||||||
if ((uint) hr == 0x80070581)
|
|
||||||
throw new HotkeyAlreadyRegisteredException(name, ex);
|
|
||||||
throw ex;
|
|
||||||
}
|
|
||||||
_hwnd = hwnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Unregister()
|
|
||||||
{
|
|
||||||
if (_hwnd != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
if (!NativeMethods.UnregisterHotKey(_hwnd, _id))
|
|
||||||
{
|
|
||||||
var hr = Marshal.GetHRForLastWin32Error();
|
|
||||||
throw Marshal.GetExceptionForHR(hr);
|
|
||||||
}
|
|
||||||
_hwnd = IntPtr.Zero;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Runtime.Serialization;
|
|
||||||
|
|
||||||
namespace NHotkey
|
|
||||||
{
|
|
||||||
[Serializable]
|
|
||||||
public class HotkeyAlreadyRegisteredException : Exception
|
|
||||||
{
|
|
||||||
private readonly string _name;
|
|
||||||
|
|
||||||
public HotkeyAlreadyRegisteredException(string name, Exception inner) : base(inner.Message, inner)
|
|
||||||
{
|
|
||||||
_name = name;
|
|
||||||
HResult = Marshal.GetHRForException(inner);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected HotkeyAlreadyRegisteredException(
|
|
||||||
SerializationInfo info,
|
|
||||||
StreamingContext context) : base(info, context)
|
|
||||||
{
|
|
||||||
_name = (string) info.GetValue("_name", typeof (string));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
|
||||||
{
|
|
||||||
base.GetObjectData(info, context);
|
|
||||||
info.AddValue("_name", _name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get { return _name; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace NHotkey
|
|
||||||
{
|
|
||||||
public class HotkeyEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
private readonly string _name;
|
|
||||||
|
|
||||||
internal HotkeyEventArgs(string name)
|
|
||||||
{
|
|
||||||
_name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get { return _name; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Handled { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace NHotkey
|
|
||||||
{
|
|
||||||
[Flags]
|
|
||||||
internal enum HotkeyFlags : uint
|
|
||||||
{
|
|
||||||
None = 0x0000,
|
|
||||||
Alt = 0x0001,
|
|
||||||
Control = 0x0002,
|
|
||||||
Shift = 0x0004,
|
|
||||||
Windows = 0x0008,
|
|
||||||
NoRepeat = 0x4000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace NHotkey
|
|
||||||
{
|
|
||||||
public abstract class HotkeyManagerBase
|
|
||||||
{
|
|
||||||
private readonly Dictionary<int, string> _hotkeyNames = new Dictionary<int, string>();
|
|
||||||
private readonly Dictionary<string, Hotkey> _hotkeys = new Dictionary<string, Hotkey>();
|
|
||||||
private IntPtr _hwnd;
|
|
||||||
internal static readonly IntPtr HwndMessage = (IntPtr)(-3);
|
|
||||||
|
|
||||||
internal HotkeyManagerBase()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void AddOrReplace(string name, uint virtualKey, HotkeyFlags flags, EventHandler<HotkeyEventArgs> handler)
|
|
||||||
{
|
|
||||||
var hotkey = new Hotkey(virtualKey, flags, handler);
|
|
||||||
lock (_hotkeys)
|
|
||||||
{
|
|
||||||
Remove(name);
|
|
||||||
_hotkeys.Add(name, hotkey);
|
|
||||||
_hotkeyNames.Add(hotkey.Id, name);
|
|
||||||
if (_hwnd != IntPtr.Zero)
|
|
||||||
hotkey.Register(_hwnd, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Remove(string name)
|
|
||||||
{
|
|
||||||
lock (_hotkeys)
|
|
||||||
{
|
|
||||||
Hotkey hotkey;
|
|
||||||
if (_hotkeys.TryGetValue(name, out hotkey))
|
|
||||||
{
|
|
||||||
_hotkeys.Remove(name);
|
|
||||||
_hotkeyNames.Remove(hotkey.Id);
|
|
||||||
if (_hwnd != IntPtr.Zero)
|
|
||||||
hotkey.Unregister();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsEnabled { get; set; } = true;
|
|
||||||
|
|
||||||
internal void SetHwnd(IntPtr hwnd)
|
|
||||||
{
|
|
||||||
_hwnd = hwnd;
|
|
||||||
}
|
|
||||||
|
|
||||||
private const int WmHotkey = 0x0312;
|
|
||||||
|
|
||||||
internal IntPtr HandleHotkeyMessage(
|
|
||||||
IntPtr hwnd,
|
|
||||||
int msg,
|
|
||||||
IntPtr wParam,
|
|
||||||
IntPtr lParam,
|
|
||||||
ref bool handled,
|
|
||||||
out Hotkey hotkey)
|
|
||||||
{
|
|
||||||
hotkey = null;
|
|
||||||
if (IsEnabled && msg == WmHotkey)
|
|
||||||
{
|
|
||||||
int id = wParam.ToInt32();
|
|
||||||
string name;
|
|
||||||
if (_hotkeyNames.TryGetValue(id, out name))
|
|
||||||
{
|
|
||||||
hotkey = _hotkeys[name];
|
|
||||||
var handler = hotkey.Handler;
|
|
||||||
if (handler != null)
|
|
||||||
{
|
|
||||||
var e = new HotkeyEventArgs(name);
|
|
||||||
handler(this, e);
|
|
||||||
handled = e.Handled;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return IntPtr.Zero;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFrameworks>net40;net45;netcoreapp3.0;net6.0-windows</TargetFrameworks>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Label="Package properties">
|
|
||||||
<Description>A managed library to handle global hotkeys in Windows Forms and WPF applications. NOTE: this package doesn't contain a concrete HotkeyManager implementation; you should add either the NHotkey.Wpf or NHotkey.WindowsForms package to get one.</Description>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace NHotkey
|
|
||||||
{
|
|
||||||
static class NativeMethods
|
|
||||||
{
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
|
||||||
internal static extern bool RegisterHotKey(IntPtr hWnd, int id, HotkeyFlags fsModifiers, uint vk);
|
|
||||||
|
|
||||||
[DllImport("user32.dll", SetLastError = true)]
|
|
||||||
internal static extern bool UnregisterHotKey(IntPtr hWnd, int id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("NHotkey.WindowsForms, PublicKey=00240000048000009400000006020000002400005253413100040000010001000d37f28dea0d86462d702c5ff882a20c5701fc1421107b336430c0af082910e58ff42c9030dcfe5739ab99f74b91b11dd4de06bfcd30bc9402beb15f023becb0c6b92ad9496e8e5474f3f5684ed32bf9fb69da84593b8be9bebd86542bd452c5bb77e071bbb2f0024a501ebfa897a62798fe2f2a4e72f250fc9c8277e17db1d5")]
|
|
||||||
[assembly: InternalsVisibleTo("NHotkey.Wpf, PublicKey=00240000048000009400000006020000002400005253413100040000010001000d37f28dea0d86462d702c5ff882a20c5701fc1421107b336430c0af082910e58ff42c9030dcfe5739ab99f74b91b11dd4de06bfcd30bc9402beb15f023becb0c6b92ad9496e8e5474f3f5684ed32bf9fb69da84593b8be9bebd86542bd452c5bb77e071bbb2f0024a501ebfa897a62798fe2f2a4e72f250fc9c8277e17db1d5")]
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# NHotkey.Wpf
|
|
||||||
|
|
||||||
400
NotifyIconWpf/.gitignore
vendored
400
NotifyIconWpf/.gitignore
vendored
@@ -1,400 +0,0 @@
|
|||||||
# ---> VisualStudio
|
|
||||||
## Ignore Visual Studio temporary files, build results, and
|
|
||||||
## files generated by popular Visual Studio add-ons.
|
|
||||||
##
|
|
||||||
## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
|
|
||||||
|
|
||||||
# User-specific files
|
|
||||||
*.rsuser
|
|
||||||
*.suo
|
|
||||||
*.user
|
|
||||||
*.userosscache
|
|
||||||
*.sln.docstates
|
|
||||||
|
|
||||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
|
||||||
*.userprefs
|
|
||||||
|
|
||||||
# Mono auto generated files
|
|
||||||
mono_crash.*
|
|
||||||
|
|
||||||
# Build results
|
|
||||||
[Dd]ebug/
|
|
||||||
[Dd]ebugPublic/
|
|
||||||
[Rr]elease/
|
|
||||||
[Rr]eleases/
|
|
||||||
x64/
|
|
||||||
x86/
|
|
||||||
[Ww][Ii][Nn]32/
|
|
||||||
[Aa][Rr][Mm]/
|
|
||||||
[Aa][Rr][Mm]64/
|
|
||||||
bld/
|
|
||||||
[Bb]in/
|
|
||||||
[Oo]bj/
|
|
||||||
[Ll]og/
|
|
||||||
[Ll]ogs/
|
|
||||||
|
|
||||||
# Visual Studio 2015/2017 cache/options directory
|
|
||||||
.vs/
|
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
|
||||||
#wwwroot/
|
|
||||||
|
|
||||||
# Visual Studio 2017 auto generated files
|
|
||||||
Generated\ Files/
|
|
||||||
|
|
||||||
# MSTest test Results
|
|
||||||
[Tt]est[Rr]esult*/
|
|
||||||
[Bb]uild[Ll]og.*
|
|
||||||
|
|
||||||
# NUnit
|
|
||||||
*.VisualState.xml
|
|
||||||
TestResult.xml
|
|
||||||
nunit-*.xml
|
|
||||||
|
|
||||||
# Build Results of an ATL Project
|
|
||||||
[Dd]ebugPS/
|
|
||||||
[Rr]eleasePS/
|
|
||||||
dlldata.c
|
|
||||||
|
|
||||||
# Benchmark Results
|
|
||||||
BenchmarkDotNet.Artifacts/
|
|
||||||
|
|
||||||
# .NET Core
|
|
||||||
project.lock.json
|
|
||||||
project.fragment.lock.json
|
|
||||||
artifacts/
|
|
||||||
|
|
||||||
# ASP.NET Scaffolding
|
|
||||||
ScaffoldingReadMe.txt
|
|
||||||
|
|
||||||
# StyleCop
|
|
||||||
StyleCopReport.xml
|
|
||||||
|
|
||||||
# Files built by Visual Studio
|
|
||||||
*_i.c
|
|
||||||
*_p.c
|
|
||||||
*_h.h
|
|
||||||
*.ilk
|
|
||||||
*.meta
|
|
||||||
*.obj
|
|
||||||
*.iobj
|
|
||||||
*.pch
|
|
||||||
*.pdb
|
|
||||||
*.ipdb
|
|
||||||
*.pgc
|
|
||||||
*.pgd
|
|
||||||
*.rsp
|
|
||||||
*.sbr
|
|
||||||
*.tlb
|
|
||||||
*.tli
|
|
||||||
*.tlh
|
|
||||||
*.tmp
|
|
||||||
*.tmp_proj
|
|
||||||
*_wpftmp.csproj
|
|
||||||
*.log
|
|
||||||
*.tlog
|
|
||||||
*.vspscc
|
|
||||||
*.vssscc
|
|
||||||
.builds
|
|
||||||
*.pidb
|
|
||||||
*.svclog
|
|
||||||
*.scc
|
|
||||||
|
|
||||||
# Chutzpah Test files
|
|
||||||
_Chutzpah*
|
|
||||||
|
|
||||||
# Visual C++ cache files
|
|
||||||
ipch/
|
|
||||||
*.aps
|
|
||||||
*.ncb
|
|
||||||
*.opendb
|
|
||||||
*.opensdf
|
|
||||||
*.sdf
|
|
||||||
*.cachefile
|
|
||||||
*.VC.db
|
|
||||||
*.VC.VC.opendb
|
|
||||||
|
|
||||||
# Visual Studio profiler
|
|
||||||
*.psess
|
|
||||||
*.vsp
|
|
||||||
*.vspx
|
|
||||||
*.sap
|
|
||||||
|
|
||||||
# Visual Studio Trace Files
|
|
||||||
*.e2e
|
|
||||||
|
|
||||||
# TFS 2012 Local Workspace
|
|
||||||
$tf/
|
|
||||||
|
|
||||||
# Guidance Automation Toolkit
|
|
||||||
*.gpState
|
|
||||||
|
|
||||||
# ReSharper is a .NET coding add-in
|
|
||||||
_ReSharper*/
|
|
||||||
*.[Rr]e[Ss]harper
|
|
||||||
*.DotSettings.user
|
|
||||||
|
|
||||||
# TeamCity is a build add-in
|
|
||||||
_TeamCity*
|
|
||||||
|
|
||||||
# DotCover is a Code Coverage Tool
|
|
||||||
*.dotCover
|
|
||||||
|
|
||||||
# AxoCover is a Code Coverage Tool
|
|
||||||
.axoCover/*
|
|
||||||
!.axoCover/settings.json
|
|
||||||
|
|
||||||
# Coverlet is a free, cross platform Code Coverage Tool
|
|
||||||
coverage*.json
|
|
||||||
coverage*.xml
|
|
||||||
coverage*.info
|
|
||||||
|
|
||||||
# Visual Studio code coverage results
|
|
||||||
*.coverage
|
|
||||||
*.coveragexml
|
|
||||||
|
|
||||||
# NCrunch
|
|
||||||
_NCrunch_*
|
|
||||||
.*crunch*.local.xml
|
|
||||||
nCrunchTemp_*
|
|
||||||
|
|
||||||
# MightyMoose
|
|
||||||
*.mm.*
|
|
||||||
AutoTest.Net/
|
|
||||||
|
|
||||||
# Web workbench (sass)
|
|
||||||
.sass-cache/
|
|
||||||
|
|
||||||
# Installshield output folder
|
|
||||||
[Ee]xpress/
|
|
||||||
|
|
||||||
# DocProject is a documentation generator add-in
|
|
||||||
DocProject/buildhelp/
|
|
||||||
DocProject/Help/*.HxT
|
|
||||||
DocProject/Help/*.HxC
|
|
||||||
DocProject/Help/*.hhc
|
|
||||||
DocProject/Help/*.hhk
|
|
||||||
DocProject/Help/*.hhp
|
|
||||||
DocProject/Help/Html2
|
|
||||||
DocProject/Help/html
|
|
||||||
|
|
||||||
# Click-Once directory
|
|
||||||
publish/
|
|
||||||
|
|
||||||
# Publish Web Output
|
|
||||||
*.[Pp]ublish.xml
|
|
||||||
*.azurePubxml
|
|
||||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
|
||||||
# but database connection strings (with potential passwords) will be unencrypted
|
|
||||||
*.pubxml
|
|
||||||
*.publishproj
|
|
||||||
|
|
||||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
|
||||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
|
||||||
# in these scripts will be unencrypted
|
|
||||||
PublishScripts/
|
|
||||||
|
|
||||||
# NuGet Packages
|
|
||||||
*.nupkg
|
|
||||||
# NuGet Symbol Packages
|
|
||||||
*.snupkg
|
|
||||||
# The packages folder can be ignored because of Package Restore
|
|
||||||
**/[Pp]ackages/*
|
|
||||||
# except build/, which is used as an MSBuild target.
|
|
||||||
!**/[Pp]ackages/build/
|
|
||||||
# Uncomment if necessary however generally it will be regenerated when needed
|
|
||||||
#!**/[Pp]ackages/repositories.config
|
|
||||||
# NuGet v3's project.json files produces more ignorable files
|
|
||||||
*.nuget.props
|
|
||||||
*.nuget.targets
|
|
||||||
|
|
||||||
# Microsoft Azure Build Output
|
|
||||||
csx/
|
|
||||||
*.build.csdef
|
|
||||||
|
|
||||||
# Microsoft Azure Emulator
|
|
||||||
ecf/
|
|
||||||
rcf/
|
|
||||||
|
|
||||||
# Windows Store app package directories and files
|
|
||||||
AppPackages/
|
|
||||||
BundleArtifacts/
|
|
||||||
Package.StoreAssociation.xml
|
|
||||||
_pkginfo.txt
|
|
||||||
*.appx
|
|
||||||
*.appxbundle
|
|
||||||
*.appxupload
|
|
||||||
|
|
||||||
# Visual Studio cache files
|
|
||||||
# files ending in .cache can be ignored
|
|
||||||
*.[Cc]ache
|
|
||||||
# but keep track of directories ending in .cache
|
|
||||||
!?*.[Cc]ache/
|
|
||||||
|
|
||||||
# Others
|
|
||||||
ClientBin/
|
|
||||||
~$*
|
|
||||||
*~
|
|
||||||
*.dbmdl
|
|
||||||
*.dbproj.schemaview
|
|
||||||
*.jfm
|
|
||||||
*.pfx
|
|
||||||
*.publishsettings
|
|
||||||
orleans.codegen.cs
|
|
||||||
|
|
||||||
# Including strong name files can present a security risk
|
|
||||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
|
||||||
#*.snk
|
|
||||||
|
|
||||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
|
||||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
|
||||||
#bower_components/
|
|
||||||
|
|
||||||
# RIA/Silverlight projects
|
|
||||||
Generated_Code/
|
|
||||||
|
|
||||||
# Backup & report files from converting an old project file
|
|
||||||
# to a newer Visual Studio version. Backup files are not needed,
|
|
||||||
# because we have git ;-)
|
|
||||||
_UpgradeReport_Files/
|
|
||||||
Backup*/
|
|
||||||
UpgradeLog*.XML
|
|
||||||
UpgradeLog*.htm
|
|
||||||
ServiceFabricBackup/
|
|
||||||
*.rptproj.bak
|
|
||||||
|
|
||||||
# SQL Server files
|
|
||||||
*.mdf
|
|
||||||
*.ldf
|
|
||||||
*.ndf
|
|
||||||
|
|
||||||
# Business Intelligence projects
|
|
||||||
*.rdl.data
|
|
||||||
*.bim.layout
|
|
||||||
*.bim_*.settings
|
|
||||||
*.rptproj.rsuser
|
|
||||||
*- [Bb]ackup.rdl
|
|
||||||
*- [Bb]ackup ([0-9]).rdl
|
|
||||||
*- [Bb]ackup ([0-9][0-9]).rdl
|
|
||||||
|
|
||||||
# Microsoft Fakes
|
|
||||||
FakesAssemblies/
|
|
||||||
|
|
||||||
# GhostDoc plugin setting file
|
|
||||||
*.GhostDoc.xml
|
|
||||||
|
|
||||||
# Node.js Tools for Visual Studio
|
|
||||||
.ntvs_analysis.dat
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# Visual Studio 6 build log
|
|
||||||
*.plg
|
|
||||||
|
|
||||||
# Visual Studio 6 workspace options file
|
|
||||||
*.opt
|
|
||||||
|
|
||||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
|
||||||
*.vbw
|
|
||||||
|
|
||||||
# Visual Studio 6 auto-generated project file (contains which files were open etc.)
|
|
||||||
*.vbp
|
|
||||||
|
|
||||||
# Visual Studio 6 workspace and project file (working project files containing files to include in project)
|
|
||||||
*.dsw
|
|
||||||
*.dsp
|
|
||||||
|
|
||||||
# Visual Studio 6 technical files
|
|
||||||
*.ncb
|
|
||||||
*.aps
|
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/ModelManifest.xml
|
|
||||||
**/*.Server/GeneratedArtifacts
|
|
||||||
**/*.Server/ModelManifest.xml
|
|
||||||
_Pvt_Extensions
|
|
||||||
|
|
||||||
# Paket dependency manager
|
|
||||||
.paket/paket.exe
|
|
||||||
paket-files/
|
|
||||||
|
|
||||||
# FAKE - F# Make
|
|
||||||
.fake/
|
|
||||||
|
|
||||||
# CodeRush personal settings
|
|
||||||
.cr/personal
|
|
||||||
|
|
||||||
# Python Tools for Visual Studio (PTVS)
|
|
||||||
__pycache__/
|
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# Cake - Uncomment if you are using it
|
|
||||||
# tools/**
|
|
||||||
# !tools/packages.config
|
|
||||||
|
|
||||||
# Tabs Studio
|
|
||||||
*.tss
|
|
||||||
|
|
||||||
# Telerik's JustMock configuration file
|
|
||||||
*.jmconfig
|
|
||||||
|
|
||||||
# BizTalk build output
|
|
||||||
*.btp.cs
|
|
||||||
*.btm.cs
|
|
||||||
*.odx.cs
|
|
||||||
*.xsd.cs
|
|
||||||
|
|
||||||
# OpenCover UI analysis results
|
|
||||||
OpenCover/
|
|
||||||
|
|
||||||
# Azure Stream Analytics local run output
|
|
||||||
ASALocalRun/
|
|
||||||
|
|
||||||
# MSBuild Binary and Structured Log
|
|
||||||
*.binlog
|
|
||||||
|
|
||||||
# NVidia Nsight GPU debugger configuration file
|
|
||||||
*.nvuser
|
|
||||||
|
|
||||||
# MFractors (Xamarin productivity tool) working folder
|
|
||||||
.mfractor/
|
|
||||||
|
|
||||||
# Local History for Visual Studio
|
|
||||||
.localhistory/
|
|
||||||
|
|
||||||
# Visual Studio History (VSHistory) files
|
|
||||||
.vshistory/
|
|
||||||
|
|
||||||
# BeatPulse healthcheck temp database
|
|
||||||
healthchecksdb
|
|
||||||
|
|
||||||
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
|
||||||
MigrationBackup/
|
|
||||||
|
|
||||||
# Ionide (cross platform F# VS Code tools) working folder
|
|
||||||
.ionide/
|
|
||||||
|
|
||||||
# Fody - auto-generated XML schema
|
|
||||||
FodyWeavers.xsd
|
|
||||||
|
|
||||||
# VS Code files for those working on multiple tools
|
|
||||||
.vscode/*
|
|
||||||
!.vscode/settings.json
|
|
||||||
!.vscode/tasks.json
|
|
||||||
!.vscode/launch.json
|
|
||||||
!.vscode/extensions.json
|
|
||||||
*.code-workspace
|
|
||||||
|
|
||||||
# Local History for Visual Studio Code
|
|
||||||
.history/
|
|
||||||
|
|
||||||
# Windows Installer files from build outputs
|
|
||||||
*.cab
|
|
||||||
*.msi
|
|
||||||
*.msix
|
|
||||||
*.msm
|
|
||||||
*.msp
|
|
||||||
|
|
||||||
# JetBrains Rider
|
|
||||||
*.sln.iml
|
|
||||||
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
<Project>
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFrameworks>net45;net462;net472;netcoreapp3.1;net5.0-windows</TargetFrameworks>
|
|
||||||
<LangVersion>latest</LangVersion>
|
|
||||||
<UseWindowsForms>true</UseWindowsForms>
|
|
||||||
<UseWPF>true</UseWPF>
|
|
||||||
<AppendTargetFrameworkToOutputPath>true</AppendTargetFrameworkToOutputPath>
|
|
||||||
<IsSampleProject>$(MSBuildProjectName.Contains('Sample'))</IsSampleProject>
|
|
||||||
<DebugSymbols>True</DebugSymbols>
|
|
||||||
<DebugType>embedded</DebugType>
|
|
||||||
|
|
||||||
<Copyright>Copyright (c) 2009-2021 Philipp Sumi</Copyright>
|
|
||||||
<Company>hardcodet.net</Company>
|
|
||||||
<Authors>Philipp Sumi, Robin Krom, Jan Karger</Authors>
|
|
||||||
<PackageIcon>icon.png</PackageIcon>
|
|
||||||
<RepositoryUrl>https://github.com/hardcodet/wpf-notifyicon</RepositoryUrl>
|
|
||||||
<RepositoryType>git</RepositoryType>
|
|
||||||
<PackageProjectUrl>https://github.com/hardcodet/wpf-notifyicon</PackageProjectUrl>
|
|
||||||
<PackageLicenseFile>LICENSE</PackageLicenseFile>
|
|
||||||
<requireLicenseAcceptance>false</requireLicenseAcceptance>
|
|
||||||
<Description>This is an implementation of a NotifyIcon (aka system tray icon or taskbar icon) for the WPF platform. It does not just rely on the Windows Forms NotifyIcon component, but is a purely independent control which leverages several features of the WPF framework in order to display rich tooltips, popups, context menus, and balloon messages. It can be used directly in code or embedded in any XAML file.
|
|
||||||
|
|
||||||
Source code and extensive sample application available at http://www.hardcodet.net/projects/wpf-notifyicon</Description>
|
|
||||||
<Summary>NotifyIcon (aka system tray icon or taskbar icon) for the WPF platform.</Summary>
|
|
||||||
<tags>NotifyIcon WPF Tray Notify ToolTip Popup Balloon Toast</tags>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition="$(TargetFramework.StartsWith('net4'))">
|
|
||||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
|
|
||||||
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Nerdbank.GitVersioning" Version="3.3.37">
|
|
||||||
<PrivateAssets>all</PrivateAssets>
|
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
|
||||||
</PackageReference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<Choose>
|
|
||||||
<When Condition=" '$(IsSampleProject)' != 'true' ">
|
|
||||||
<PropertyGroup>
|
|
||||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
|
||||||
<IsPackable>true</IsPackable>
|
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<SignAssembly>true</SignAssembly>
|
|
||||||
<AssemblyOriginatorKeyFile>..\NotifyIconWpf.snk</AssemblyOriginatorKeyFile>
|
|
||||||
<DelaySign>false</DelaySign>
|
|
||||||
<PublicSign Condition=" '$(OS)' != 'Windows_NT' ">true</PublicSign>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All"/>
|
|
||||||
<None Include="$(SolutionDir)\icon.png" Pack="true" PackagePath="\"/>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<!-- SourceLink -->
|
|
||||||
<PropertyGroup>
|
|
||||||
<!-- Optional: Declare that the Repository URL can be published to NuSpec -->
|
|
||||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
|
||||||
<!-- Optional: Embed source files that are not tracked by the source control manager to the PDB -->
|
|
||||||
<EmbedUntrackedSources>true</EmbedUntrackedSources>
|
|
||||||
<!-- https://github.com/dotnet/sourcelink/blob/master/docs/README.md#embedallsources -->
|
|
||||||
<EmbedAllSources>true</EmbedAllSources>
|
|
||||||
</PropertyGroup>
|
|
||||||
</When>
|
|
||||||
</Choose>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Remove="**\*.png;**\*.jpg;**\*.ico" />
|
|
||||||
<Resource Include="**\*.png;**\*.jpg;**\*.ico" />
|
|
||||||
<None Include="..\..\LICENSE" Pack="true" PackagePath="" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
|
||||||
# Visual Studio Version 17
|
|
||||||
VisualStudioVersion = 17.0.32112.339
|
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NotifyIconWpf", "NotifyIconWpf\NotifyIconWpf.csproj", "{78E6F5E5-11F1-4840-BA37-87522806DEDF}"
|
|
||||||
EndProject
|
|
||||||
Global
|
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
|
||||||
Debug|Any CPU = Debug|Any CPU
|
|
||||||
Release|Any CPU = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
|
||||||
{78E6F5E5-11F1-4840-BA37-87522806DEDF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{78E6F5E5-11F1-4840-BA37-87522806DEDF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{78E6F5E5-11F1-4840-BA37-87522806DEDF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{78E6F5E5-11F1-4840-BA37-87522806DEDF}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
|
||||||
HideSolutionNode = FALSE
|
|
||||||
EndGlobalSection
|
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
|
||||||
SolutionGuid = {DE07A147-0D17-4667-A1F7-7076FDFF4AEA}
|
|
||||||
EndGlobalSection
|
|
||||||
EndGlobal
|
|
||||||
Binary file not shown.
@@ -1,52 +0,0 @@
|
|||||||
// hardcodet.net NotifyIcon for WPF
|
|
||||||
// Copyright (c) 2009 - 2020 Philipp Sumi
|
|
||||||
// Contact and Information: http://www.hardcodet.net
|
|
||||||
//
|
|
||||||
// This library is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the Code Project Open License (CPOL);
|
|
||||||
// either version 1.0 of the License, or (at your option) any later
|
|
||||||
// version.
|
|
||||||
//
|
|
||||||
// The above copyright notice and this permission notice shall be
|
|
||||||
// included in all copies or substantial portions of the Software.
|
|
||||||
//
|
|
||||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
||||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
||||||
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
||||||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
||||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
||||||
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
||||||
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
||||||
// OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
//
|
|
||||||
// THIS COPYRIGHT NOTICE MAY NOT BE REMOVED FROM THIS FILE
|
|
||||||
|
|
||||||
|
|
||||||
namespace Hardcodet.Wpf.TaskbarNotification
|
|
||||||
{
|
|
||||||
///<summary>
|
|
||||||
/// Supported icons for the tray's balloon messages.
|
|
||||||
///</summary>
|
|
||||||
public enum BalloonIcon
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The balloon message is displayed without an icon.
|
|
||||||
/// </summary>
|
|
||||||
None,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An information is displayed.
|
|
||||||
/// </summary>
|
|
||||||
Info,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A warning is displayed.
|
|
||||||
/// </summary>
|
|
||||||
Warning,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An error is displayed.
|
|
||||||
/// </summary>
|
|
||||||
Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<ClassDiagram MajorVersion="1" MinorVersion="1">
|
|
||||||
<Class Name="Hardcodet.Wpf.TaskbarNotification.TaskbarIcon">
|
|
||||||
<Position X="1.75" Y="0.5" Width="3.5" />
|
|
||||||
<Compartments>
|
|
||||||
<Compartment Name="Fields" Collapsed="true" />
|
|
||||||
<Compartment Name="Methods" Collapsed="true" />
|
|
||||||
</Compartments>
|
|
||||||
<TypeIdentifier>
|
|
||||||
<HashCode>N6qdVIeUdLmQtSUbiJhEGdYRjvJYXlhbEVBDKuPRO5s=</HashCode>
|
|
||||||
<FileName>TaskbarIcon.cs</FileName>
|
|
||||||
</TypeIdentifier>
|
|
||||||
<Lollipop Position="0.2" />
|
|
||||||
</Class>
|
|
||||||
<Enum Name="Hardcodet.Wpf.TaskbarNotification.PopupActivationMode">
|
|
||||||
<Position X="6.75" Y="0.5" Width="2" />
|
|
||||||
<TypeIdentifier>
|
|
||||||
<HashCode>ABAEAAAAAAAAAAABAAAAAAAAAAAAAAAAAIAKAIAAAAA=</HashCode>
|
|
||||||
<FileName>PopupActivationMode.cs</FileName>
|
|
||||||
</TypeIdentifier>
|
|
||||||
</Enum>
|
|
||||||
<Enum Name="Hardcodet.Wpf.TaskbarNotification.BalloonIcon">
|
|
||||||
<Position X="9.25" Y="0.5" Width="1.5" />
|
|
||||||
<TypeIdentifier>
|
|
||||||
<HashCode>AAAAAAAAAAAAAQAAAAAAABAAAAAAAAAAAAAAAEEAAAA=</HashCode>
|
|
||||||
<FileName>BalloonIcon.cs</FileName>
|
|
||||||
</TypeIdentifier>
|
|
||||||
</Enum>
|
|
||||||
<Font Name="Segoe UI" Size="9" />
|
|
||||||
</ClassDiagram>
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
// Some interop code taken from Mike Marshall's AnyForm
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
|
||||||
namespace Hardcodet.Wpf.TaskbarNotification.Interop
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// This contains the logic to access the location of the app bar and communicate with it.
|
|
||||||
/// </summary>
|
|
||||||
public class AppBarInfo
|
|
||||||
{
|
|
||||||
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
|
|
||||||
private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
|
||||||
|
|
||||||
[DllImport("shell32.dll")]
|
|
||||||
private static extern uint SHAppBarMessage(uint dwMessage, ref APPBARDATA data);
|
|
||||||
|
|
||||||
[DllImport("user32.dll")]
|
|
||||||
private static extern int SystemParametersInfo(uint uiAction, uint uiParam,
|
|
||||||
IntPtr pvParam, uint fWinIni);
|
|
||||||
|
|
||||||
private const int ABM_GETTASKBARPOS = 0x00000005;
|
|
||||||
|
|
||||||
|
|
||||||
private APPBARDATA m_data;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get on which edge the app bar is located
|
|
||||||
/// </summary>
|
|
||||||
public ScreenEdge Edge
|
|
||||||
{
|
|
||||||
get { return (ScreenEdge) m_data.uEdge; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get the working area
|
|
||||||
/// </summary>
|
|
||||||
public Rectangle WorkArea
|
|
||||||
{
|
|
||||||
get { return GetRectangle(m_data.rc); }
|
|
||||||
}
|
|
||||||
|
|
||||||
private Rectangle GetRectangle(RECT rc)
|
|
||||||
{
|
|
||||||
return new Rectangle(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update the location of the appbar with the specified classname and window name.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="strClassName">string</param>
|
|
||||||
/// <param name="strWindowName">string</param>
|
|
||||||
private void GetPosition(string strClassName, string strWindowName)
|
|
||||||
{
|
|
||||||
m_data = new APPBARDATA();
|
|
||||||
m_data.cbSize = (uint) Marshal.SizeOf(m_data.GetType());
|
|
||||||
|
|
||||||
IntPtr hWnd = FindWindow(strClassName, strWindowName);
|
|
||||||
|
|
||||||
if (hWnd != IntPtr.Zero)
|
|
||||||
{
|
|
||||||
uint uResult = SHAppBarMessage(ABM_GETTASKBARPOS, ref m_data);
|
|
||||||
|
|
||||||
if (uResult != 1)
|
|
||||||
{
|
|
||||||
throw new Exception("Failed to communicate with the given AppBar");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new Exception("Failed to find an AppBar that matched the given criteria");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Updates the system taskbar position
|
|
||||||
/// </summary>
|
|
||||||
public void GetSystemTaskBarPosition()
|
|
||||||
{
|
|
||||||
GetPosition("Shell_TrayWnd", null);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A value that specifies an edge of the screen.
|
|
||||||
/// </summary>
|
|
||||||
public enum ScreenEdge
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Undefined
|
|
||||||
/// </summary>
|
|
||||||
Undefined = -1,
|
|
||||||
/// <summary>
|
|
||||||
/// Left edge.
|
|
||||||
/// </summary>
|
|
||||||
Left = 0,
|
|
||||||
/// <summary>
|
|
||||||
/// Top edge.
|
|
||||||
/// </summary>
|
|
||||||
Top = 1,
|
|
||||||
/// <summary>
|
|
||||||
/// Right edge.
|
|
||||||
/// </summary>
|
|
||||||
Right = 2,
|
|
||||||
/// <summary>
|
|
||||||
/// Bottom edge.
|
|
||||||
/// </summary>
|
|
||||||
Bottom = 3
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
private struct APPBARDATA
|
|
||||||
{
|
|
||||||
public uint cbSize;
|
|
||||||
public IntPtr hWnd;
|
|
||||||
public uint uCallbackMessage;
|
|
||||||
public uint uEdge;
|
|
||||||
public RECT rc;
|
|
||||||
public int lParam;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
private struct RECT
|
|
||||||
{
|
|
||||||
public int left;
|
|
||||||
public int top;
|
|
||||||
public int right;
|
|
||||||
public int bottom;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Hardcodet.Wpf.TaskbarNotification.Interop
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Flags that define the icon that is shown on a balloon
|
|
||||||
/// tooltip.
|
|
||||||
/// </summary>
|
|
||||||
public enum BalloonFlags
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// No icon is displayed.
|
|
||||||
/// </summary>
|
|
||||||
None = 0x00,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An information icon is displayed.
|
|
||||||
/// </summary>
|
|
||||||
Info = 0x01,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A warning icon is displayed.
|
|
||||||
/// </summary>
|
|
||||||
Warning = 0x02,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// An error icon is displayed.
|
|
||||||
/// </summary>
|
|
||||||
Error = 0x03,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Windows XP Service Pack 2 (SP2) and later.
|
|
||||||
/// Use a custom icon as the title icon.
|
|
||||||
/// </summary>
|
|
||||||
User = 0x04,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Windows XP (Shell32.dll version 6.0) and later.
|
|
||||||
/// Do not play the associated sound. Applies only to balloon ToolTips.
|
|
||||||
/// </summary>
|
|
||||||
NoSound = 0x10,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Windows Vista (Shell32.dll version 6.0.6) and later. The large version
|
|
||||||
/// of the icon should be used as the balloon icon. This corresponds to the
|
|
||||||
/// icon with dimensions SM_CXICON x SM_CYICON. If this flag is not set,
|
|
||||||
/// the icon with dimensions XM_CXSMICON x SM_CYSMICON is used.<br/>
|
|
||||||
/// - This flag can be used with all stock icons.<br/>
|
|
||||||
/// - Applications that use older customized icons (NIIF_USER with hIcon) must
|
|
||||||
/// provide a new SM_CXICON x SM_CYICON version in the tray icon (hIcon). These
|
|
||||||
/// icons are scaled down when they are displayed in the System Tray or
|
|
||||||
/// System Control Area (SCA).<br/>
|
|
||||||
/// - New customized icons (NIIF_USER with hBalloonIcon) must supply an
|
|
||||||
/// SM_CXICON x SM_CYICON version in the supplied icon (hBalloonIcon).
|
|
||||||
/// </summary>
|
|
||||||
LargeIcon = 0x20,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Windows 7 and later.
|
|
||||||
/// </summary>
|
|
||||||
RespectQuietTime = 0x80
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Hardcodet.Wpf.TaskbarNotification.Interop
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Indicates which members of a <see cref="NotifyIconData"/> structure
|
|
||||||
/// were set, and thus contain valid data or provide additional information
|
|
||||||
/// to the ToolTip as to how it should display.
|
|
||||||
/// </summary>
|
|
||||||
[Flags]
|
|
||||||
public enum IconDataMembers
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The message ID is set.
|
|
||||||
/// </summary>
|
|
||||||
Message = 0x01,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The notification icon is set.
|
|
||||||
/// </summary>
|
|
||||||
Icon = 0x02,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The tooltip is set.
|
|
||||||
/// </summary>
|
|
||||||
Tip = 0x04,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// State information (<see cref="IconState"/>) is set. This
|
|
||||||
/// applies to both <see cref="NotifyIconData.IconState"/> and
|
|
||||||
/// <see cref="NotifyIconData.StateMask"/>.
|
|
||||||
/// </summary>
|
|
||||||
State = 0x08,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The balloon ToolTip is set. Accordingly, the following
|
|
||||||
/// members are set: <see cref="NotifyIconData.BalloonText"/>,
|
|
||||||
/// <see cref="NotifyIconData.BalloonTitle"/>, <see cref="NotifyIconData.BalloonFlags"/>,
|
|
||||||
/// and <see cref="NotifyIconData.VersionOrTimeout"/>.
|
|
||||||
/// </summary>
|
|
||||||
Info = 0x10,
|
|
||||||
|
|
||||||
// Internal identifier is set. Reserved, thus commented out.
|
|
||||||
//Guid = 0x20,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Windows Vista (Shell32.dll version 6.0.6) and later. If the ToolTip
|
|
||||||
/// cannot be displayed immediately, discard it.<br/>
|
|
||||||
/// Use this flag for ToolTips that represent real-time information which
|
|
||||||
/// would be meaningless or misleading if displayed at a later time.
|
|
||||||
/// For example, a message that states "Your telephone is ringing."<br/>
|
|
||||||
/// This modifies and must be combined with the <see cref="Info"/> flag.
|
|
||||||
/// </summary>
|
|
||||||
Realtime = 0x40,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Windows Vista (Shell32.dll version 6.0.6) and later.
|
|
||||||
/// Use the standard ToolTip. Normally, when uVersion is set
|
|
||||||
/// to NOTIFYICON_VERSION_4, the standard ToolTip is replaced
|
|
||||||
/// by the application-drawn pop-up user interface (UI).
|
|
||||||
/// If the application wants to show the standard tooltip
|
|
||||||
/// in that case, regardless of whether the on-hover UI is showing,
|
|
||||||
/// it can specify NIF_SHOWTIP to indicate the standard tooltip
|
|
||||||
/// should still be shown.<br/>
|
|
||||||
/// Note that the NIF_SHOWTIP flag is effective until the next call
|
|
||||||
/// to Shell_NotifyIcon.
|
|
||||||
/// </summary>
|
|
||||||
UseLegacyToolTips = 0x80
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
namespace Hardcodet.Wpf.TaskbarNotification.Interop
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The state of the icon - can be set to
|
|
||||||
/// hide the icon.
|
|
||||||
/// </summary>
|
|
||||||
public enum IconState
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The icon is visible.
|
|
||||||
/// </summary>
|
|
||||||
Visible = 0x00,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Hide the icon.
|
|
||||||
/// </summary>
|
|
||||||
Hidden = 0x01,
|
|
||||||
|
|
||||||
// The icon is shared - currently not supported, thus commented out.
|
|
||||||
//Shared = 0x02
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
namespace Hardcodet.Wpf.TaskbarNotification.Interop
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Event flags for clicked events.
|
|
||||||
/// </summary>
|
|
||||||
public enum MouseEvent
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The mouse was moved withing the
|
|
||||||
/// taskbar icon's area.
|
|
||||||
/// </summary>
|
|
||||||
MouseMove,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The right mouse button was clicked.
|
|
||||||
/// </summary>
|
|
||||||
IconRightMouseDown,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The left mouse button was clicked.
|
|
||||||
/// </summary>
|
|
||||||
IconLeftMouseDown,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The right mouse button was released.
|
|
||||||
/// </summary>
|
|
||||||
IconRightMouseUp,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The left mouse button was released.
|
|
||||||
/// </summary>
|
|
||||||
IconLeftMouseUp,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The middle mouse button was clicked.
|
|
||||||
/// </summary>
|
|
||||||
IconMiddleMouseDown,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The middle mouse button was released.
|
|
||||||
/// </summary>
|
|
||||||
IconMiddleMouseUp,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The taskbar icon was double clicked.
|
|
||||||
/// </summary>
|
|
||||||
IconDoubleClick,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The balloon tip was clicked.
|
|
||||||
/// </summary>
|
|
||||||
BalloonToolTipClicked
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
namespace Hardcodet.Wpf.TaskbarNotification.Interop
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Main operations performed on the
|
|
||||||
/// <see cref="WinApi.Shell_NotifyIcon"/> function.
|
|
||||||
/// </summary>
|
|
||||||
public enum NotifyCommand
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The taskbar icon is being created.
|
|
||||||
/// </summary>
|
|
||||||
Add = 0x00,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The settings of the taskbar icon are being updated.
|
|
||||||
/// </summary>
|
|
||||||
Modify = 0x01,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The taskbar icon is deleted.
|
|
||||||
/// </summary>
|
|
||||||
Delete = 0x02,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Focus is returned to the taskbar icon. Currently not in use.
|
|
||||||
/// </summary>
|
|
||||||
SetFocus = 0x03,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Shell32.dll version 5.0 and later only. Instructs the taskbar
|
|
||||||
/// to behave according to the version number specified in the
|
|
||||||
/// uVersion member of the structure pointed to by lpdata.
|
|
||||||
/// This message allows you to specify whether you want the version
|
|
||||||
/// 5.0 behavior found on Microsoft Windows 2000 systems, or the
|
|
||||||
/// behavior found on earlier Shell versions. The default value for
|
|
||||||
/// uVersion is zero, indicating that the original Windows 95 notify
|
|
||||||
/// icon behavior should be used.
|
|
||||||
/// </summary>
|
|
||||||
SetVersion = 0x04
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user