From 8bf09d9088cbcb0fdf9cb3238e4734842e02fcd0 Mon Sep 17 00:00:00 2001 From: Nexusls <luis.sander@edu.bib.de> Date: Wed, 9 Apr 2025 10:00:17 +0200 Subject: [PATCH] Add: SearchWindow with Id and string search --- PrototypWPFHAG/Images/pdf-icon.png | Bin 0 -> 10565 bytes PrototypWPFHAG/MainWindow.xaml.cs | 4 +- PrototypWPFHAG/PdfServiceClient.cs | 52 ++++ PrototypWPFHAG/PrototypWPFHAG.csproj | 5 + PrototypWPFHAG/SearchWindow.xaml | 211 ++++++++++++--- PrototypWPFHAG/SearchWindow.xaml.cs | 385 ++++++++++++++++++++++++++- 6 files changed, 606 insertions(+), 51 deletions(-) create mode 100644 PrototypWPFHAG/Images/pdf-icon.png create mode 100644 PrototypWPFHAG/PdfServiceClient.cs diff --git a/PrototypWPFHAG/Images/pdf-icon.png b/PrototypWPFHAG/Images/pdf-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..476c5b5befd5a77a027207007f382832d80e5c48 GIT binary patch literal 10565 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 CR1CcU literal 0 HcmV?d00001 diff --git a/PrototypWPFHAG/MainWindow.xaml.cs b/PrototypWPFHAG/MainWindow.xaml.cs index 17895b2..4365c5e 100644 --- a/PrototypWPFHAG/MainWindow.xaml.cs +++ b/PrototypWPFHAG/MainWindow.xaml.cs @@ -42,7 +42,7 @@ public partial class MainWindow : MetroWindow con.Open(); // Check for correct UserName - string userQuery = "SELECT COUNT(*) FROM \"User\" WHERE \"UserName\" = @username"; + string userQuery = "SELECT COUNT(*) FROM \"users\" WHERE \"username\" = @username"; using (NpgsqlCommand userCmd = new NpgsqlCommand(userQuery, con)) { userCmd.Parameters.AddWithValue("@username", username); @@ -55,7 +55,7 @@ public partial class MainWindow : MetroWindow } // Check for correct Password - string pwQuery = "SELECT COUNT(*) FROM \"User\" WHERE \"UserName\" = @username AND \"Password\" = @password"; + string pwQuery = "SELECT COUNT(*) FROM \"users\" WHERE \"username\" = @username AND \"password\" = @password"; using (NpgsqlCommand pwCmd = new NpgsqlCommand(pwQuery, con)) { pwCmd.Parameters.AddWithValue("@username", username); diff --git a/PrototypWPFHAG/PdfServiceClient.cs b/PrototypWPFHAG/PdfServiceClient.cs new file mode 100644 index 0000000..3ecfb8f --- /dev/null +++ b/PrototypWPFHAG/PdfServiceClient.cs @@ -0,0 +1,52 @@ +using System.Net.Http; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +public class DocumentResponse +{ + [JsonPropertyName("documents")] // Konsistent mit Such-Endpoint + public List<SearchResult> Documents { get; set; } +} + +public class PdfServiceClient +{ + private readonly HttpClient _httpClient; + private const string BaseUrl = "http://localhost:8000"; // Microservice-URL + + public PdfServiceClient() + { + _httpClient = new HttpClient + { + BaseAddress = new Uri(BaseUrl), Timeout = TimeSpan.FromSeconds(30) + }; + } + + public async Task<string> GetDocumentContentAsync(int documentId) + { + var response = await _httpClient.GetAsync($"{BaseUrl}/documents/{documentId}/markdown"); + response.EnsureSuccessStatusCode(); + var json = await response.Content.ReadAsStringAsync(); + var result = JsonSerializer.Deserialize<JsonElement>(json); + return result.GetProperty("content").GetString(); + } + + public async Task<List<SearchResult>> SearchDocumentsAsync(string query) + { + var response = await _httpClient.GetAsync($"{BaseUrl}/documents/search?query={query}"); + response.EnsureSuccessStatusCode(); + var json = await response.Content.ReadAsStringAsync(); + return JsonSerializer.Deserialize<List<SearchResult>>(json); + } +} + +public class SearchResult +{ + [JsonPropertyName("id")] + public int Id { get; set; } + + [JsonPropertyName("filename")] + public string Filename { get; set; } + [JsonPropertyName("content")] + public string Content { get; set; } +} diff --git a/PrototypWPFHAG/PrototypWPFHAG.csproj b/PrototypWPFHAG/PrototypWPFHAG.csproj index 0422d05..334273d 100644 --- a/PrototypWPFHAG/PrototypWPFHAG.csproj +++ b/PrototypWPFHAG/PrototypWPFHAG.csproj @@ -14,6 +14,7 @@ <ItemGroup> <None Remove="Images\databaseicon.png" /> + <None Remove="Images\pdf-icon.png" /> </ItemGroup> <ItemGroup> @@ -31,4 +32,8 @@ <PackageReference Include="SixLabors.ImageSharp" Version="3.1.7" /> </ItemGroup> + <ItemGroup> + <Resource Include="Images\pdf-icon.png" /> + </ItemGroup> + </Project> diff --git a/PrototypWPFHAG/SearchWindow.xaml b/PrototypWPFHAG/SearchWindow.xaml index 72ac88d..a8b50c6 100644 --- a/PrototypWPFHAG/SearchWindow.xaml +++ b/PrototypWPFHAG/SearchWindow.xaml @@ -1,69 +1,204 @@ -<Window x:Class="PrototypWPFHAG.SearchWindow" +<mah:MetroWindow xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" + x:Class="PrototypWPFHAG.SearchWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:PrototypWPFHAG" - Title="Such Fenster" Height="600" Width="800"> + Title="PDF-Verwaltung (Admin)" Height="600" Width="1000" + WindowTitleBrush="FireBrick" + Icon="pack://application:,,,/Images/databaseicon.png"> <Grid> <!-- 左侧垂直布局 --> <Grid.ColumnDefinitions> - <ColumnDefinition Width="200"/> + <ColumnDefinition Width="56.527"/> + <ColumnDefinition Width="143.473"/> <!-- 左侧固定宽度 --> <ColumnDefinition Width="*"/> <!-- 右侧占满剩余空间 --> </Grid.ColumnDefinitions> <!-- 左侧区域 --> - <StackPanel Orientation="Vertical" Margin="10"> - <Grid Margin="0,0,0,10"> + <Border + BorderBrush="FireBrick" + BorderThickness="3" Padding="20" + Grid.ColumnSpan="3" + /> + + <StackPanel + Orientation="Vertical" + Margin="10,10,772,10" + Grid.ColumnSpan="3"> + <Grid + Margin="0,0,0,10" + Height="85"> <Grid.ColumnDefinitions> - <ColumnDefinition Width="*"/> - <ColumnDefinition Width="Auto"/> + <ColumnDefinition + Width="*" + /> + <ColumnDefinition + Width="Auto" + /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> - <RowDefinition Height="Auto"/> - <RowDefinition Height="Auto"/> + <RowDefinition + Height="Auto" + /> + <RowDefinition + Height="Auto" + /> </Grid.RowDefinitions> - <TextBox x:Name="TextField" Grid.Row="0" Height="50" VerticalContentAlignment="Center" Margin="0,0,5,0"/> - <Border Grid.Row="0" Grid.Column="1" Background="LightGray" Height="50" Margin="5,0,0,0"> - <TextBlock Text="Bild hochladen" VerticalAlignment="Center" HorizontalAlignment="Center"/> + + <Border + BorderBrush="Gray" + BorderThickness="1" + Margin="5,10,0,-85" Grid.Row="1"> + <Canvas + x:Name="PdfDropCanvas" + Margin="5,0,0,-24" + Grid.RowSpan="2" + AllowDrop="True" + Background="Transparent" + DragEnter="PdfDropCanvas_DragEnter" + Drop="PdfDropCanvas_Drop"> + + <TextBlock + x:Name="DropHintText" + Text="PDF hier rein ziehen" + HorizontalAlignment="Center" + VerticalAlignment="Center" + Foreground="Gray" + /> + + <!-- Vorschau-Elemente (unsichtbar, bis eine Datei abgelegt wird) --> + <Image + x:Name="PdfIcon" + Source="pack://application:,,,/Images/pdf-icon.png" + Width="25" Height="25" + Margin="0,5,0,0" + Visibility="Collapsed" + /> + <TextBlock + x:Name="PdfFileNameText" + Margin="40,10,0,0" + Visibility="Collapsed" + /> + </Canvas> </Border> - <Line Grid.Row="0" Grid.Column="1" X1="0" Y1="25" X2="1" Y2="25" Stroke="Black" StrokeThickness="1" Margin="5,0,0,0"/> - <Button Content="Suchen" Width="180" Height="30" Grid.Row="1" Grid.ColumnSpan="2" HorizontalAlignment="Right" Margin="0,5,0,0"/> + + </Grid> + <!-- PDFField --> <Grid Margin="0,0,0,10"> <Grid.ColumnDefinitions> - <ColumnDefinition Width="*"/> - <ColumnDefinition Width="Auto"/> + <ColumnDefinition + Width="*" + /> + <ColumnDefinition + Width="Auto" + /> </Grid.ColumnDefinitions> - <Border Background="LightGray" Height="30" Margin="0,0,0,0" Grid.Column="0"> - <TextBlock Text="PDF hochladen" VerticalAlignment="Center" HorizontalAlignment="Center" RenderTransformOrigin="0.514,5.613"/> - </Border> - <Button Content="ADD" Width="60" Height="30" Grid.Column="1" Margin="5,0,0,0"/> + <Button + Content="PDF hochladen" + Width="auto" Height="30" + Margin="5,0,0,0" + Background="LightGreen" + Click="UploadButton_Click" + /> + </Grid> - <Button Content="Zurück " Margin="5,380" Click="BackToLogIn_Click"/> + + <StackPanel Orientation="Horizontal" Margin="5,10"> + <RadioButton x:Name="SearchByIdRadio" Content="ID" IsChecked="True"/> + <RadioButton x:Name="SearchByTextRadio" Content="Text" Margin="10,0"/> + </StackPanel> + + <TextBox + x:Name="SearchTextBox" + Margin="5,0,0,0" + /> + + <Button + Content="Suchen" + x:Name="SearchButton" + Click="SearchButton_Click" + Margin="5,10,0,10" + /> + + <!-- ListField --> + <ListBox + x:Name="SearchResultsListBox" + DisplayMemberPath="Filename" + Margin="5,0,0,0" + ItemsSource="{Binding}" + SelectionMode="Extended" + SelectionChanged="SearchResultsListBox_SelectionChanged" + /> + + <TextBlock + x:Name="UploadStatusText" + TextAlignment="Center" Margin="0,35,0,35" Height="27" + /> + + <ProgressBar + x:Name="UploadProgressBar" + Height="10" + Minimum="0" Maximum="100" + Visibility="Collapsed" + Margin="0,20,0,0" + /> + + <Button + Content="Zurück zur Anmeldung" + Click="BackToLogIn_Click" + Margin="5,10,0,0" + Height="30" + Background="#ffd64f" + /> + </StackPanel> <!-- 右侧区域 --> - <Grid Grid.Column="1" Margin="10"> - <Label Content="Zeugnisse:" HorizontalAlignment="Left" Margin="0,2,0,8"/> - <!-- ListField --> - <ListBox x:Name="ListField" Margin="0,29,0,35" BorderThickness="1" BorderBrush="Black"> - <ListBox.ItemTemplate> - <DataTemplate> - <StackPanel Orientation="Vertical"> - <!-- 内容 --> - <TextBlock Text="{Binding}" VerticalAlignment="Center" HorizontalAlignment="Stretch" Padding="5"/> - <!-- 分隔线 --> - <Border Height="1" Background="Black" Margin="0,2,0,2"/> - </StackPanel> - </DataTemplate> - </ListBox.ItemTemplate> - </ListBox> + <Grid + Grid.Column="2" + Margin="60,10,10,10"> + <Label + Content="PDF-Inhalt:" + HorizontalAlignment="Left" + Margin="0,2,0,8" + /> + + <ScrollViewer + x:Name="ContentScrollViewer" + Margin="0,0,0,35" + VerticalScrollBarVisibility="Auto" + HorizontalScrollBarVisibility="Auto"> + + <TextBox + x:Name="ContentTextBox" + Text="{Binding SelectedDocument.Content}" + IsReadOnly="True" + TextWrapping="Wrap" + AcceptsReturn="True" + VerticalScrollBarVisibility="Auto" + HorizontalScrollBarVisibility="Auto" + Margin="5,25, 0, 35" + Height="Auto" + MinHeight="494" + /> + + </ScrollViewer> <!-- 删除按钮 --> - <Button Content="Löschen" Width="100" Height="30" HorizontalAlignment="Right" VerticalAlignment="Bottom"/> + <Button + Content="Löschen" + Width="100" + Height="30" + HorizontalAlignment="Right" + VerticalAlignment="Bottom" + Background="Firebrick" + Click="DeleteButton_Click" + /> </Grid> </Grid> -</Window> \ No newline at end of file +</mah:MetroWindow> \ No newline at end of file diff --git a/PrototypWPFHAG/SearchWindow.xaml.cs b/PrototypWPFHAG/SearchWindow.xaml.cs index ed81b01..c09d822 100644 --- a/PrototypWPFHAG/SearchWindow.xaml.cs +++ b/PrototypWPFHAG/SearchWindow.xaml.cs @@ -1,27 +1,42 @@ -using System; -using System.Collections.Generic; -using System.Linq; +using MahApps.Metro.Controls; +using System.Diagnostics; +using System.IO; +using System.Net; +using System.Net.Http; using System.Text; -using System.Threading.Tasks; +using System.Text.Json; +using System.Text.Json.Serialization; +using System.Web; 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 PrototypWPFHAG { /// <summary> /// Interaktionslogik für SearchWindow.xaml /// </summary> - public partial class SearchWindow : Window + + public class DocumentResponse { + [JsonPropertyName("documents")] + public List<SearchResult> Documents { get; set; } + } + public partial class SearchWindow : MetroWindow + { + public readonly HttpClient _httpClient; + private bool _isSearchInProgress; + private readonly PdfServiceClient _pdfServiceClient = new(); + private const string BaseUrl = "http://localhost:8000"; // Microservice-URL + private string _selectedPdfPath; public SearchWindow() { InitializeComponent(); + _httpClient = new HttpClient + { + BaseAddress = new Uri(BaseUrl), + Timeout = TimeSpan.FromSeconds(30) + }; } private void BackToLogIn_Click(object sender, RoutedEventArgs e) @@ -30,5 +45,353 @@ namespace PrototypWPFHAG loginWindow.Show(); // Open new window this.Close(); // Close this window } + private async void SearchButton_Click(object sender, RoutedEventArgs e) + { + if (_isSearchInProgress) return; + + try + { + _isSearchInProgress = true; + SearchButton.IsEnabled = false; + + if (SearchByIdRadio.IsChecked == true) + { + await SearchByIdAsync(); + } + else + { + await SearchByTextAsync(); + } + } + catch (Exception ex) + { + MessageBox.Show($"Fehler bei der Suche: {ex.Message}", + "Fehler", + MessageBoxButton.OK, + MessageBoxImage.Error); + } + finally + { + _isSearchInProgress = false; + SearchButton.IsEnabled = true; + } + } + private async Task SearchByIdAsync() + { + if (!int.TryParse(SearchTextBox.Text, out int documentId)) + { + MessageBox.Show("Bitte eine gültige ID eingeben"); + return; + } + + try + { + var response = await _httpClient.GetAsync($"/documents/by-id/{documentId}"); + var json = await response.Content.ReadAsStringAsync(); + var result = JsonSerializer.Deserialize<JsonElement>(json); + + // Extrahiere das Array "documents" + var documents = result.GetProperty("documents"); + if (documents.GetArrayLength() == 0) + { + MessageBox.Show("Dokument nicht gefunden"); + return; + } + + // Nimm das erste Element des Arrays + var document = documents[0]; + + // UI aktualisieren + await Dispatcher.InvokeAsync(() => + { + SearchResultsListBox.ItemsSource = new List<SearchResult> + { + new SearchResult + { + Id = document.GetProperty("id").GetInt32(), + Filename = document.GetProperty("filename").GetString(), + Content = document.GetProperty("content").GetString() + } + }; + ContentTextBox.Text = document.GetProperty("content").GetString(); + }); + } + catch (Exception ex) + { + MessageBox.Show($"Fehler: {ex.Message}"); + } + } + private async Task SearchByTextAsync() + { + try + { + var encodedQuery = Uri.EscapeDataString(SearchTextBox.Text); + var response = await _httpClient.GetAsync($"/documents/search?query={encodedQuery}"); + + var json = await response.Content.ReadAsStringAsync(); + var result = JsonSerializer.Deserialize<JsonElement>(json); + + var documents = JsonSerializer.Deserialize<List<SearchResult>>( + result.GetProperty("documents").GetRawText()); + + MessageBox.Show($"Gefundene Dokumente: {documents?.Count}", "Debug"); + + SearchResultsListBox.ItemsSource = documents; + SearchResultsListBox.DisplayMemberPath = "Filename"; + } + catch (Exception ex) + { + MessageBox.Show($"Fehler: {ex.Message}"); + } + } + + + + private void PdfDropCanvas_DragEnter(object sender, DragEventArgs e) + { + // Nur PDF-Dateien erlauben + if (e.Data.GetDataPresent(DataFormats.FileDrop)) + { + var files = (string[])e.Data.GetData(DataFormats.FileDrop); + if (files.Any(f => System.IO.Path.GetExtension(f).Equals(".pdf", StringComparison.OrdinalIgnoreCase))) + { + e.Effects = DragDropEffects.Copy; + DropHintText.Visibility = Visibility.Collapsed; // Platzhalter ausblenden + } + } + else + { + e.Effects = DragDropEffects.None; + } + e.Handled = true; + } + + private void PdfDropCanvas_Drop(object sender, DragEventArgs e) + { + if (e.Data.GetDataPresent(DataFormats.FileDrop)) + { + string[] files = (string[])e.Data.GetData(DataFormats.FileDrop); + _selectedPdfPath = files.FirstOrDefault(f => System.IO.Path.GetExtension(f).Equals(".pdf", StringComparison.OrdinalIgnoreCase)); + + if (_selectedPdfPath != null) + { + // Vorschau anzeigen + PdfIcon.Visibility = Visibility.Visible; + PdfFileNameText.Text = System.IO.Path.GetFileName(_selectedPdfPath); + PdfFileNameText.Visibility = Visibility.Visible; + DropHintText.Visibility = Visibility.Collapsed; + } + } + } + + // Response-Klassen + public class ApiResponse + { + [JsonPropertyName("success")] + public bool Success { get; set; } + + [JsonPropertyName("document")] + public DocumentDetail Document { get; set; } + } + + public class DocumentDetail + { + [JsonPropertyName("id")] + public int Id { get; set; } + + [JsonPropertyName("filename")] + public string Filename { get; set; } + + [JsonPropertyName("content")] + public string Content { get; set; } + } + public class ApiError + { + public string Detail { get; set; } + } + + private async void UploadButton_Click(object sender, RoutedEventArgs e) + { + if (string.IsNullOrEmpty(_selectedPdfPath)) + { + MessageBox.Show("Keine PDF ausgewählt!"); + return; + } + + // UI zurücksetzen + UploadProgressBar.Visibility = Visibility.Visible; + UploadProgressBar.Value = 0; + UploadStatusText.Text = "Upload läuft..."; + + try + { + using (var httpClient = new HttpClient()) + using (var fileStream = File.OpenRead(_selectedPdfPath)) + { + var progress = new Progress<float>(percent => + { + Dispatcher.Invoke(() => + { + UploadProgressBar.Value = percent * 100; + UploadStatusText.Text = $"Upload: {(int)(percent * 100)}%"; + }); + }); + + var content = new StreamContent(fileStream); + var formData = new MultipartFormDataContent(); + formData.Add(content, "file", Path.GetFileName(_selectedPdfPath)); + + // Simulierter Fortschritt + for (int i = 0; i <= 100; i += 10) + { + await Task.Delay(100); + ((IProgress<float>)progress).Report(i / 100f); + } + + var response = await httpClient.PostAsync($"{BaseUrl}/upload-pdf", formData); + + if (response.IsSuccessStatusCode) + { + // Erfolgsmeldung anzeigen + UploadStatusText.Text = "Erfolgreich hochgeladen!"; + + // Canvas zurücksetzen + Dispatcher.Invoke(() => + { + PdfIcon.Visibility = Visibility.Collapsed; + PdfFileNameText.Visibility = Visibility.Collapsed; + DropHintText.Visibility = Visibility.Visible; + _selectedPdfPath = null; + }); + + // Erfolgsmeldung nach 3 Sekunden ausblenden + await Task.Delay(3000); + UploadStatusText.Text = string.Empty; + } + else + { + UploadStatusText.Text = "Fehler beim Upload"; + } + } + } + catch (Exception ex) + { + UploadStatusText.Text = $"Fehler: {ex.Message}"; + } + finally + { + UploadProgressBar.Visibility = Visibility.Collapsed; + } + } + private async void DeleteButton_Click(object sender, RoutedEventArgs e) + { + if (SearchResultsListBox.SelectedItems.Count == 0) + { + MessageBox.Show("Bitte Dokumente auswählen."); + return; + } + + var result = MessageBox.Show( + $"{SearchResultsListBox.SelectedItems.Count} Dokument(e) löschen?", + "Bestätigung", + MessageBoxButton.YesNo, + MessageBoxImage.Warning + ); + + if (result != MessageBoxResult.Yes) return; + + var deletedIds = new List<int>(); + var errorIds = new List<int>(); + + foreach (var item in SearchResultsListBox.SelectedItems.Cast<SearchResult>().ToList()) + { + try + { + var response = await _httpClient.DeleteAsync($"/documents/by-id/{item.Id}/delete"); + if (response.IsSuccessStatusCode) + { + deletedIds.Add(item.Id); + Debug.WriteLine($"Gelöscht: {item.Id}"); + } + else + { + errorIds.Add(item.Id); + var errorContent = await response.Content.ReadAsStringAsync(); + Debug.WriteLine($"Fehler bei {item.Id}: {errorContent}"); + } + } + catch (Exception ex) + { + errorIds.Add(item.Id); + Debug.WriteLine($"Ausnahme: {ex.Message}"); + } + } + + // Aktualisiere die Liste unabhängig vom Suchmodus + if (SearchByIdRadio.IsChecked == true) + { + await SearchByIdAsync(); // Neu laden der ID-Suche + } + else + { + await SearchByTextAsync(); // Neu laden der Textsuche + } + + // Feedback an Benutzer + var message = new StringBuilder(); + if (deletedIds.Count > 0) + { + message.AppendLine($"{deletedIds.Count} Dokument(e) gelöscht."); + } + if (errorIds.Count > 0) + { + message.AppendLine($"{errorIds.Count} Dokument(e) konnten nicht gelöscht werden."); + } + MessageBox.Show(message.ToString()); + } + + private async void SearchResultsListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + if (SearchResultsListBox.SelectedItem is SearchResult selectedDocument) + { + try + { + var response = await _httpClient.GetAsync($"/documents/by-id/{selectedDocument.Id}"); + var json = await response.Content.ReadAsStringAsync(); + var result = JsonSerializer.Deserialize<JsonElement>(json); + + // Sicherstellen, dass das "documents" Array existiert + if (!result.TryGetProperty("documents", out var documents)) + { + ContentTextBox.Text = "Ungültiges Antwortformat"; + return; + } + + // Sicherstellen, dass das Array mindestens ein Element hat + if (documents.GetArrayLength() == 0) + { + ContentTextBox.Text = "Dokument nicht gefunden"; + return; + } + + var document = documents[0]; + + // Sicherstellen, dass alle benötigten Felder existieren + if (!document.TryGetProperty("content", out var contentProp)) + { + ContentTextBox.Text = "Dokumentinhalt fehlt"; + return; + } + + ContentTextBox.Text = contentProp.GetString(); + + Debug.WriteLine($"API-Antwort: {json}"); + } + catch (Exception ex) + { + ContentTextBox.Text = $"Fehler: {ex.Message}"; + } + } + } } }