Initial commit: EngineeringSync v1.0.0
Vollständige Implementierung des EngineeringSync-Middleware-Tools: - Windows Service (Kestrel :5050) mit FileSystemWatcher + SignalR - WPF Tray-App mit PendingChanges- und Projektverwaltungs-Fenster - Setup-Wizard (8-Schritte-Installer) - SQLite/EF Core Datenschicht (WAL-Modus) - SHA-256-basiertes Debouncing (2s Fenster) - Backup-System mit konfigurierbarer Aufbewahrung Bugfixes & Verbesserungen: - BUG-1: AppDbContext OnConfiguring invertierte Bedingung behoben - BUG-2: Event-Handler-Leak in TrayApp (Fenster-Singleton-Pattern) - BUG-3: ProjectConfigChanged SignalR-Signal in allen CRUD-Endpoints - BUG-5: Rename-Sync löscht alte Datei im Simulations-Ordner - BUG-6: Doppeltes Dispose von SignalR verhindert - BUG-7: Registry-Deinstallation nur EngineeringSync-Eintrag entfernt - S1: Path-Traversal-Schutz via SafeCombine() im SyncManager - E1: FSW Buffer 64KB + automatischer Re-Scan bei Overflow - E2: Retry-Logik (3x) für gesperrte Dateien mit exponentiellem Backoff - E4: Channel.Writer.TryComplete() beim Shutdown - C2: HubMethodNames-Konstanten statt Magic Strings - E3: Pagination in Changes-API (page/pageSize Query-Parameter) - A1: Fire-and-Forget mit try/catch + Logging Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
86
EngineeringSync.Setup/Views/Pages/BackupOptionsPage.xaml
Normal file
86
EngineeringSync.Setup/Views/Pages/BackupOptionsPage.xaml
Normal file
@@ -0,0 +1,86 @@
|
||||
<local:WizardPageBase x:Class="EngineeringSync.Setup.Views.Pages.BackupOptionsPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:EngineeringSync.Setup.Views.Pages"
|
||||
Background="White">
|
||||
<Grid Margin="40,32,40,24">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Text="Backup-Einstellungen"
|
||||
Style="{StaticResource PageTitleStyle}"/>
|
||||
<TextBlock Grid.Row="1" Style="{StaticResource PageSubtitleStyle}"
|
||||
Text="Legen Sie fest, ob und wie Sicherungskopien vor dem Überschreiben von Simulationsdateien erstellt werden."/>
|
||||
|
||||
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel>
|
||||
|
||||
<!-- Master-Toggle -->
|
||||
<local:OptionCard Icon="" Title="Backups aktivieren"
|
||||
Description="Vor jeder Dateiüberschreibung wird automatisch eine .bak-Sicherungskopie erstellt"
|
||||
IsChecked="{Binding BackupEnabled, Mode=TwoWay}"/>
|
||||
|
||||
<!-- Optionen (nur wenn Backup aktiviert) -->
|
||||
<StackPanel Visibility="{Binding BackupEnabled,
|
||||
Converter={StaticResource BoolToVisConverter}}">
|
||||
|
||||
<!-- Speicherort -->
|
||||
<TextBlock Text="SPEICHERORT" Style="{StaticResource FieldLabelStyle}"
|
||||
Margin="0,16,0,8"/>
|
||||
|
||||
<!-- Mode=OneWay: gegenseitiger Ausschluss läuft über GroupName + TwoWay am zweiten Radio -->
|
||||
<RadioButton GroupName="BackupLocation"
|
||||
Content="Gleicher Ordner wie die Simulationsdatei"
|
||||
IsChecked="{Binding BackupUseCustomPath,
|
||||
Converter={StaticResource BoolToInvVisConverter},
|
||||
Mode=OneWay}"
|
||||
FontFamily="Segoe UI" FontSize="13" Margin="0,0,0,8"/>
|
||||
|
||||
<RadioButton GroupName="BackupLocation"
|
||||
Content="Eigener Backup-Ordner"
|
||||
IsChecked="{Binding BackupUseCustomPath, Mode=TwoWay}"
|
||||
FontFamily="Segoe UI" FontSize="13" Margin="0,0,0,8"/>
|
||||
|
||||
<!-- Pfad-Eingabe (nur bei eigenem Ordner) -->
|
||||
<DockPanel Margin="0,0,0,16"
|
||||
Visibility="{Binding BackupUseCustomPath,
|
||||
Converter={StaticResource BoolToVisConverter}}">
|
||||
<Button DockPanel.Dock="Right" Style="{StaticResource IconButtonStyle}"
|
||||
Margin="6,0,0,0" Click="BrowseBackupPath_Click"
|
||||
ToolTip="Backup-Verzeichnis wählen">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="14" Foreground="#0078D4"/>
|
||||
</Button>
|
||||
<TextBox Style="{StaticResource ModernTextBoxStyle}"
|
||||
Text="{Binding BackupCustomPath, UpdateSourceTrigger=PropertyChanged}"
|
||||
Height="36"/>
|
||||
</DockPanel>
|
||||
|
||||
<!-- Aufbewahrung -->
|
||||
<TextBlock Text="AUFBEWAHRUNG" Style="{StaticResource FieldLabelStyle}"
|
||||
Margin="0,0,0,8"/>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,4">
|
||||
<TextBlock Text="Maximal" FontFamily="Segoe UI" FontSize="13"
|
||||
VerticalAlignment="Center" Margin="0,0,8,0"/>
|
||||
<TextBox x:Name="MaxBackupsBox"
|
||||
Width="60" Height="32" Padding="6,0"
|
||||
FontFamily="Segoe UI" FontSize="13"
|
||||
Text="{Binding MaxBackupsPerFile, UpdateSourceTrigger=PropertyChanged}"
|
||||
VerticalContentAlignment="Center"/>
|
||||
<TextBlock Text="Backups pro Datei" FontFamily="Segoe UI" FontSize="13"
|
||||
VerticalAlignment="Center" Margin="8,0,0,0"/>
|
||||
</StackPanel>
|
||||
<TextBlock Text="(0 = unbegrenzt, alle Backups behalten)"
|
||||
FontFamily="Segoe UI" FontSize="11" Foreground="#5F5F5F"
|
||||
Margin="0,2,0,0"/>
|
||||
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</local:WizardPageBase>
|
||||
39
EngineeringSync.Setup/Views/Pages/BackupOptionsPage.xaml.cs
Normal file
39
EngineeringSync.Setup/Views/Pages/BackupOptionsPage.xaml.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Windows;
|
||||
using EngineeringSync.Setup.ViewModels;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace EngineeringSync.Setup.Views.Pages;
|
||||
|
||||
public partial class BackupOptionsPage : WizardPageBase
|
||||
{
|
||||
public BackupOptionsPage(WizardViewModel wizard) : base(wizard)
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void BrowseBackupPath_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dlg = new OpenFolderDialog
|
||||
{
|
||||
Title = "Backup-Verzeichnis wählen",
|
||||
InitialDirectory = string.IsNullOrEmpty(Wizard.State.BackupCustomPath)
|
||||
? null
|
||||
: Wizard.State.BackupCustomPath
|
||||
};
|
||||
if (dlg.ShowDialog() == true)
|
||||
Wizard.State.BackupCustomPath = dlg.FolderName;
|
||||
}
|
||||
|
||||
public override bool Validate()
|
||||
{
|
||||
if (Wizard.State.BackupEnabled &&
|
||||
Wizard.State.BackupUseCustomPath &&
|
||||
string.IsNullOrWhiteSpace(Wizard.State.BackupCustomPath))
|
||||
{
|
||||
MessageBox.Show("Bitte wählen Sie einen Backup-Ordner oder deaktivieren Sie die Option 'Eigener Backup-Ordner'.",
|
||||
"Validierung", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
62
EngineeringSync.Setup/Views/Pages/CompletionPage.xaml
Normal file
62
EngineeringSync.Setup/Views/Pages/CompletionPage.xaml
Normal file
@@ -0,0 +1,62 @@
|
||||
<local:WizardPageBase x:Class="EngineeringSync.Setup.Views.Pages.CompletionPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:EngineeringSync.Setup.Views.Pages"
|
||||
Background="White">
|
||||
<Grid>
|
||||
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center"
|
||||
MaxWidth="400" Margin="40">
|
||||
|
||||
<!-- Großes Erfolgs-Icon -->
|
||||
<Border Width="80" Height="80" CornerRadius="40"
|
||||
HorizontalAlignment="Center" Margin="0,0,0,24">
|
||||
<Border.Background>
|
||||
<RadialGradientBrush>
|
||||
<GradientStop Color="#E8F5E9" Offset="0"/>
|
||||
<GradientStop Color="#C8E6C9" Offset="1"/>
|
||||
</RadialGradientBrush>
|
||||
</Border.Background>
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="40"
|
||||
Foreground="#107C10" HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
|
||||
<TextBlock Text="Installation erfolgreich!"
|
||||
FontFamily="Segoe UI" FontSize="22" FontWeight="Light"
|
||||
Foreground="#1A1A1A" HorizontalAlignment="Center"
|
||||
Margin="0,0,0,12"/>
|
||||
|
||||
<TextBlock FontFamily="Segoe UI" FontSize="13" Foreground="#5F5F5F"
|
||||
TextAlignment="Center" TextWrapping="Wrap" LineHeight="22"
|
||||
Margin="0,0,0,32">
|
||||
<Run Text="EngineeringSync wurde erfolgreich installiert und konfiguriert."/>
|
||||
<LineBreak/>
|
||||
<Run Text="Der Windows-Dienst läuft im Hintergrund und überwacht Ihren Engineering-Ordner."/>
|
||||
</TextBlock>
|
||||
|
||||
<!-- Status-Chips -->
|
||||
<WrapPanel HorizontalAlignment="Center" Margin="0,0,0,32">
|
||||
<Border Background="#E8F5E9" CornerRadius="12" Padding="12,6" Margin="4">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="11" Foreground="#107C10" Margin="0,0,6,0"/>
|
||||
<TextBlock Text="Dienst aktiv" FontFamily="Segoe UI"
|
||||
FontSize="12" Foreground="#107C10"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
<Border Background="#E3F2FD" CornerRadius="12" Padding="12,6" Margin="4">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="11" Foreground="#0078D4" Margin="0,0,6,0"/>
|
||||
<TextBlock Text="Tray-App startet" FontFamily="Segoe UI"
|
||||
FontSize="12" Foreground="#0078D4"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</WrapPanel>
|
||||
|
||||
<TextBlock FontFamily="Segoe UI" FontSize="12" Foreground="#888888"
|
||||
TextAlignment="Center" TextWrapping="Wrap"
|
||||
Text="Klicken Sie auf "Schließen" um den Assistenten zu beenden."/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</local:WizardPageBase>
|
||||
11
EngineeringSync.Setup/Views/Pages/CompletionPage.xaml.cs
Normal file
11
EngineeringSync.Setup/Views/Pages/CompletionPage.xaml.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using EngineeringSync.Setup.ViewModels;
|
||||
|
||||
namespace EngineeringSync.Setup.Views.Pages;
|
||||
|
||||
public partial class CompletionPage : WizardPageBase
|
||||
{
|
||||
public CompletionPage(WizardViewModel wizard) : base(wizard)
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
17
EngineeringSync.Setup/Views/Pages/FeatureRow.xaml
Normal file
17
EngineeringSync.Setup/Views/Pages/FeatureRow.xaml
Normal file
@@ -0,0 +1,17 @@
|
||||
<UserControl x:Class="EngineeringSync.Setup.Views.Pages.FeatureRow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Margin="0,0,0,12">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<Border Width="36" Height="36" CornerRadius="8" Background="#F0F7FF" Margin="0,0,12,0">
|
||||
<TextBlock x:Name="IconText" FontFamily="Segoe MDL2 Assets" FontSize="16"
|
||||
Foreground="#0078D4" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<TextBlock x:Name="TitleText" FontFamily="Segoe UI" FontSize="13"
|
||||
FontWeight="SemiBold" Foreground="#1A1A1A"/>
|
||||
<TextBlock x:Name="DescText" FontFamily="Segoe UI" FontSize="11"
|
||||
Foreground="#5F5F5F" TextWrapping="Wrap" MaxWidth="420"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
25
EngineeringSync.Setup/Views/Pages/FeatureRow.xaml.cs
Normal file
25
EngineeringSync.Setup/Views/Pages/FeatureRow.xaml.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace EngineeringSync.Setup.Views.Pages;
|
||||
|
||||
public partial class FeatureRow : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty IconProperty =
|
||||
DependencyProperty.Register(nameof(Icon), typeof(string), typeof(FeatureRow),
|
||||
new PropertyMetadata(string.Empty, (d, e) => ((FeatureRow)d).IconText.Text = (string)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty TitleProperty =
|
||||
DependencyProperty.Register(nameof(Title), typeof(string), typeof(FeatureRow),
|
||||
new PropertyMetadata(string.Empty, (d, e) => ((FeatureRow)d).TitleText.Text = (string)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty DescriptionProperty =
|
||||
DependencyProperty.Register(nameof(Description), typeof(string), typeof(FeatureRow),
|
||||
new PropertyMetadata(string.Empty, (d, e) => ((FeatureRow)d).DescText.Text = (string)e.NewValue));
|
||||
|
||||
public string Icon { get => (string)GetValue(IconProperty); set => SetValue(IconProperty, value); }
|
||||
public string Title { get => (string)GetValue(TitleProperty); set => SetValue(TitleProperty, value); }
|
||||
public string Description { get => (string)GetValue(DescriptionProperty); set => SetValue(DescriptionProperty, value); }
|
||||
|
||||
public FeatureRow() => InitializeComponent();
|
||||
}
|
||||
138
EngineeringSync.Setup/Views/Pages/FirstProjectPage.xaml
Normal file
138
EngineeringSync.Setup/Views/Pages/FirstProjectPage.xaml
Normal file
@@ -0,0 +1,138 @@
|
||||
<local:WizardPageBase x:Class="EngineeringSync.Setup.Views.Pages.FirstProjectPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:EngineeringSync.Setup.Views.Pages"
|
||||
Background="White">
|
||||
<Grid Margin="40,32,40,24">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Text="Erstes Projekt konfigurieren"
|
||||
Style="{StaticResource PageTitleStyle}"/>
|
||||
<TextBlock Grid.Row="1" Style="{StaticResource PageSubtitleStyle}"
|
||||
Text="Definieren Sie Ihr erstes überwachtes Projekt. Sie können später über die Tray-App beliebig viele weitere Projekte hinzufügen."/>
|
||||
|
||||
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel>
|
||||
|
||||
<!-- Projektname -->
|
||||
<StackPanel Margin="0,0,0,16">
|
||||
<TextBlock Text="PROJEKTNAME" Style="{StaticResource FieldLabelStyle}"/>
|
||||
<TextBox Style="{StaticResource ModernTextBoxStyle}"
|
||||
Text="{Binding ProjectName, UpdateSourceTrigger=PropertyChanged}"
|
||||
Height="36"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Engineering-Pfad -->
|
||||
<StackPanel Margin="0,0,0,16">
|
||||
<TextBlock Style="{StaticResource FieldLabelStyle}">
|
||||
<Run Text="ENGINEERING-QUELLPFAD "/>
|
||||
<Run Text="(wird überwacht)" Foreground="#0078D4" FontWeight="Normal"/>
|
||||
</TextBlock>
|
||||
<DockPanel>
|
||||
<Button DockPanel.Dock="Right" Style="{StaticResource IconButtonStyle}"
|
||||
Margin="6,0,0,0" Click="BrowseEngineering_Click"
|
||||
ToolTip="Engineering-Verzeichnis wählen">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="14" Foreground="#0078D4"/>
|
||||
</Button>
|
||||
<TextBox Style="{StaticResource ModernTextBoxStyle}"
|
||||
Text="{Binding EngineeringPath, UpdateSourceTrigger=PropertyChanged}"
|
||||
Height="36"/>
|
||||
</DockPanel>
|
||||
<TextBlock Text="Änderungen in diesem Verzeichnis werden protokolliert und dem Simulations-Ingenieur gemeldet."
|
||||
FontFamily="Segoe UI" FontSize="11" Foreground="#5F5F5F" Margin="0,4,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Simulations-Pfad -->
|
||||
<StackPanel Margin="0,0,0,16">
|
||||
<TextBlock Style="{StaticResource FieldLabelStyle}">
|
||||
<Run Text="SIMULATIONS-ZIELPFAD "/>
|
||||
<Run Text="(Sync-Ziel)" Foreground="#107C10" FontWeight="Normal"/>
|
||||
</TextBlock>
|
||||
<DockPanel>
|
||||
<Button DockPanel.Dock="Right" Style="{StaticResource IconButtonStyle}"
|
||||
Margin="6,0,0,0" Click="BrowseSimulation_Click"
|
||||
ToolTip="Simulations-Verzeichnis wählen">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="14" Foreground="#107C10"/>
|
||||
</Button>
|
||||
<TextBox Style="{StaticResource ModernTextBoxStyle}"
|
||||
Text="{Binding SimulationPath, UpdateSourceTrigger=PropertyChanged}"
|
||||
Height="36"/>
|
||||
</DockPanel>
|
||||
<TextBlock Text="Freigegebene Änderungen werden kontrolliert in dieses Verzeichnis kopiert (mit automatischem Backup)."
|
||||
FontFamily="Segoe UI" FontSize="11" Foreground="#5F5F5F" Margin="0,4,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Dateiüberwachung -->
|
||||
<StackPanel Margin="0,0,0,16">
|
||||
<TextBlock Text="ÜBERWACHTE DATEIEN" Style="{StaticResource FieldLabelStyle}"/>
|
||||
|
||||
<!-- Option: Alle Dateien -->
|
||||
<Border Background="#F0F8FF" CornerRadius="6" Padding="12,10" Margin="0,4,0,8">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox x:Name="WatchAllCheck"
|
||||
IsChecked="{Binding WatchAllFiles}"
|
||||
VerticalAlignment="Center"
|
||||
Margin="0,0,10,0"/>
|
||||
<StackPanel>
|
||||
<TextBlock Text="Alle Dateitypen überwachen"
|
||||
FontFamily="Segoe UI" FontSize="13" FontWeight="SemiBold"
|
||||
Foreground="#1B1B2F"/>
|
||||
<TextBlock Text="Jede Dateiänderung im Ordner wird protokolliert (unabhängig von der Endung)."
|
||||
FontFamily="Segoe UI" FontSize="11" Foreground="#5F5F5F"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Spezifische Endungen (nur wenn nicht "Alle Dateien") -->
|
||||
<StackPanel Visibility="{Binding WatchAllFiles,
|
||||
Converter={StaticResource BoolToInvVisConverter}}">
|
||||
<TextBlock Text="DATEIENDUNGEN (komma-getrennt)"
|
||||
Style="{StaticResource FieldLabelStyle}" Margin="0,0,0,6"/>
|
||||
|
||||
<!-- Quick-Select Buttons -->
|
||||
<WrapPanel Margin="0,0,0,8">
|
||||
<Button Content=".jt" Tag=".jt" Click="AddExt_Click"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Padding="8,4" Margin="0,0,6,6" Height="26" FontSize="11"/>
|
||||
<Button Content=".cojt" Tag=".cojt" Click="AddExt_Click"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Padding="8,4" Margin="0,0,6,6" Height="26" FontSize="11"/>
|
||||
<Button Content=".xml" Tag=".xml" Click="AddExt_Click"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Padding="8,4" Margin="0,0,6,6" Height="26" FontSize="11"/>
|
||||
<Button Content=".stp" Tag=".stp" Click="AddExt_Click"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Padding="8,4" Margin="0,0,6,6" Height="26" FontSize="11"/>
|
||||
<Button Content=".step" Tag=".step" Click="AddExt_Click"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Padding="8,4" Margin="0,0,6,6" Height="26" FontSize="11"/>
|
||||
<Button Content=".igs" Tag=".igs" Click="AddExt_Click"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Padding="8,4" Margin="0,0,6,6" Height="26" FontSize="11"/>
|
||||
<Button Content=".iges" Tag=".iges" Click="AddExt_Click"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Padding="8,4" Margin="0,0,6,6" Height="26" FontSize="11"/>
|
||||
<Button Content=".prt" Tag=".prt" Click="AddExt_Click"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Padding="8,4" Margin="0,0,6,6" Height="26" FontSize="11"/>
|
||||
</WrapPanel>
|
||||
|
||||
<TextBox x:Name="ExtensionsBox"
|
||||
Style="{StaticResource ModernTextBoxStyle}"
|
||||
Text="{Binding FileExtensions, UpdateSourceTrigger=PropertyChanged}"
|
||||
Height="36"/>
|
||||
<TextBlock Text="Klicke auf einen Typ um ihn hinzuzufügen, oder tippe direkt."
|
||||
FontFamily="Segoe UI" FontSize="11" Foreground="#5F5F5F" Margin="0,4,0,0"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</local:WizardPageBase>
|
||||
79
EngineeringSync.Setup/Views/Pages/FirstProjectPage.xaml.cs
Normal file
79
EngineeringSync.Setup/Views/Pages/FirstProjectPage.xaml.cs
Normal file
@@ -0,0 +1,79 @@
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using EngineeringSync.Setup.ViewModels;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace EngineeringSync.Setup.Views.Pages;
|
||||
|
||||
public partial class FirstProjectPage : WizardPageBase
|
||||
{
|
||||
public FirstProjectPage(WizardViewModel wizard) : base(wizard)
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void BrowseEngineering_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dlg = new OpenFolderDialog
|
||||
{
|
||||
Title = "Engineering-Quellpfad wählen",
|
||||
InitialDirectory = Wizard.State.EngineeringPath
|
||||
};
|
||||
if (dlg.ShowDialog() == true)
|
||||
Wizard.State.EngineeringPath = dlg.FolderName;
|
||||
}
|
||||
|
||||
private void BrowseSimulation_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dlg = new OpenFolderDialog
|
||||
{
|
||||
Title = "Simulations-Zielpfad wählen",
|
||||
InitialDirectory = Wizard.State.SimulationPath
|
||||
};
|
||||
if (dlg.ShowDialog() == true)
|
||||
Wizard.State.SimulationPath = dlg.FolderName;
|
||||
}
|
||||
|
||||
private void AddExt_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var ext = (sender as Button)?.Tag?.ToString();
|
||||
if (string.IsNullOrEmpty(ext)) return;
|
||||
|
||||
var current = Wizard.State.FileExtensions?.Trim() ?? string.Empty;
|
||||
var parts = current.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
if (!parts.Contains(ext, StringComparer.OrdinalIgnoreCase))
|
||||
Wizard.State.FileExtensions = current.Length > 0 ? current + "," + ext : ext;
|
||||
}
|
||||
|
||||
public override bool Validate()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Wizard.State.ProjectName))
|
||||
{
|
||||
MessageBox.Show("Bitte geben Sie einen Projektnamen an.",
|
||||
"Validierung", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(Wizard.State.EngineeringPath) ||
|
||||
!Directory.Exists(Wizard.State.EngineeringPath))
|
||||
{
|
||||
MessageBox.Show("Der Engineering-Pfad existiert nicht oder ist nicht angegeben.",
|
||||
"Validierung", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return false;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(Wizard.State.SimulationPath) ||
|
||||
!Directory.Exists(Wizard.State.SimulationPath))
|
||||
{
|
||||
MessageBox.Show("Der Simulations-Pfad existiert nicht oder ist nicht angegeben.",
|
||||
"Validierung", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return false;
|
||||
}
|
||||
if (!Wizard.State.WatchAllFiles && string.IsNullOrWhiteSpace(Wizard.State.FileExtensions))
|
||||
{
|
||||
MessageBox.Show("Bitte geben Sie mindestens eine Dateiendung an oder wählen Sie 'Alle Dateitypen überwachen'.",
|
||||
"Validierung", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
10
EngineeringSync.Setup/Views/Pages/InstallItem.xaml
Normal file
10
EngineeringSync.Setup/Views/Pages/InstallItem.xaml
Normal file
@@ -0,0 +1,10 @@
|
||||
<UserControl x:Class="EngineeringSync.Setup.Views.Pages.InstallItem"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Margin="0,2">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="10"
|
||||
Foreground="#107C10" Margin="0,0,8,0" VerticalAlignment="Center"/>
|
||||
<TextBlock x:Name="ItemText" FontFamily="Consolas" FontSize="12" Foreground="#1A1A1A"/>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
14
EngineeringSync.Setup/Views/Pages/InstallItem.xaml.cs
Normal file
14
EngineeringSync.Setup/Views/Pages/InstallItem.xaml.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace EngineeringSync.Setup.Views.Pages;
|
||||
|
||||
public partial class InstallItem : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty TextProperty =
|
||||
DependencyProperty.Register(nameof(Text), typeof(string), typeof(InstallItem),
|
||||
new PropertyMetadata(string.Empty, (d, e) => ((InstallItem)d).ItemText.Text = (string)e.NewValue));
|
||||
|
||||
public string Text { get => (string)GetValue(TextProperty); set => SetValue(TextProperty, value); }
|
||||
public InstallItem() => InitializeComponent();
|
||||
}
|
||||
61
EngineeringSync.Setup/Views/Pages/InstallPathPage.xaml
Normal file
61
EngineeringSync.Setup/Views/Pages/InstallPathPage.xaml
Normal file
@@ -0,0 +1,61 @@
|
||||
<local:WizardPageBase x:Class="EngineeringSync.Setup.Views.Pages.InstallPathPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:EngineeringSync.Setup.Views.Pages"
|
||||
Background="White">
|
||||
<Grid Margin="40,32,40,24">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Text="Installationsverzeichnis"
|
||||
Style="{StaticResource PageTitleStyle}"/>
|
||||
<TextBlock Grid.Row="1" Style="{StaticResource PageSubtitleStyle}"
|
||||
Text="Wählen Sie das Verzeichnis, in dem EngineeringSync installiert werden soll. Der Windows-Dienst und die Tray-App werden dort abgelegt."/>
|
||||
|
||||
<!-- Pfad-Auswahl -->
|
||||
<StackPanel Grid.Row="2" Margin="0,0,0,20">
|
||||
<TextBlock Text="INSTALLATIONSPFAD" Style="{StaticResource FieldLabelStyle}"/>
|
||||
<DockPanel>
|
||||
<Button DockPanel.Dock="Right" Style="{StaticResource IconButtonStyle}"
|
||||
Margin="6,0,0,0" ToolTip="Verzeichnis auswählen"
|
||||
Click="Browse_Click">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="14" Foreground="#0078D4"/>
|
||||
</Button>
|
||||
<TextBox x:Name="PathBox"
|
||||
Style="{StaticResource ModernTextBoxStyle}"
|
||||
Text="{Binding InstallPath, UpdateSourceTrigger=PropertyChanged}"
|
||||
Height="36"/>
|
||||
</DockPanel>
|
||||
|
||||
<!-- Speicherplatz-Hinweis -->
|
||||
<StackPanel Orientation="Horizontal" Margin="0,8,0,0">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="11" Foreground="#5F5F5F" Margin="0,0,6,0" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="Benötigter Speicherplatz: ca. 45 MB"
|
||||
FontFamily="Segoe UI" FontSize="11" Foreground="#5F5F5F"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Info-Karte -->
|
||||
<Border Grid.Row="3" Style="{StaticResource InfoCardStyle}" VerticalAlignment="Top">
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,8">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="14" Foreground="#0078D4" Margin="0,0,8,0"/>
|
||||
<TextBlock Text="Folgende Komponenten werden installiert:"
|
||||
FontFamily="Segoe UI" FontSize="12" FontWeight="SemiBold"
|
||||
Foreground="#1A1A1A"/>
|
||||
</StackPanel>
|
||||
<local:InstallItem Text="EngineeringSync.Service.exe (Windows-Dienst)"/>
|
||||
<local:InstallItem Text="EngineeringSync.TrayApp.exe (Tray-Anwendung)"/>
|
||||
<local:InstallItem Text="engineeringsync.db (Datenbank)"/>
|
||||
<local:InstallItem Text="appsettings.json (Konfiguration)"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</local:WizardPageBase>
|
||||
35
EngineeringSync.Setup/Views/Pages/InstallPathPage.xaml.cs
Normal file
35
EngineeringSync.Setup/Views/Pages/InstallPathPage.xaml.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.Windows;
|
||||
using EngineeringSync.Setup.ViewModels;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace EngineeringSync.Setup.Views.Pages;
|
||||
|
||||
public partial class InstallPathPage : WizardPageBase
|
||||
{
|
||||
public InstallPathPage(WizardViewModel wizard) : base(wizard)
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void Browse_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var dlg = new OpenFolderDialog
|
||||
{
|
||||
Title = "Installationsverzeichnis auswählen",
|
||||
InitialDirectory = Wizard.State.InstallPath
|
||||
};
|
||||
if (dlg.ShowDialog() == true)
|
||||
Wizard.State.InstallPath = dlg.FolderName;
|
||||
}
|
||||
|
||||
public override bool Validate()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Wizard.State.InstallPath))
|
||||
{
|
||||
MessageBox.Show("Bitte wählen Sie ein Installationsverzeichnis.",
|
||||
"Validierung", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
65
EngineeringSync.Setup/Views/Pages/InstallingPage.xaml
Normal file
65
EngineeringSync.Setup/Views/Pages/InstallingPage.xaml
Normal file
@@ -0,0 +1,65 @@
|
||||
<local:WizardPageBase x:Class="EngineeringSync.Setup.Views.Pages.InstallingPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:EngineeringSync.Setup.Views.Pages"
|
||||
Background="White"
|
||||
Loaded="Page_Loaded">
|
||||
<Grid Margin="40,32,40,24">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Text="Installation läuft..."
|
||||
Style="{StaticResource PageTitleStyle}"/>
|
||||
<TextBlock Grid.Row="1" x:Name="SubtitleText"
|
||||
Style="{StaticResource PageSubtitleStyle}"
|
||||
Text="Bitte warten Sie, während EngineeringSync installiert wird."/>
|
||||
|
||||
<!-- Fortschrittsbereich -->
|
||||
<StackPanel Grid.Row="2" VerticalAlignment="Center">
|
||||
|
||||
<!-- Aktueller Schritt -->
|
||||
<TextBlock x:Name="StepText"
|
||||
FontFamily="Segoe UI" FontSize="13" FontWeight="SemiBold"
|
||||
Foreground="#1A1A1A" Margin="0,0,0,8" Text="Starte Installation..."/>
|
||||
|
||||
<!-- Fortschrittsbalken -->
|
||||
<ProgressBar x:Name="ProgressBar"
|
||||
Style="{StaticResource ModernProgressBarStyle}"
|
||||
Minimum="0" Maximum="100" Value="0"
|
||||
Margin="0,0,0,4"/>
|
||||
|
||||
<Grid Margin="0,0,0,24">
|
||||
<TextBlock x:Name="ProgressText" FontFamily="Segoe UI" FontSize="11"
|
||||
Foreground="#5F5F5F" HorizontalAlignment="Left" Text="0%"/>
|
||||
<TextBlock x:Name="TimeText" FontFamily="Segoe UI" FontSize="11"
|
||||
Foreground="#5F5F5F" HorizontalAlignment="Right" Text=""/>
|
||||
</Grid>
|
||||
|
||||
<!-- Live-Log -->
|
||||
<Border Background="#1E1E1E" CornerRadius="8" Padding="16" Height="180">
|
||||
<ScrollViewer x:Name="LogScrollViewer" VerticalScrollBarVisibility="Auto">
|
||||
<TextBlock x:Name="LogText"
|
||||
FontFamily="Cascadia Code, Consolas, Courier New"
|
||||
FontSize="11" Foreground="#CCCCCC"
|
||||
TextWrapping="Wrap" LineHeight="18"/>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Erfolgs/Fehler-Banner -->
|
||||
<Border Grid.Row="3" x:Name="ResultBanner"
|
||||
CornerRadius="8" Padding="14,10" Margin="0,16,0,0"
|
||||
Visibility="Collapsed">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock x:Name="ResultIcon" FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="16" Margin="0,0,10,0" VerticalAlignment="Center"/>
|
||||
<TextBlock x:Name="ResultText" FontFamily="Segoe UI" FontSize="12"
|
||||
VerticalAlignment="Center" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</local:WizardPageBase>
|
||||
102
EngineeringSync.Setup/Views/Pages/InstallingPage.xaml.cs
Normal file
102
EngineeringSync.Setup/Views/Pages/InstallingPage.xaml.cs
Normal file
@@ -0,0 +1,102 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using EngineeringSync.Setup.Services;
|
||||
using EngineeringSync.Setup.ViewModels;
|
||||
|
||||
namespace EngineeringSync.Setup.Views.Pages;
|
||||
|
||||
public partial class InstallingPage : WizardPageBase
|
||||
{
|
||||
private readonly InstallerService _installer;
|
||||
private bool _started;
|
||||
|
||||
public InstallingPage(WizardViewModel wizard, InstallerService installer) : base(wizard)
|
||||
{
|
||||
_installer = installer;
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private async void Page_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Nur einmal starten (Page kann bei Navigation neu erzeugt werden)
|
||||
if (_started) return;
|
||||
_started = true;
|
||||
|
||||
_installer.Progress += OnProgress;
|
||||
_installer.LogMessage += OnLogMessage;
|
||||
|
||||
try
|
||||
{
|
||||
// Button während Installation deaktivieren
|
||||
Wizard.SetInstallingState(true);
|
||||
|
||||
await _installer.InstallAsync();
|
||||
ShowSuccess();
|
||||
|
||||
// Buttons wieder aktivieren vor Navigation
|
||||
Wizard.SetInstallingState(false);
|
||||
Wizard.NavigateTo(7); // → CompletionPage
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ShowError(ex.Message);
|
||||
// Buttons wieder aktivieren im Fehlerfall
|
||||
Wizard.SetInstallingState(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_installer.Progress -= OnProgress;
|
||||
_installer.LogMessage -= OnLogMessage;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnProgress(int percent, string step)
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
ProgressBar.Value = percent;
|
||||
ProgressText.Text = $"{percent}%";
|
||||
StepText.Text = step;
|
||||
});
|
||||
}
|
||||
|
||||
private void OnLogMessage(string message)
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
var ts = DateTime.Now.ToString("HH:mm:ss");
|
||||
LogText.Text += $"[{ts}] {message}\n";
|
||||
LogScrollViewer.ScrollToEnd();
|
||||
});
|
||||
}
|
||||
|
||||
private void ShowSuccess()
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
ResultBanner.Background = new SolidColorBrush(Color.FromRgb(232, 245, 233));
|
||||
ResultIcon.Text = "\uE73E";
|
||||
ResultIcon.Foreground = new SolidColorBrush(Color.FromRgb(16, 124, 16));
|
||||
ResultText.Text = "Installation erfolgreich abgeschlossen.";
|
||||
ResultText.Foreground = new SolidColorBrush(Color.FromRgb(16, 124, 16));
|
||||
ResultBanner.Visibility = Visibility.Visible;
|
||||
SubtitleText.Text = "Alle Komponenten wurden erfolgreich installiert.";
|
||||
ProgressBar.Value = 100;
|
||||
ProgressText.Text = "100%";
|
||||
});
|
||||
}
|
||||
|
||||
private void ShowError(string message)
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
ResultBanner.Background = new SolidColorBrush(Color.FromRgb(255, 235, 238));
|
||||
ResultIcon.Text = "\uE783";
|
||||
ResultIcon.Foreground = new SolidColorBrush(Color.FromRgb(196, 43, 28));
|
||||
ResultText.Text = $"Fehler: {message}";
|
||||
ResultText.Foreground = new SolidColorBrush(Color.FromRgb(196, 43, 28));
|
||||
ResultBanner.Visibility = Visibility.Visible;
|
||||
SubtitleText.Text = "Die Installation konnte nicht abgeschlossen werden.";
|
||||
});
|
||||
}
|
||||
}
|
||||
32
EngineeringSync.Setup/Views/Pages/OptionCard.xaml
Normal file
32
EngineeringSync.Setup/Views/Pages/OptionCard.xaml
Normal file
@@ -0,0 +1,32 @@
|
||||
<UserControl x:Class="EngineeringSync.Setup.Views.Pages.OptionCard"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Margin="0,0,0,8">
|
||||
<Border x:Name="CardBorder" Background="White" BorderThickness="1"
|
||||
BorderBrush="#E0E0E0" CornerRadius="8" Padding="16,12"
|
||||
Cursor="Hand" MouseLeftButtonDown="Card_Click">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="40"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Border Grid.Column="0" Width="32" Height="32" CornerRadius="8" Background="#F0F7FF">
|
||||
<TextBlock x:Name="IconText" FontFamily="Segoe MDL2 Assets" FontSize="15"
|
||||
Foreground="#0078D4" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
|
||||
<StackPanel Grid.Column="1" VerticalAlignment="Center" Margin="12,0">
|
||||
<TextBlock x:Name="TitleText" FontFamily="Segoe UI" FontSize="13"
|
||||
FontWeight="SemiBold" Foreground="#1A1A1A"/>
|
||||
<TextBlock x:Name="DescText" FontFamily="Segoe UI" FontSize="11"
|
||||
Foreground="#5F5F5F" TextWrapping="Wrap"/>
|
||||
</StackPanel>
|
||||
|
||||
<CheckBox x:Name="ToggleBox" Grid.Column="2"
|
||||
Style="{StaticResource ModernCheckBoxStyle}"
|
||||
VerticalAlignment="Center" IsHitTestVisible="False"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</UserControl>
|
||||
47
EngineeringSync.Setup/Views/Pages/OptionCard.xaml.cs
Normal file
47
EngineeringSync.Setup/Views/Pages/OptionCard.xaml.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace EngineeringSync.Setup.Views.Pages;
|
||||
|
||||
public partial class OptionCard : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty IconProperty =
|
||||
DependencyProperty.Register(nameof(Icon), typeof(string), typeof(OptionCard),
|
||||
new PropertyMetadata(string.Empty, (d, e) => ((OptionCard)d).IconText.Text = (string)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty TitleProperty =
|
||||
DependencyProperty.Register(nameof(Title), typeof(string), typeof(OptionCard),
|
||||
new PropertyMetadata(string.Empty, (d, e) => ((OptionCard)d).TitleText.Text = (string)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty DescriptionProperty =
|
||||
DependencyProperty.Register(nameof(Description), typeof(string), typeof(OptionCard),
|
||||
new PropertyMetadata(string.Empty, (d, e) => ((OptionCard)d).DescText.Text = (string)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty IsCheckedProperty =
|
||||
DependencyProperty.Register(nameof(IsChecked), typeof(bool), typeof(OptionCard),
|
||||
new FrameworkPropertyMetadata(true,
|
||||
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
|
||||
(d, e) => ((OptionCard)d).UpdateVisual((bool)e.NewValue)));
|
||||
|
||||
public string Icon { get => (string)GetValue(IconProperty); set => SetValue(IconProperty, value); }
|
||||
public string Title { get => (string)GetValue(TitleProperty); set => SetValue(TitleProperty, value); }
|
||||
public string Description { get => (string)GetValue(DescriptionProperty); set => SetValue(DescriptionProperty, value); }
|
||||
public bool IsChecked { get => (bool)GetValue(IsCheckedProperty); set => SetValue(IsCheckedProperty, value); }
|
||||
|
||||
public OptionCard() => InitializeComponent();
|
||||
|
||||
private void Card_Click(object sender, RoutedEventArgs e) => IsChecked = !IsChecked;
|
||||
|
||||
private void UpdateVisual(bool isChecked)
|
||||
{
|
||||
if (ToggleBox is null) return;
|
||||
ToggleBox.IsChecked = isChecked;
|
||||
CardBorder.BorderBrush = isChecked
|
||||
? new SolidColorBrush(Color.FromRgb(0, 120, 212))
|
||||
: new SolidColorBrush(Color.FromRgb(224, 224, 224));
|
||||
CardBorder.Background = isChecked
|
||||
? new SolidColorBrush(Color.FromArgb(15, 0, 120, 212))
|
||||
: new SolidColorBrush(Colors.White);
|
||||
}
|
||||
}
|
||||
51
EngineeringSync.Setup/Views/Pages/ServiceOptionsPage.xaml
Normal file
51
EngineeringSync.Setup/Views/Pages/ServiceOptionsPage.xaml
Normal file
@@ -0,0 +1,51 @@
|
||||
<local:WizardPageBase x:Class="EngineeringSync.Setup.Views.Pages.ServiceOptionsPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:EngineeringSync.Setup.Views.Pages"
|
||||
Background="White">
|
||||
<Grid Margin="40,32,40,24">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Text="Start- und Verknüpfungs-Optionen"
|
||||
Style="{StaticResource PageTitleStyle}"/>
|
||||
<TextBlock Grid.Row="1" Style="{StaticResource PageSubtitleStyle}"
|
||||
Text="Legen Sie fest, wie EngineeringSync beim Start von Windows und nach der Installation verhalten soll."/>
|
||||
|
||||
<StackPanel Grid.Row="2">
|
||||
|
||||
<!-- Autostart-Gruppe -->
|
||||
<TextBlock Text="AUTOSTART" Style="{StaticResource FieldLabelStyle}" Margin="0,0,0,10"/>
|
||||
|
||||
<local:OptionCard Icon="" Title="Windows-Dienst automatisch starten"
|
||||
Description="Der EngineeringSync-Dienst startet automatisch mit Windows (empfohlen)"
|
||||
IsChecked="{Binding AutoStartService, Mode=TwoWay}"/>
|
||||
|
||||
<local:OptionCard Icon="" Title="Tray-App bei Anmeldung starten"
|
||||
Description="Die Benachrichtigungs-App erscheint automatisch im Systemtray nach dem Login"
|
||||
IsChecked="{Binding AutoStartTrayApp, Mode=TwoWay}"/>
|
||||
|
||||
<!-- Verknüpfungen -->
|
||||
<TextBlock Text="VERKNÜPFUNGEN" Style="{StaticResource FieldLabelStyle}" Margin="0,20,0,10"/>
|
||||
|
||||
<local:OptionCard Icon="" Title="Desktop-Verknüpfung erstellen"
|
||||
Description="Erstellt eine Verknüpfung zur Tray-App auf dem Desktop"
|
||||
IsChecked="{Binding CreateDesktopShortcut, Mode=TwoWay}"/>
|
||||
|
||||
<local:OptionCard Icon="" Title="Startmenü-Eintrag erstellen"
|
||||
Description="Fügt EngineeringSync dem Windows-Startmenü hinzu"
|
||||
IsChecked="{Binding CreateStartMenuEntry, Mode=TwoWay}"/>
|
||||
|
||||
<!-- Nach Installation -->
|
||||
<TextBlock Text="NACH INSTALLATION" Style="{StaticResource FieldLabelStyle}" Margin="0,20,0,10"/>
|
||||
|
||||
<local:OptionCard Icon="" Title="Tray-App nach Installation starten"
|
||||
Description="Startet die Tray-App direkt nach Abschluss der Installation"
|
||||
IsChecked="{Binding StartAfterInstall, Mode=TwoWay}"/>
|
||||
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</local:WizardPageBase>
|
||||
11
EngineeringSync.Setup/Views/Pages/ServiceOptionsPage.xaml.cs
Normal file
11
EngineeringSync.Setup/Views/Pages/ServiceOptionsPage.xaml.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using EngineeringSync.Setup.ViewModels;
|
||||
|
||||
namespace EngineeringSync.Setup.Views.Pages;
|
||||
|
||||
public partial class ServiceOptionsPage : WizardPageBase
|
||||
{
|
||||
public ServiceOptionsPage(WizardViewModel wizard) : base(wizard)
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
18
EngineeringSync.Setup/Views/Pages/SummaryBoolRow.xaml
Normal file
18
EngineeringSync.Setup/Views/Pages/SummaryBoolRow.xaml
Normal file
@@ -0,0 +1,18 @@
|
||||
<UserControl x:Class="EngineeringSync.Setup.Views.Pages.SummaryBoolRow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Margin="0,2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="140"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock x:Name="LabelText" Grid.Column="0"
|
||||
FontFamily="Segoe UI" FontSize="12" Foreground="#5F5F5F"/>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<TextBlock x:Name="CheckIcon" FontFamily="Segoe MDL2 Assets" FontSize="11"
|
||||
Margin="0,0,6,0" VerticalAlignment="Center"/>
|
||||
<TextBlock x:Name="ValueText" FontFamily="Segoe UI" FontSize="12"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
40
EngineeringSync.Setup/Views/Pages/SummaryBoolRow.xaml.cs
Normal file
40
EngineeringSync.Setup/Views/Pages/SummaryBoolRow.xaml.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace EngineeringSync.Setup.Views.Pages;
|
||||
|
||||
public partial class SummaryBoolRow : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty LabelProperty =
|
||||
DependencyProperty.Register(nameof(Label), typeof(string), typeof(SummaryBoolRow),
|
||||
new PropertyMetadata(string.Empty, (d, e) => ((SummaryBoolRow)d).LabelText.Text = (string)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty ValueProperty =
|
||||
DependencyProperty.Register(nameof(Value), typeof(bool), typeof(SummaryBoolRow),
|
||||
new PropertyMetadata(false, (d, e) => ((SummaryBoolRow)d).UpdateVisual((bool)e.NewValue)));
|
||||
|
||||
public string Label { get => (string)GetValue(LabelProperty); set => SetValue(LabelProperty, value); }
|
||||
public bool Value { get => (bool)GetValue(ValueProperty); set => SetValue(ValueProperty, value); }
|
||||
|
||||
public SummaryBoolRow() => InitializeComponent();
|
||||
|
||||
private void UpdateVisual(bool isOn)
|
||||
{
|
||||
if (CheckIcon is null) return;
|
||||
if (isOn)
|
||||
{
|
||||
CheckIcon.Text = "\uE73E";
|
||||
CheckIcon.Foreground = new SolidColorBrush(Color.FromRgb(16, 124, 16));
|
||||
ValueText.Text = "Ja";
|
||||
ValueText.Foreground = new SolidColorBrush(Color.FromRgb(16, 124, 16));
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckIcon.Text = "\uE711";
|
||||
CheckIcon.Foreground = new SolidColorBrush(Color.FromRgb(160, 160, 160));
|
||||
ValueText.Text = "Nein";
|
||||
ValueText.Foreground = new SolidColorBrush(Color.FromRgb(160, 160, 160));
|
||||
}
|
||||
}
|
||||
}
|
||||
92
EngineeringSync.Setup/Views/Pages/SummaryPage.xaml
Normal file
92
EngineeringSync.Setup/Views/Pages/SummaryPage.xaml
Normal file
@@ -0,0 +1,92 @@
|
||||
<local:WizardPageBase x:Class="EngineeringSync.Setup.Views.Pages.SummaryPage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:EngineeringSync.Setup.Views.Pages"
|
||||
Background="White">
|
||||
<Grid Margin="40,32,40,24">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" Text="Zusammenfassung" Style="{StaticResource PageTitleStyle}"/>
|
||||
<TextBlock Grid.Row="1" Style="{StaticResource PageSubtitleStyle}"
|
||||
Text="Überprüfen Sie Ihre Einstellungen. Klicken Sie auf "Jetzt installieren" um die Installation zu starten."/>
|
||||
|
||||
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
|
||||
<StackPanel>
|
||||
|
||||
<!-- Installation -->
|
||||
<Border Style="{StaticResource InfoCardStyle}">
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="14"
|
||||
Foreground="#0078D4" Margin="0,0,8,0" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="Installation" FontFamily="Segoe UI" FontSize="13"
|
||||
FontWeight="SemiBold" Foreground="#1A1A1A" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<local:SummaryRow Label="Installationspfad" Value="{Binding InstallPath}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Erstes Projekt -->
|
||||
<Border Style="{StaticResource InfoCardStyle}">
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="14"
|
||||
Foreground="#0078D4" Margin="0,0,8,0" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="Erstes Projekt" FontFamily="Segoe UI" FontSize="13"
|
||||
FontWeight="SemiBold" Foreground="#1A1A1A" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<local:SummaryRow Label="Projektname" Value="{Binding ProjectName}"/>
|
||||
<local:SummaryRow Label="Engineering-Pfad" Value="{Binding EngineeringPath}"/>
|
||||
<local:SummaryRow Label="Simulations-Pfad" Value="{Binding SimulationPath}"/>
|
||||
<local:SummaryRow Label="Dateiendungen" Value="{Binding FileExtensions}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Backup -->
|
||||
<Border Style="{StaticResource InfoCardStyle}">
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="14"
|
||||
Foreground="#0078D4" Margin="0,0,8,0" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="Backup" FontFamily="Segoe UI" FontSize="13"
|
||||
FontWeight="SemiBold" Foreground="#1A1A1A" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<local:SummaryBoolRow Label="Backups aktiviert" Value="{Binding BackupEnabled}"/>
|
||||
<local:SummaryRow Label="Backup-Ordner"
|
||||
Value="{Binding BackupCustomPath}"
|
||||
Visibility="{Binding BackupUseCustomPath,
|
||||
Converter={StaticResource BoolToVisConverter}}"/>
|
||||
<!-- Aufbewahrung immer anzeigen wenn Backup aktiv (0 = unbegrenzt ist ein valider Wert) -->
|
||||
<local:SummaryRow Label="Max. Backups/Datei"
|
||||
Value="{Binding MaxBackupsPerFile,
|
||||
StringFormat='{}{0} (0=unbegrenzt)'}"
|
||||
Visibility="{Binding BackupEnabled,
|
||||
Converter={StaticResource BoolToVisConverter}}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Optionen -->
|
||||
<Border Style="{StaticResource InfoCardStyle}">
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal" Margin="0,0,0,10">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="14"
|
||||
Foreground="#0078D4" Margin="0,0,8,0" VerticalAlignment="Center"/>
|
||||
<TextBlock Text="Optionen" FontFamily="Segoe UI" FontSize="13"
|
||||
FontWeight="SemiBold" Foreground="#1A1A1A" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<local:SummaryBoolRow Label="Dienst automatisch starten" Value="{Binding AutoStartService}"/>
|
||||
<local:SummaryBoolRow Label="Tray-App bei Anmeldung" Value="{Binding AutoStartTrayApp}"/>
|
||||
<local:SummaryBoolRow Label="Desktop-Verknüpfung" Value="{Binding CreateDesktopShortcut}"/>
|
||||
<local:SummaryBoolRow Label="Startmenü-Eintrag" Value="{Binding CreateStartMenuEntry}"/>
|
||||
<local:SummaryBoolRow Label="Tray-App nach Installation" Value="{Binding StartAfterInstall}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</local:WizardPageBase>
|
||||
11
EngineeringSync.Setup/Views/Pages/SummaryPage.xaml.cs
Normal file
11
EngineeringSync.Setup/Views/Pages/SummaryPage.xaml.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using EngineeringSync.Setup.ViewModels;
|
||||
|
||||
namespace EngineeringSync.Setup.Views.Pages;
|
||||
|
||||
public partial class SummaryPage : WizardPageBase
|
||||
{
|
||||
public SummaryPage(WizardViewModel wizard) : base(wizard)
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
16
EngineeringSync.Setup/Views/Pages/SummaryRow.xaml
Normal file
16
EngineeringSync.Setup/Views/Pages/SummaryRow.xaml
Normal file
@@ -0,0 +1,16 @@
|
||||
<UserControl x:Class="EngineeringSync.Setup.Views.Pages.SummaryRow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Margin="0,2">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="140"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<TextBlock x:Name="LabelText" Grid.Column="0"
|
||||
FontFamily="Segoe UI" FontSize="12" Foreground="#5F5F5F"/>
|
||||
<TextBlock x:Name="ValueText" Grid.Column="1"
|
||||
FontFamily="Segoe UI" FontSize="12" Foreground="#1A1A1A"
|
||||
TextWrapping="Wrap"/>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
19
EngineeringSync.Setup/Views/Pages/SummaryRow.xaml.cs
Normal file
19
EngineeringSync.Setup/Views/Pages/SummaryRow.xaml.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace EngineeringSync.Setup.Views.Pages;
|
||||
|
||||
public partial class SummaryRow : UserControl
|
||||
{
|
||||
public static readonly DependencyProperty LabelProperty =
|
||||
DependencyProperty.Register(nameof(Label), typeof(string), typeof(SummaryRow),
|
||||
new PropertyMetadata(string.Empty, (d, e) => ((SummaryRow)d).LabelText.Text = (string)e.NewValue));
|
||||
|
||||
public static readonly DependencyProperty ValueProperty =
|
||||
DependencyProperty.Register(nameof(Value), typeof(string), typeof(SummaryRow),
|
||||
new PropertyMetadata(string.Empty, (d, e) => ((SummaryRow)d).ValueText.Text = (string)e.NewValue));
|
||||
|
||||
public string Label { get => (string)GetValue(LabelProperty); set => SetValue(LabelProperty, value); }
|
||||
public string Value { get => (string)GetValue(ValueProperty); set => SetValue(ValueProperty, value); }
|
||||
public SummaryRow() => InitializeComponent();
|
||||
}
|
||||
63
EngineeringSync.Setup/Views/Pages/WelcomePage.xaml
Normal file
63
EngineeringSync.Setup/Views/Pages/WelcomePage.xaml
Normal file
@@ -0,0 +1,63 @@
|
||||
<local:WizardPageBase x:Class="EngineeringSync.Setup.Views.Pages.WelcomePage"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="clr-namespace:EngineeringSync.Setup.Views.Pages"
|
||||
Background="White">
|
||||
<Grid Margin="40,32,40,24">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Großes Begrüßungs-Icon -->
|
||||
<Border Grid.Row="0" Width="64" Height="64" CornerRadius="16"
|
||||
HorizontalAlignment="Left" Margin="0,0,0,24">
|
||||
<Border.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
|
||||
<GradientStop Color="#0078D4" Offset="0"/>
|
||||
<GradientStop Color="#00B4FF" Offset="1"/>
|
||||
</LinearGradientBrush>
|
||||
</Border.Background>
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="32"
|
||||
Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
|
||||
<!-- Überschrift -->
|
||||
<StackPanel Grid.Row="1" Margin="0,0,0,20">
|
||||
<TextBlock Text="Willkommen bei EngineeringSync"
|
||||
Style="{StaticResource PageTitleStyle}"/>
|
||||
<TextBlock Style="{StaticResource PageSubtitleStyle}"
|
||||
Text="Dieser Assistent führt Sie durch die Installation und Erstkonfiguration von EngineeringSync – dem intelligenten Bindeglied zwischen Ihrem Engineering- und Simulationsumfeld."/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Feature-Liste -->
|
||||
<StackPanel Grid.Row="2" VerticalAlignment="Top">
|
||||
<TextBlock Text="Was wird installiert:"
|
||||
FontFamily="Segoe UI" FontSize="12" FontWeight="SemiBold"
|
||||
Foreground="#5F5F5F" Margin="0,0,0,12"/>
|
||||
|
||||
<local:FeatureRow Icon="" Title="EngineeringSync Service"
|
||||
Description="Windows-Dienst der Ihr Engineering-Verzeichnis überwacht und Änderungen protokolliert"/>
|
||||
<local:FeatureRow Icon="" Title="System Tray App"
|
||||
Description="Benachrichtigt Sie sofort über neue Änderungen und ermöglicht kontrollierten Sync"/>
|
||||
<local:FeatureRow Icon="" Title="Konfigurations-Wizard"
|
||||
Description="Verwalten Sie Projekte und Sync-Pfade bequem per grafischer Oberfläche"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- System-Check -->
|
||||
<Border Grid.Row="3" Background="#F0F7FF" CornerRadius="8" Padding="14,10" Margin="0,16,0,0">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="" FontFamily="Segoe MDL2 Assets" FontSize="14"
|
||||
Foreground="#0078D4" VerticalAlignment="Center" Margin="0,0,10,0"/>
|
||||
<TextBlock FontFamily="Segoe UI" FontSize="12" Foreground="#5F5F5F"
|
||||
VerticalAlignment="Center" TextWrapping="Wrap">
|
||||
<Run Text="Klicken Sie auf " FontWeight="Regular"/>
|
||||
<Run Text="Weiter" FontWeight="SemiBold"/>
|
||||
<Run Text=" um die Installation zu beginnen." FontWeight="Regular"/>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</local:WizardPageBase>
|
||||
11
EngineeringSync.Setup/Views/Pages/WelcomePage.xaml.cs
Normal file
11
EngineeringSync.Setup/Views/Pages/WelcomePage.xaml.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using EngineeringSync.Setup.ViewModels;
|
||||
|
||||
namespace EngineeringSync.Setup.Views.Pages;
|
||||
|
||||
public partial class WelcomePage : WizardPageBase
|
||||
{
|
||||
public WelcomePage(WizardViewModel wizard) : base(wizard)
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
25
EngineeringSync.Setup/Views/Pages/WizardPageBase.cs
Normal file
25
EngineeringSync.Setup/Views/Pages/WizardPageBase.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Windows.Controls;
|
||||
using EngineeringSync.Setup.ViewModels;
|
||||
|
||||
namespace EngineeringSync.Setup.Views.Pages;
|
||||
|
||||
/// <summary>
|
||||
/// Basisklasse für alle Wizard-Seiten.
|
||||
/// Stellt gemeinsame WizardViewModel-Referenz und Validierungsschnittstelle bereit.
|
||||
/// </summary>
|
||||
public abstract class WizardPageBase : UserControl
|
||||
{
|
||||
protected WizardViewModel Wizard { get; }
|
||||
|
||||
protected WizardPageBase(WizardViewModel wizard)
|
||||
{
|
||||
Wizard = wizard;
|
||||
DataContext = wizard.State;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Wird vor dem Vorwärtsnavigieren aufgerufen.
|
||||
/// Gibt false zurück um die Navigation zu blockieren (z.B. Validierungsfehler).
|
||||
/// </summary>
|
||||
public virtual bool Validate() => true;
|
||||
}
|
||||
251
EngineeringSync.Setup/Views/WizardWindow.xaml
Normal file
251
EngineeringSync.Setup/Views/WizardWindow.xaml
Normal file
@@ -0,0 +1,251 @@
|
||||
<Window x:Class="EngineeringSync.Setup.Views.WizardWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:vm="clr-namespace:EngineeringSync.Setup.ViewModels"
|
||||
Title="EngineeringSync Setup"
|
||||
Width="860" Height="580"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
ResizeMode="NoResize"
|
||||
WindowStyle="None"
|
||||
AllowsTransparency="True"
|
||||
Background="Transparent">
|
||||
|
||||
<Window.DataContext>
|
||||
<vm:WizardViewModel/>
|
||||
</Window.DataContext>
|
||||
|
||||
<!-- Äußerer Schatten-Container -->
|
||||
<Border CornerRadius="10"
|
||||
Background="White">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect Color="#40000000" BlurRadius="30" ShadowDepth="0" Opacity="0.4"/>
|
||||
</Border.Effect>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="260"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- ═══════════════════════════════
|
||||
LINKE SIDEBAR
|
||||
═══════════════════════════════ -->
|
||||
<Border Grid.Column="0"
|
||||
Background="{StaticResource SidebarGradient}"
|
||||
CornerRadius="10,0,0,10">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Logo-Bereich -->
|
||||
<StackPanel Grid.Row="0" Margin="24,32,24,32">
|
||||
<!-- App-Icon (Segoe MDL2 Gear-ähnliches Symbol) -->
|
||||
<Border Width="52" Height="52"
|
||||
CornerRadius="12"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="0,0,0,16">
|
||||
<Border.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
|
||||
<GradientStop Color="#0078D4" Offset="0"/>
|
||||
<GradientStop Color="#00B4FF" Offset="1"/>
|
||||
</LinearGradientBrush>
|
||||
</Border.Background>
|
||||
<TextBlock Text=""
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="26"
|
||||
Foreground="White"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
|
||||
<TextBlock Text="EngineeringSync"
|
||||
FontFamily="Segoe UI"
|
||||
FontSize="16"
|
||||
FontWeight="SemiBold"
|
||||
Foreground="White"/>
|
||||
<TextBlock Text="Setup-Assistent"
|
||||
FontFamily="Segoe UI"
|
||||
FontSize="11"
|
||||
Foreground="#7788AA"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Schritt-Indikatoren -->
|
||||
<ItemsControl Grid.Row="1"
|
||||
ItemsSource="{Binding Steps}"
|
||||
Margin="20,0,20,0">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl Style="{StaticResource StepItemStyle}"
|
||||
Content="{Binding}"/>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<!-- Version -->
|
||||
<TextBlock Grid.Row="2"
|
||||
Text="Version 1.0.0"
|
||||
FontFamily="Segoe UI"
|
||||
FontSize="10"
|
||||
Foreground="#445566"
|
||||
Margin="24,0,24,20"
|
||||
HorizontalAlignment="Left"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ═══════════════════════════════
|
||||
RECHTE INHALTSSEITE + NAVIGATION
|
||||
═══════════════════════════════ -->
|
||||
<Grid Grid.Column="1">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/> <!-- Custom Title Bar -->
|
||||
<RowDefinition Height="*"/> <!-- Page Content -->
|
||||
<RowDefinition Height="Auto"/> <!-- Navigation Bar -->
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Custom Title Bar (Drag + Schließen) -->
|
||||
<Border Grid.Row="0"
|
||||
Height="40"
|
||||
CornerRadius="0,10,0,0"
|
||||
MouseLeftButtonDown="TitleBar_MouseDown">
|
||||
<Grid>
|
||||
<TextBlock Text="EngineeringSync Setup"
|
||||
FontFamily="Segoe UI"
|
||||
FontSize="12"
|
||||
Foreground="#888888"
|
||||
VerticalAlignment="Center"
|
||||
Margin="16,0,0,0"/>
|
||||
<Button Content=""
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
FontSize="12"
|
||||
HorizontalAlignment="Right"
|
||||
VerticalAlignment="Center"
|
||||
Width="40" Height="40"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
Foreground="#888888"
|
||||
Cursor="Hand"
|
||||
Click="CloseButton_Click"
|
||||
ToolTip="Schließen">
|
||||
<Button.Style>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Border x:Name="bg"
|
||||
Background="Transparent"
|
||||
CornerRadius="0,10,0,0">
|
||||
<ContentPresenter HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="bg" Property="Background" Value="#FFE81123"/>
|
||||
<Setter Property="Foreground" Value="White"/>
|
||||
</Trigger>
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Button.Style>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- ── Separator ── -->
|
||||
<Border Grid.Row="0" Height="1" Background="{StaticResource BorderBrush}"
|
||||
VerticalAlignment="Bottom"/>
|
||||
|
||||
<!-- Seiten-Content mit Animation -->
|
||||
<ContentPresenter Grid.Row="1"
|
||||
Content="{Binding CurrentPage}"
|
||||
Margin="0"/>
|
||||
|
||||
<!-- ── Separator ── -->
|
||||
<Border Grid.Row="2" Height="1" Background="{StaticResource BorderBrush}"
|
||||
VerticalAlignment="Top"/>
|
||||
|
||||
<!-- Navigation Bar -->
|
||||
<Border Grid.Row="2"
|
||||
Background="#FAFAFA"
|
||||
CornerRadius="0,0,10,0"
|
||||
Padding="24,12">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Abbrechen (links) -->
|
||||
<Button Grid.Column="0"
|
||||
Content="Abbrechen"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Command="{Binding CancelCommand}"
|
||||
Visibility="{Binding IsCompleted,
|
||||
Converter={StaticResource BoolToInvVisConverter}}"/>
|
||||
|
||||
<!-- Zurück -->
|
||||
<Button Grid.Column="1"
|
||||
Style="{StaticResource SecondaryButtonStyle}"
|
||||
Margin="0,0,8,0"
|
||||
Command="{Binding GoBackCommand}"
|
||||
Visibility="{Binding CanGoBack,
|
||||
Converter={StaticResource BoolToVisConverter}}">
|
||||
<Button.Content>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text=""
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Margin="0,0,6,0"/>
|
||||
<TextBlock Text="Zurück"
|
||||
FontFamily="Segoe UI"/>
|
||||
</StackPanel>
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<!-- Weiter / Installieren -->
|
||||
<Button Grid.Column="2"
|
||||
Style="{StaticResource PrimaryButtonStyle}"
|
||||
Command="{Binding GoNextCommand}"
|
||||
Visibility="{Binding ShowNextButton,
|
||||
Converter={StaticResource BoolToVisConverter}}">
|
||||
<Button.Content>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock x:Name="nextLabel"
|
||||
Text="{Binding IsLastStep,
|
||||
Converter={StaticResource LastStepLabelConverter}}"/>
|
||||
<TextBlock Text=" "
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Visibility="{Binding IsLastStep,
|
||||
Converter={StaticResource BoolToInvVisConverter}}"/>
|
||||
</StackPanel>
|
||||
</Button.Content>
|
||||
</Button>
|
||||
|
||||
<!-- Fertig-Button -->
|
||||
<Button Grid.Column="3"
|
||||
Style="{StaticResource PrimaryButtonStyle}"
|
||||
Command="{Binding FinishCommand}"
|
||||
Visibility="{Binding IsCompleted,
|
||||
Converter={StaticResource BoolToVisConverter}}">
|
||||
<Button.Content>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text=""
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
Margin="0,0,6,0"/>
|
||||
<TextBlock Text="Schließen"
|
||||
FontFamily="Segoe UI"/>
|
||||
</StackPanel>
|
||||
</Button.Content>
|
||||
</Button>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Window>
|
||||
24
EngineeringSync.Setup/Views/WizardWindow.xaml.cs
Normal file
24
EngineeringSync.Setup/Views/WizardWindow.xaml.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace EngineeringSync.Setup.Views;
|
||||
|
||||
public partial class WizardWindow : Window
|
||||
{
|
||||
public WizardWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void TitleBar_MouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.ChangedButton == MouseButton.Left)
|
||||
DragMove();
|
||||
}
|
||||
|
||||
private void CloseButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var vm = (ViewModels.WizardViewModel)DataContext;
|
||||
vm.CancelCommand.Execute(null);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user