Squashed 'FSI.Lib/' content from commit dceb500

git-subtree-dir: FSI.Lib
git-subtree-split: dceb5008a2176c2b8ab5e55a73b1c25d31a7f841
This commit is contained in:
maier_S
2022-03-14 11:02:41 +01:00
commit 1a74bce2ad
51 changed files with 6124 additions and 0 deletions

390
.gitignore vendored Normal file
View File

@@ -0,0 +1,390 @@
# ---> 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

25
FSI.Lib.sln Normal file
View File

@@ -0,0 +1,25 @@

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

13
FSI.Lib/Alg/Casts.cs Normal file
View File

@@ -0,0 +1,13 @@
using System;
namespace FSI.Lib.Alg
{
public class Casts
{
public static dynamic Cast(dynamic obj, Type castTo)
{
return Convert.ChangeType(obj, castTo);
}
}
}

24
FSI.Lib/App.config Normal file
View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="Epl.Prj.Path"
value="\\fondium.org\DESI$\AUG_Abteilung\Betriebstechnik\EPL\P8\Data\Projekte\FSI\"/>
<add key="Epl.Pdf.Path"
value="\\10.10.1.40\Betriebstechnik\Eplan\"/>
<add key="TimeStamp.Format"
value="_yyyyMMdd_HHmmss"/>
<add key ="SieTiaWinCCMsgMgt.Autostart"
value="false"/>
<add key ="SieTiaWinCCMsgMgt.UpdateIntervall"
value="100"/>
<add key ="SieTiaWinCCMsgMgt.WindowsName"
value=""/>
<add key ="SieTiaWinCCMsgMgt.WindowsClassName"
value="#32770"/>
<add key ="SieTiaWinCCMsgMgt.ButtonName"
value="Zur Kenntnis genommen"/>
</appSettings>
</configuration>

View File

@@ -0,0 +1,78 @@
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);
}
}
}

31
FSI.Lib/FSI.Lib.csproj Normal file
View File

@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework>
<OutputType>Library</OutputType>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<UseWPF>true</UseWPF>
<ImportWindowsDesktopTargets>true</ImportWindowsDesktopTargets>
<AssemblyVersion>1.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>

View File

@@ -0,0 +1,54 @@
<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>

View File

@@ -0,0 +1,81 @@
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)
{
Close();
PwOk = true;
}
else
{
Close();
PwOk = false;
}
}
}
}

View File

@@ -0,0 +1,55 @@
<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>

View File

@@ -0,0 +1,61 @@
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);
}
}
}
}

View File

@@ -0,0 +1,116 @@
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));
}
}
});
}
}
}

View File

@@ -0,0 +1,68 @@
<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>

View File

@@ -0,0 +1,71 @@
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";
}
}
}
}

View File

@@ -0,0 +1,185 @@
<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>

View File

@@ -0,0 +1,63 @@
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 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)
{
string path;
if (ShowPdf)
{
Title = "FSI PDF-Auswahl";
path = Settings.Setting<string>("Epl.Pdf.Path");
}
else
{
Title = "FSI Epl Projektauswahl";
path = Settings.Setting<string>("Epl.Prj.Path");
}
Title += " v" + Assembly.GetExecutingAssembly().GetName().Version; // Version in Titel eintragen
Prj = new ViewModelPrj(new PrjDataProvider())
{
DataPath = path,
ShowPdf = ShowPdf,
};
DataContext = Prj;
Prj.Load();
}
private void tbSearch_TextChanged(object sender, TextChangedEventArgs e)
{
tbSearch.Select(tbSearch.Text.Length, 0);
}
}
}

View File

@@ -0,0 +1,25 @@
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);
}
}

View File

@@ -0,0 +1,209 @@
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 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 files = Settings.Setting<string>("Epl.Exe", Settings.Mode.ExeSetttings).Replace(Environment.NewLine, "").Replace("\t", "").Split(";");
var arguments = " /Variant:\"Electric P8\" ProjectOpen /Project:\"" + SeletctedPrj.FullName + "\"";
string fileName = string.Empty;
string path = string.Empty;
for (int i = 0; i <= files.Length - 1; i++)
{
if (File.Exists(files[i].Trim()))
{
fileName = files[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;
}
}
}

View File

@@ -0,0 +1,54 @@
<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>

View File

@@ -0,0 +1,116 @@
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;
}
}
}
}

View File

@@ -0,0 +1,59 @@
<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>

View File

@@ -0,0 +1,57 @@
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;
}
}
}
}

View File

@@ -0,0 +1,172 @@
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;
}
}
}
}

View File

@@ -0,0 +1,16 @@
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;
}
}
}

BIN
FSI.Lib/Icons/Cross.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
FSI.Lib/Icons/FondiumU.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
FSI.Lib/Icons/Open.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View File

@@ -0,0 +1,57 @@
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);
}
}

View File

@@ -0,0 +1,43 @@
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
}
}

View File

@@ -0,0 +1,77 @@
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
}
}

View File

@@ -0,0 +1,40 @@
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(); }
}
}
}

View File

@@ -0,0 +1,61 @@
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));
}
}
}

73
FSI.Lib/Settings.cs Normal file
View File

@@ -0,0 +1,73 @@
using System;
using System.Configuration;
using System.Globalization;
using System.Reflection;
namespace FSI.Lib
{
public static class Settings
{
//static UriBuilder uri = new UriBuilder(Assembly.GetExecutingAssembly().CodeBase);
#if NET472
static UriBuilder uri = new UriBuilder(Assembly.GetExecutingAssembly().Location);
#elif NET6_0
static UriBuilder uri = new(Assembly.GetExecutingAssembly().Location);
#endif
static readonly NumberFormatInfo nfi = new NumberFormatInfo()
{
NumberGroupSeparator = "",
CurrencyDecimalSeparator = "."
};
public static T Setting<T>(string name)
{
return Setting<T>(name, Mode.DllSettings);
}
public static T Setting<T>(string name, Mode exeSettings)
{
if (exeSettings == Mode.ExeSetttings)
{
Configuration configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
AppSettingsSection appSettingsSection = (AppSettingsSection)configuration.GetSection("appSettings");
return (T)Convert.ChangeType(appSettingsSection.Settings[name].Value, typeof(T), nfi);
}
if (exeSettings == Mode.DllSettings)
{
Configuration configuration = ConfigurationManager.OpenExeConfiguration(uri.Path);
AppSettingsSection appSettingsSection = (AppSettingsSection)configuration.GetSection("appSettings");
return (T)Convert.ChangeType(appSettingsSection.Settings[name].Value, typeof(T), nfi);
}
return (T)Convert.ChangeType(null, typeof(T), nfi);
}
public enum Mode
{
ExeSetttings,
DllSettings,
}
}
}
/*
App.Config file sample
<add key="Enabled" value="true" />
<add key="ExportPath" value="c:\" />
<add key="Seconds" value="25" />
<add key="Ratio" value="0.14" />
Usage:
somebooleanvar = Settings.Setting<bool>("Enabled");
somestringlvar = Settings.Setting<string>("ExportPath");
someintvar = Settings.Setting<int>("Seconds");
somedoublevar = Settings.Setting<double>("Ratio");
*/

16
FSI.Lib/TimeStamp.cs Normal file
View File

@@ -0,0 +1,16 @@
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);
}
}
}

View File

@@ -0,0 +1,27 @@
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;
}
}
}

View File

@@ -0,0 +1,22 @@
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;
}
}
}

View File

@@ -0,0 +1,16 @@
<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>

View File

@@ -0,0 +1,89 @@
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;
}
}
}

View File

@@ -0,0 +1,78 @@
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
}
}

View File

@@ -0,0 +1,319 @@
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

View File

@@ -0,0 +1,20 @@
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
}
}

View File

@@ -0,0 +1,396 @@
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
}
}

View File

@@ -0,0 +1,147 @@
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
}
}

View File

@@ -0,0 +1,235 @@
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
}
}

View File

@@ -0,0 +1 @@
https://github.com/macgile/DataGridFilter

View File

@@ -0,0 +1,36 @@
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();
}
}
}

View File

@@ -0,0 +1,880 @@
<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>

View File

@@ -0,0 +1,18 @@
<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>

View File

@@ -0,0 +1,138 @@
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
}
}

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# FSI.Lib
Fondium Singen Library