[feat:] first project version
This commit is contained in:
@@ -7,4 +7,8 @@
|
||||
<Application.Styles>
|
||||
<FluentTheme />
|
||||
</Application.Styles>
|
||||
<Application.Resources>
|
||||
<x:Double x:Key="DatePickerThemeMinWidth">10</x:Double>
|
||||
<x:Double x:Key="DatePickerThemeMaxWidth">1000</x:Double>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
7
Backup.cs
Normal file
7
Backup.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
20
Exam.cs
Normal file
20
Exam.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace PLG_Exam
|
||||
{
|
||||
public class Exam
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Vorname { get; set; } = string.Empty;
|
||||
public DateTime? Datum { get; set; }
|
||||
public List<ExamTab> Tabs { get; set; } = new();
|
||||
}
|
||||
|
||||
public class ExamTab
|
||||
{
|
||||
public string Aufgabennummer { get; set; } = string.Empty;
|
||||
public string Überschrift { get; set; } = string.Empty;
|
||||
public string Inhalt { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,49 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="PLG_Exam.MainWindow"
|
||||
Title="PLG_Exam">
|
||||
Welcome to Avalonia!
|
||||
Title="PLG Exam">
|
||||
<DockPanel Margin="10">
|
||||
<!-- Unterer Teil: Dateiverwaltung -->
|
||||
<Border DockPanel.Dock="Bottom" Background="#232327" Margin="0,10,0,0">
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="10" VerticalAlignment="Center" Spacing="10">
|
||||
<Button Content="Speichern" Click="OnSaveClick" />
|
||||
<Button Content="Speichern unter..." Click="OnSaveAsClick" />
|
||||
<Button Content="Öffnen" Click="OnOpenClick" />
|
||||
<Button Content="Neu" Click="OnNewClick" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Oberer Teil: Name, Vorname, Datum -->
|
||||
<Border DockPanel.Dock="Top" Background="#232327" Height="100" Margin="0,0,0,10">
|
||||
<Grid Margin="10">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="350" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0" Margin="5" Spacing="5">
|
||||
<TextBlock Text="Name" FontWeight="Bold" Foreground="White" />
|
||||
<TextBox Name="NameField" Height="33"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="1" Margin="5" Spacing="5">
|
||||
<TextBlock Text="Vorname" FontWeight="Bold" Foreground="White" />
|
||||
<TextBox Name="VornameField" Height="33"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2" Margin="5" Spacing="5">
|
||||
<TextBlock Text="Datum" HorizontalAlignment="Stretch" FontWeight="Bold" Foreground="White" />
|
||||
<DatePicker Name="DatumField" Width="340" Height="33" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Mittlerer Teil: Tabansicht -->
|
||||
<Border Background="#232327" Margin="0,0,0,0">
|
||||
<DockPanel>
|
||||
<Button Content="Weitere Aufgabenlösung hinzufügen" DockPanel.Dock="Top" HorizontalAlignment="Center" Margin="10,10,10,0" Click="OnAddTabClick" />
|
||||
<TabControl Name="TabView" Margin="10">
|
||||
|
||||
</TabControl>
|
||||
</DockPanel>
|
||||
</Border>
|
||||
</DockPanel>
|
||||
</Window>
|
||||
|
||||
@@ -1,11 +1,515 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Media;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace PLG_Exam;
|
||||
|
||||
public partial class MainWindow : Window
|
||||
namespace PLG_Exam
|
||||
{
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
private int _tabCounter = 0;
|
||||
private bool _isSaved = true;
|
||||
private string? _currentFilePath;
|
||||
public static Exam _currentExam = new();
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
InitializeBackupTimer();
|
||||
AddNewTab();
|
||||
|
||||
this.KeyDown += OnKeyDown;
|
||||
}
|
||||
|
||||
// Event für "Neuen Tab hinzufügen"
|
||||
private void OnAddTabClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
AddNewTab();
|
||||
}
|
||||
|
||||
private async void OnKeyDown(object? sender, Avalonia.Input.KeyEventArgs e)
|
||||
{
|
||||
if (e.KeyModifiers.HasFlag(Avalonia.Input.KeyModifiers.Control))
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
case Avalonia.Input.Key.S:
|
||||
if (e.KeyModifiers.HasFlag(Avalonia.Input.KeyModifiers.Shift))
|
||||
{
|
||||
// Strg + Shift + S: Speichern Unter
|
||||
OnSaveAsClick(sender, e);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Strg + S: Speichern
|
||||
OnSaveClick(sender, e);
|
||||
}
|
||||
break;
|
||||
|
||||
case Avalonia.Input.Key.O:
|
||||
// Strg + O: Öffnen
|
||||
OnOpenClick(sender, e);
|
||||
break;
|
||||
|
||||
case Avalonia.Input.Key.T:
|
||||
// Strg + T: Neuer Tab
|
||||
OnAddTabClick(sender, e);
|
||||
break;
|
||||
|
||||
case Avalonia.Input.Key.N:
|
||||
// Strg + N: Neu
|
||||
OnNewClick(sender, e);
|
||||
break;
|
||||
|
||||
case Avalonia.Input.Key.R:
|
||||
// Strg + R: Abgeben (coming soon)
|
||||
await OnSubmitClick(sender, e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnSubmitClick(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
|
||||
{
|
||||
await MessageBox.Show(this, "Abgeben-Funktion wird bald verfügbar sein!", "Abgeben", MessageBoxButton.Ok);
|
||||
}
|
||||
|
||||
|
||||
private void AddNewTab()
|
||||
{
|
||||
_tabCounter++;
|
||||
|
||||
var closeButton = new Button
|
||||
{
|
||||
Content = "×",
|
||||
FontSize = 14,
|
||||
HorizontalContentAlignment = Avalonia.Layout.HorizontalAlignment.Center,
|
||||
VerticalContentAlignment = Avalonia.Layout.VerticalAlignment.Center,
|
||||
Width = 20,
|
||||
Height = 20,
|
||||
Background = new SolidColorBrush(Color.FromRgb(123,35,39)),
|
||||
Foreground = new SolidColorBrush(Color.FromRgb(0,0,0)),
|
||||
Padding = new Thickness(0),
|
||||
Margin = new Thickness(5, 0, 0, 0),
|
||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center
|
||||
};
|
||||
|
||||
ToolTip.SetTip(closeButton, "Tab schließen");
|
||||
|
||||
var headerStackPanel = new StackPanel
|
||||
{
|
||||
Orientation = Avalonia.Layout.Orientation.Horizontal
|
||||
};
|
||||
|
||||
var tabHeader = new TextBlock
|
||||
{
|
||||
Text = $"{_tabCounter} - Neu",
|
||||
VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center
|
||||
};
|
||||
|
||||
headerStackPanel.Children.Add(tabHeader);
|
||||
headerStackPanel.Children.Add(closeButton);
|
||||
|
||||
var tabItem = new TabItem
|
||||
{
|
||||
Header = headerStackPanel,
|
||||
Content = CreateTabContent()
|
||||
};
|
||||
|
||||
// Schließen-Event hinzufügen
|
||||
closeButton.Click += async (sender, e) =>
|
||||
{
|
||||
var result = await MessageBox.Show(this, "Diese Aktion schließt die Aufgabe unwiderruflich. Möchten Sie fortfahren?",
|
||||
"Tab schließen", MessageBoxButton.YesNo);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
TabView.Items.Remove(tabItem);
|
||||
_isSaved = false;
|
||||
}
|
||||
};
|
||||
|
||||
TabView.Items.Add(tabItem);
|
||||
TabView.SelectedItem = tabItem;
|
||||
_isSaved = false;
|
||||
}
|
||||
|
||||
|
||||
// Tab entfernen mit Sicherheitsabfrage
|
||||
private async void OnRemoveTabClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (TabView.SelectedItem is TabItem selectedTab)
|
||||
{
|
||||
var result = await MessageBox.Show(this, "Dieser Tab wird unwiderruflich gelöscht. Möchten Sie fortfahren?",
|
||||
"Tab löschen", MessageBoxButton.YesNo);
|
||||
if (result == MessageBoxResult.Yes)
|
||||
{
|
||||
TabView.Items.Remove(selectedTab);
|
||||
_isSaved = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Speichern
|
||||
private async void OnSaveClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_currentFilePath))
|
||||
{
|
||||
await SaveAs();
|
||||
}
|
||||
else
|
||||
{
|
||||
SaveToFile(_currentFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
private async void OnSaveAsClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
await SaveAs();
|
||||
}
|
||||
|
||||
private async Task<bool> SaveAs()
|
||||
{
|
||||
var saveDialog = new SaveFileDialog
|
||||
{
|
||||
DefaultExtension = "exam",
|
||||
Filters = { new FileDialogFilter { Name = "Exam files", Extensions = { "exam" } } }
|
||||
};
|
||||
var filePath = await saveDialog.ShowAsync(this);
|
||||
|
||||
if (!string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
SaveToFile(filePath);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveToFile(string filePath)
|
||||
{
|
||||
// Update Exam-Daten
|
||||
_currentExam.Name = NameField.Text;
|
||||
_currentExam.Vorname = VornameField.Text;
|
||||
_currentExam.Datum = DatumField.SelectedDate?.UtcDateTime;
|
||||
_currentExam.Tabs = TabView.Items.OfType<TabItem>()
|
||||
.Select(tab =>
|
||||
{
|
||||
var grid = tab.Content as Grid;
|
||||
if (grid == null) return null;
|
||||
|
||||
var aufgabennummer = (grid.Children[0] as Grid)?.Children[0] as TextBox;
|
||||
var ueberschrift = (grid.Children[0] as Grid)?.Children[1] as TextBox;
|
||||
var beschreibung = grid.Children[1] as TextBox;
|
||||
|
||||
return new ExamTab
|
||||
{
|
||||
Aufgabennummer = aufgabennummer?.Text ?? "",
|
||||
Überschrift = ueberschrift?.Text ?? "",
|
||||
Inhalt = beschreibung?.Text ?? ""
|
||||
};
|
||||
})
|
||||
.Where(tab => tab != null)
|
||||
.ToList();
|
||||
|
||||
var json = JsonSerializer.Serialize(_currentExam, new JsonSerializerOptions { WriteIndented = true });
|
||||
File.WriteAllText(filePath, json);
|
||||
|
||||
_currentFilePath = filePath;
|
||||
_isSaved = true;
|
||||
}
|
||||
|
||||
// Öffnen
|
||||
private async void OnOpenClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
var openDialog = new OpenFileDialog
|
||||
{
|
||||
AllowMultiple = false,
|
||||
Filters = { new FileDialogFilter { Name = "Exam files", Extensions = { "exam" } } }
|
||||
};
|
||||
var result = await openDialog.ShowAsync(this);
|
||||
|
||||
if (result != null && result.Length > 0)
|
||||
{
|
||||
LoadFromFile(result[0]);
|
||||
}
|
||||
}
|
||||
|
||||
private void LoadFromFile(string filePath)
|
||||
{
|
||||
var fileContent = File.ReadAllText(filePath);
|
||||
var exam = JsonSerializer.Deserialize<Exam>(fileContent);
|
||||
|
||||
if (exam == null) return;
|
||||
|
||||
// Daten wiederherstellen
|
||||
_currentExam = exam;
|
||||
NameField.Text = exam.Name;
|
||||
VornameField.Text = exam.Vorname;
|
||||
DatumField.SelectedDate = exam.Datum;
|
||||
|
||||
TabView.Items.Clear();
|
||||
_tabCounter = 0;
|
||||
|
||||
foreach (var tab in exam.Tabs)
|
||||
{
|
||||
_tabCounter++;
|
||||
var tabItem = new TabItem
|
||||
{
|
||||
Header = $"{tab.Aufgabennummer} - {tab.Überschrift}",
|
||||
Content = CreateTabContent(tab.Aufgabennummer, tab.Überschrift, tab.Inhalt)
|
||||
};
|
||||
TabView.Items.Add(tabItem);
|
||||
}
|
||||
|
||||
_currentFilePath = filePath;
|
||||
_isSaved = true;
|
||||
}
|
||||
|
||||
// Neu
|
||||
private async void OnNewClick(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!_isSaved)
|
||||
{
|
||||
var result = await MessageBox.Show(this, "Möchten Sie die aktuellen Änderungen speichern?",
|
||||
"Nicht gespeicherte Änderungen", MessageBoxButton.YesNoCancel);
|
||||
if (result == MessageBoxResult.Cancel) return;
|
||||
if (result == MessageBoxResult.Yes) {
|
||||
if((await SaveAs()) != true){
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_currentExam = new Exam();
|
||||
NameField.Text = "";
|
||||
VornameField.Text = "";
|
||||
DatumField.SelectedDate = null;
|
||||
TabView.Items.Clear();
|
||||
_tabCounter = 0;
|
||||
_currentFilePath = null;
|
||||
_isSaved = true;
|
||||
}
|
||||
|
||||
private Grid CreateTabContent(string? aufgabennummer = null, string? ueberschrift = null, string? beschreibung = null)
|
||||
{
|
||||
var grid = new Grid();
|
||||
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(33) });
|
||||
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
|
||||
|
||||
var headerGrid = new Grid { Margin = new Thickness(0, 0, 0, 10) };
|
||||
headerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(250) });
|
||||
headerGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
|
||||
|
||||
var aufgabenNummerTextBox = new TextBox
|
||||
{
|
||||
Name = "Aufgabennummer",
|
||||
Watermark = "Aufgabennummer",
|
||||
Margin = new Thickness(0,10,0,0),
|
||||
Text = aufgabennummer ?? ""
|
||||
};
|
||||
|
||||
var ueberschriftTextBox = new TextBox
|
||||
{
|
||||
Name = "Überschrift",
|
||||
Watermark = "Überschrift (optional)",
|
||||
Margin = new Thickness(10,10,0,0),
|
||||
Text = ueberschrift ?? ""
|
||||
};
|
||||
|
||||
var beschreibungTextBox = new TextBox
|
||||
{
|
||||
Name = "Beschreibung",
|
||||
AcceptsReturn = true,
|
||||
VerticalContentAlignment = Avalonia.Layout.VerticalAlignment.Stretch,
|
||||
Watermark = "Beschreibung",
|
||||
Text = beschreibung ?? "",
|
||||
};
|
||||
|
||||
// Event für dynamische Tab-Umbenennung
|
||||
aufgabenNummerTextBox.KeyUp += (s, e) => UpdateTabHeader(TabView.SelectedItem as TabItem, aufgabenNummerTextBox, ueberschriftTextBox);
|
||||
ueberschriftTextBox.KeyUp += (s, e) => UpdateTabHeader(TabView.SelectedItem as TabItem, aufgabenNummerTextBox, ueberschriftTextBox);
|
||||
|
||||
headerGrid.Children.Add(aufgabenNummerTextBox);
|
||||
headerGrid.Children.Add(ueberschriftTextBox);
|
||||
Grid.SetColumn(aufgabenNummerTextBox, 0);
|
||||
Grid.SetColumn(ueberschriftTextBox, 1);
|
||||
|
||||
grid.Children.Add(headerGrid);
|
||||
grid.Children.Add(beschreibungTextBox);
|
||||
Grid.SetRow(headerGrid, 0);
|
||||
Grid.SetRow(beschreibungTextBox, 1);
|
||||
|
||||
return grid;
|
||||
}
|
||||
|
||||
private void UpdateTabHeader(TabItem? tab, TextBox aufgabennummer, TextBox ueberschrift)
|
||||
{
|
||||
if (tab == null) return;
|
||||
|
||||
var aufgabeText = string.IsNullOrWhiteSpace(aufgabennummer.Text) ? "Neu" : aufgabennummer.Text;
|
||||
var ueberschriftText = string.IsNullOrWhiteSpace(ueberschrift.Text) ? "" : ueberschrift.Text;
|
||||
|
||||
tab.Header = string.IsNullOrWhiteSpace(ueberschriftText)
|
||||
? aufgabeText
|
||||
: $"{aufgabeText} - {ueberschriftText}";
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Backups
|
||||
//
|
||||
|
||||
private const int BackupInterval = 20000; // 20 Sekunden in Millisekunden
|
||||
|
||||
|
||||
private DispatcherTimer _backupTimer;
|
||||
|
||||
private void InitializeBackupTimer()
|
||||
{
|
||||
_backupTimer = new DispatcherTimer
|
||||
{
|
||||
Interval = TimeSpan.FromSeconds(20)
|
||||
};
|
||||
_backupTimer.Tick += (sender, e) => CreateBackup();
|
||||
_backupTimer.Start();
|
||||
}
|
||||
|
||||
private const int MaxBackupFiles = 5; // Maximal 5 Backups
|
||||
private readonly string BackupFolderPath = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
||||
"PLG_Exam_Backup");
|
||||
|
||||
|
||||
|
||||
// Backup erstellen
|
||||
private void CreateBackup()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Ordner erstellen, falls nicht vorhanden
|
||||
if (!Directory.Exists(BackupFolderPath))
|
||||
{
|
||||
Directory.CreateDirectory(BackupFolderPath);
|
||||
}
|
||||
|
||||
// Erstelle Dateinamen mit Zeitstempel
|
||||
var timestamp = DateTime.Now.ToString("yyMMdd_HHmmss");
|
||||
var backupFileName = Path.Combine(BackupFolderPath, $"{timestamp}_backup.exam");
|
||||
|
||||
// Aktuelle Daten in JSON-Format speichern
|
||||
var jsonData = GetCurrentExamDataAsJson();
|
||||
File.WriteAllText(backupFileName, jsonData);
|
||||
|
||||
// Alte Backups löschen, wenn mehr als MaxBackupFiles vorhanden sind
|
||||
CleanupOldBackups();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Backup konnte nicht erstellt werden: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// Löscht alte Backups, wenn die maximale Anzahl überschritten wird
|
||||
private void CleanupOldBackups()
|
||||
{
|
||||
var backupFiles = Directory.GetFiles(BackupFolderPath, "*_backup.exam")
|
||||
.OrderBy(File.GetCreationTime)
|
||||
.ToList();
|
||||
|
||||
while (backupFiles.Count > MaxBackupFiles)
|
||||
{
|
||||
var oldestFile = backupFiles.First();
|
||||
File.Delete(oldestFile);
|
||||
backupFiles.RemoveAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Löscht alle Backups unwiderruflich (mit Überschreiben)
|
||||
private void DeleteAllBackups()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (Directory.Exists(BackupFolderPath))
|
||||
{
|
||||
foreach (var file in Directory.GetFiles(BackupFolderPath, "*_backup.exam"))
|
||||
{
|
||||
OverwriteAndDeleteFile(file);
|
||||
}
|
||||
Directory.Delete(BackupFolderPath, true);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Backups konnten nicht gelöscht werden: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// Überschreibt eine Datei mit Zufallsdaten und löscht sie anschließend
|
||||
private void OverwriteAndDeleteFile(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(filePath)) return;
|
||||
|
||||
var fileLength = new FileInfo(filePath).Length;
|
||||
|
||||
// Datei mit Zufallsdaten überschreiben
|
||||
using (var stream = new FileStream(filePath, FileMode.Open))
|
||||
{
|
||||
var randomData = new byte[fileLength];
|
||||
new Random().NextBytes(randomData);
|
||||
stream.Write(randomData, 0, randomData.Length);
|
||||
}
|
||||
|
||||
// Datei löschen
|
||||
File.Delete(filePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Datei konnte nicht überschrieben und gelöscht werden: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// Holt die aktuelle Exam-Daten als JSON
|
||||
private string GetCurrentExamDataAsJson()
|
||||
{
|
||||
_currentExam.Name = NameField.Text;
|
||||
_currentExam.Vorname = VornameField.Text;
|
||||
_currentExam.Datum = DatumField.SelectedDate?.UtcDateTime;
|
||||
|
||||
_currentExam.Tabs = TabView.Items.OfType<TabItem>()
|
||||
.Select(tab =>
|
||||
{
|
||||
var grid = tab.Content as Grid;
|
||||
if (grid == null) return null;
|
||||
|
||||
var aufgabennummer = (grid.Children[0] as Grid)?.Children[0] as TextBox;
|
||||
var ueberschrift = (grid.Children[0] as Grid)?.Children[1] as TextBox;
|
||||
var beschreibung = grid.Children[1] as TextBox;
|
||||
|
||||
return new ExamTab
|
||||
{
|
||||
Aufgabennummer = aufgabennummer?.Text ?? "",
|
||||
Überschrift = ueberschrift?.Text ?? "",
|
||||
Inhalt = beschreibung?.Text ?? ""
|
||||
};
|
||||
})
|
||||
.Where(tab => tab != null)
|
||||
.ToList();
|
||||
|
||||
return System.Text.Json.JsonSerializer.Serialize(_currentExam, new System.Text.Json.JsonSerializerOptions { WriteIndented = true });
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
18
MessageBox.axaml
Normal file
18
MessageBox.axaml
Normal file
@@ -0,0 +1,18 @@
|
||||
<Window xmlns="https://github.com/avaloniaui"
|
||||
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" SizeToContent="WidthAndHeight"
|
||||
x:Class="PLG_Exam.MessageBox"
|
||||
Title="MessageBox">
|
||||
<StackPanel>
|
||||
<TextBlock Name="Text" Margin="10" TextWrapping="Wrap"/>
|
||||
<StackPanel HorizontalAlignment="Right" Margin="5" Orientation="Horizontal" Name="Buttons">
|
||||
<StackPanel.Styles>
|
||||
<Style Selector="Button">
|
||||
<Setter Property="Margin" Value="5"/>
|
||||
</Style>
|
||||
</StackPanel.Styles>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Window>
|
||||
76
MessageBox.axaml.cs
Normal file
76
MessageBox.axaml.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PLG_Exam;
|
||||
|
||||
public partial class MessageBox : Window
|
||||
{
|
||||
public MessageBox()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
public static Task<MessageBoxResult> Show(Window? parent, string text, string title, MessageBoxButton buttons = MessageBoxButton.Ok)
|
||||
{
|
||||
var msgbox = new MessageBox()
|
||||
{
|
||||
Title = title
|
||||
};
|
||||
var tb = msgbox.FindControl<TextBlock>("Text");
|
||||
if(tb != null) tb.Text = text;
|
||||
var buttonPanel = msgbox.FindControl<StackPanel>("Buttons");
|
||||
|
||||
var res = MessageBoxResult.Ok;
|
||||
|
||||
void AddButton(string caption, MessageBoxResult r, bool def = false)
|
||||
{
|
||||
var btn = new Button { Content = caption };
|
||||
btn.Click += (_, __) =>
|
||||
{
|
||||
res = r;
|
||||
msgbox.Close();
|
||||
};
|
||||
if(buttonPanel == null) return;
|
||||
buttonPanel.Children.Add(btn);
|
||||
if (def)
|
||||
res = r;
|
||||
}
|
||||
|
||||
if (buttons == MessageBoxButton.Ok || buttons == MessageBoxButton.OkCancel)
|
||||
AddButton("Ok", MessageBoxResult.Ok, true);
|
||||
if (buttons == MessageBoxButton.YesNo || buttons == MessageBoxButton.YesNoCancel)
|
||||
{
|
||||
AddButton("Yes", MessageBoxResult.Yes);
|
||||
AddButton("No", MessageBoxResult.No, true);
|
||||
}
|
||||
|
||||
if (buttons == MessageBoxButton.OkCancel || buttons == MessageBoxButton.YesNoCancel)
|
||||
AddButton("Cancel", MessageBoxResult.Cancel, true);
|
||||
|
||||
|
||||
|
||||
var tcs = new TaskCompletionSource<MessageBoxResult>();
|
||||
msgbox.Closed += delegate { tcs.TrySetResult(res); };
|
||||
if (parent != null)
|
||||
msgbox.ShowDialog(parent);
|
||||
else msgbox.Show();
|
||||
return tcs.Task;
|
||||
}
|
||||
}
|
||||
public enum MessageBoxButton
|
||||
{
|
||||
Ok,
|
||||
OkCancel,
|
||||
YesNo,
|
||||
YesNoCancel
|
||||
}
|
||||
|
||||
public enum MessageBoxResult
|
||||
{
|
||||
Ok,
|
||||
Cancel,
|
||||
Yes,
|
||||
No
|
||||
}
|
||||
25
PLG-Exam.sln
Normal file
25
PLG-Exam.sln
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.5.002.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PLG-Exam", "PLG-Exam.csproj", "{F120D7C1-1272-40DA-9CBB-0EE2DC779632}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{F120D7C1-1272-40DA-9CBB-0EE2DC779632}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F120D7C1-1272-40DA-9CBB-0EE2DC779632}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F120D7C1-1272-40DA-9CBB-0EE2DC779632}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F120D7C1-1272-40DA-9CBB-0EE2DC779632}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {357C5A9A-CDAF-4061-ABC2-8F768DA586D2}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
Reference in New Issue
Block a user