From b16ae70762e031140f0129cbc701ea0e8a202023 Mon Sep 17 00:00:00 2001 From: TekH Date: Thu, 11 Jun 2026 13:02:53 +0200 Subject: [PATCH] Remove signature-related functionality This commit removes all features and UI elements related to signature handling in the `EnvelopeReceiverPage_DxReportViewer.razor` file. Key changes include: - Removed signature creation (drawing, typing, uploading) and associated UI components like the signature popup and action bar. - Removed annotation handling logic, including toggling checkboxes and applying signatures to annotations. - Removed PDF export functionality for signed documents. - Deleted methods and properties related to signature handling, such as `AddSignature`, `OnInitializedAsync`, and `SignaturePopupVisible`. - Removed `@inject` services and JavaScript interop calls related to signature handling. - Simplified the `DxReportViewer` usage to only display the report without overlays or interactions. - Removed envelope metadata display and logout functionality. The page now focuses solely on displaying reports without any signature-related features. --- .../EnvelopeReceiverPage_DxReportViewer.razor | 684 +----------------- 1 file changed, 7 insertions(+), 677 deletions(-) diff --git a/EnvelopeGenerator.ReceiverUI/Pages/EnvelopeReceiverPage_DxReportViewer.razor b/EnvelopeGenerator.ReceiverUI/Pages/EnvelopeReceiverPage_DxReportViewer.razor index 3bee7f8d..6f12b843 100644 --- a/EnvelopeGenerator.ReceiverUI/Pages/EnvelopeReceiverPage_DxReportViewer.razor +++ b/EnvelopeGenerator.ReceiverUI/Pages/EnvelopeReceiverPage_DxReportViewer.razor @@ -1,522 +1,35 @@ @page "/envelope/{EnvelopeKey}/DxReportViewer" -@using System.Drawing -@using DevExpress.Blazor -@using DevExpress.Drawing -@using DevExpress.Utils -@using DevExpress.XtraPrinting -@using DevExpress.XtraPrinting.Drawing -@using Microsoft.JSInterop @using XtraReport = DevExpress.XtraReports.UI.XtraReport -@using BottomMarginBand = DevExpress.XtraReports.UI.BottomMarginBand -@using XRLabel = DevExpress.XtraReports.UI.XRLabel -@using XRPictureBox = DevExpress.XtraReports.UI.XRPictureBox -@using XRControl = DevExpress.XtraReports.UI.XRControl -@using ImageSizeMode = DevExpress.XtraPrinting.ImageSizeMode -@using EnvelopeGenerator.ReceiverUI.Services @using DevExpress.Blazor.Reporting @using Microsoft.Extensions.Options @using EnvelopeGenerator.ReceiverUI.Options -@using EnvelopeGenerator.ReceiverUI.Models -@implements IDisposable -@inject IJSRuntime JSRuntime -@inject AnnotationService AnnotationService -@inject IOptions AppOptions -@inject NavigationManager Navigation +@using EnvelopeGenerator.ReceiverUI.Services @inject InMemoryReportStorageWebExtension ReportStorage -@inject EnvelopeGenerator.ReceiverUI.Services.DocumentService DocumentService -@inject EnvelopeGenerator.ReceiverUI.Services.AuthService AuthService -@inject EnvelopeGenerator.ReceiverUI.Services.EnvelopeReceiverService EnvelopeReceiverService +@inject DocumentService DocumentService +@inject IOptions AppOptions -
-
- -@* ?? Envelope info header ???????????????????????????????????????????????? *@ -@if (_envelopeReceiver is not null) { -
-
-
- - - -
-
@(_envelopeReceiver.Envelope?.Title ?? "Dokument")
- @if (!string.IsNullOrWhiteSpace(_envelopeReceiver.Envelope?.User?.FullName) || !string.IsNullOrWhiteSpace(_envelopeReceiver.Envelope?.User?.Email)) { -
- Von - @if (!string.IsNullOrWhiteSpace(_envelopeReceiver.Envelope?.User?.FullName)) { - @_envelopeReceiver.Envelope!.User!.FullName - } - @if (!string.IsNullOrWhiteSpace(_envelopeReceiver.Envelope?.User?.Email)) { - <@_envelopeReceiver.Envelope!.User!.Email> - } -  ·  @_envelopeReceiver.Envelope?.AddedWhen.ToString("dd.MM.yyyy") -
- } -
-
-
- @if (!string.IsNullOrWhiteSpace(_envelopeReceiver.Name)) { - - - - - @_envelopeReceiver.Name - - } - @if (!string.IsNullOrWhiteSpace(_envelopeReceiver.CompanyName)) { - - - - - @_envelopeReceiver.CompanyName - - } - @if (!string.IsNullOrWhiteSpace(_envelopeReceiver.JobTitle)) { - @_envelopeReceiver.JobTitle - } - @{ - var docElements = _envelopeReceiver.Envelope?.Documents?.FirstOrDefault()?.Elements; - int sigCount = docElements?.Count() ?? _annotations.Count; - } - @if (sigCount > 0) { - - - - - @sigCount @(sigCount == 1 ? "Unterschriftsfeld" : "Unterschriftsfelder") - - } -
-
- @if (!string.IsNullOrWhiteSpace(_envelopeReceiver.Envelope?.Message)) { -
@_envelopeReceiver.Envelope!.Message
- } - @if (!string.IsNullOrWhiteSpace(_envelopeReceiver.PrivateMessage)) { -
- - - - @_envelopeReceiver.PrivateMessage -
- } -
+@if (Report is not null) { + } -@* ?? Signature action bar ???????????????????????????????????????????????? *@ -
-
- - - @if (_annotations.Count > 0 && !SignatureApplied) { -
-
-
-
- - @_checkedAnnotations.Count / @_annotations.Count - Seite@(AnnotationPages.Count() == 1 ? "" : "n") @string.Join(",", AnnotationPages) - - @if (_capturedSignature is null) { - Zuerst Unterschrift erstellen - } else if (_checkedAnnotations.Count == _annotations.Count) { - ✓ Wird angewendet… - } -
- } - - @if (!string.IsNullOrWhiteSpace(SignatureValidationMessage)) { - @SignatureValidationMessage - } - @if (SignatureApplied) { - - - - - Unterschrift angewendet - - } - -
- - -
-
-
- -
- - - - - - @if(ActiveSignatureTab == SignatureTabDraw) { -

Bitte unterschreiben Sie im folgenden Feld.

- - } else if(ActiveSignatureTab == SignatureTabText) { -

Geben Sie Ihre Unterschrift als Text ein und waehlen Sie eine Schriftart.

-
-
- -
-
- -
-
- - } else { -

Laden Sie ein Bild Ihrer Unterschrift hoch.

- - - } - - -
-

Bitte geben Sie die folgenden Angaben ein. Das Datum wird automatisch hinzugefuegt.

-
-
- - -
-
- - -
-
- - -
-
-
- - @if(!string.IsNullOrWhiteSpace(PopupValidationMessage)) { -
@PopupValidationMessage
- } -
- -
- - -
-
-
- -
-@if(Report is not null) { - -} -
- -
- @code { - - const string SignatureTabDraw = "draw"; - const string SignatureTabText = "text"; - const string SignatureTabImage = "image"; - const string DrawCanvasId = "receiver-signature-pad"; - const string TypedCanvasId = "receiver-typed-signature-pad"; - const string ImageInputId = "receiver-signature-image-input"; - const string ImageCanvasId = "receiver-image-signature-pad"; - - readonly (string Text, string Value)[] TypedSignatureFonts = { - ("Brush Script", "'Brush Script MT', cursive"), - ("Segoe Script", "'Segoe Script', cursive"), - ("Lucida Handwriting", "'Lucida Handwriting', cursive"), - ("Comic Sans", "'Comic Sans MS', cursive"), - ("Cursive", "cursive") -}; - [Parameter] public string EnvelopeKey { get; set; } = string.Empty; - DxReportViewer? reportViewer; XtraReport? Report; - bool SignatureApplied; - bool SignaturePopupVisible; - string? SignatureValidationMessage; - string? PopupValidationMessage; - string ActiveSignatureTab = SignatureTabDraw; - string TypedSignatureText = string.Empty; - string TypedSignatureFont = "'Brush Script MT', cursive"; - string SignerFullName = string.Empty; - string SignerPosition = string.Empty; - string SignaturePlace = string.Empty; - int ViewerKey; - bool IsLoggingOut; - - IReadOnlyList _annotations = []; - IEnumerable AnnotationPages => _annotations.Select(a => a.Page).Distinct().OrderBy(p => p); - EnvelopeReceiverDto? _envelopeReceiver; - record SignatureCapture(string DataUrl, string FullName, string Position, string Place); - SignatureCapture? _capturedSignature; byte[]? _basePdfBytes; - // annotation IDs the user has checked via overlay checkboxes - readonly HashSet _checkedAnnotations = []; - DotNetObjectReference? _dotNetRef; - int _lastOverlayViewerKey = -1; - - async Task LogoutAsync() { - if (IsLoggingOut) return; - IsLoggingOut = true; - await InvokeAsync(StateHasChanged); - await AuthService.LogoutEnvelopeReceiverAsync(EnvelopeKey); - Navigation.NavigateTo($"/envelope/login/{Uri.EscapeDataString(EnvelopeKey)}", forceLoad: true); - } protected override async Task OnInitializedAsync() { - var hasAccess = await AuthService.CheckEnvelopeAccessAsync(EnvelopeKey); - if (!hasAccess) { - Navigation.NavigateTo($"/envelope/login/{Uri.EscapeDataString(EnvelopeKey)}"); - return; - } - - ActiveSignatureTab = SignatureTabDraw; - SignaturePopupVisible = true; - SignatureValidationMessage = null; - PopupValidationMessage = null; - - _annotations = await AnnotationService.GetAnnotationsAsync(EnvelopeKey); - _envelopeReceiver = await EnvelopeReceiverService.GetAsync(EnvelopeKey); - if (!AppOptions.Value.ForceToUseFakeDocument) { var (pdfBytes, _) = await DocumentService.GetDocumentAsync(EnvelopeKey); if (pdfBytes is { Length: > 0 }) _basePdfBytes = pdfBytes; } - var initialReport = BuildFreshBaseReport(); - Report = initialReport; - } - - protected override async Task OnAfterRenderAsync(bool firstRender) { - if (firstRender) - _dotNetRef = DotNetObjectReference.Create(this); - - - if (Report is not null && _annotations.Count > 0 - && _capturedSignature is not null && !SignatureApplied - && _lastOverlayViewerKey != ViewerKey) { - _lastOverlayViewerKey = ViewerKey; - await JSRuntime.InvokeVoidAsync( - "receiverSignature.installAnnotationCheckboxes", - _annotations, _checkedAnnotations.ToArray(), _dotNetRef); - } - } - - [JSInvokable] - public async Task OnAnnotationToggled(long annotationId, bool isChecked) { - if (isChecked) - _checkedAnnotations.Add(annotationId); - else - _checkedAnnotations.Remove(annotationId); - await InvokeAsync(StateHasChanged); - - if (_capturedSignature is not null - && !SignatureApplied - && _annotations.Count > 0 - && _checkedAnnotations.Count == _annotations.Count) { - // K?sa bekleme: kullan?c? son tick'in görsel feedback'ini görsün - await Task.Delay(400); - await SubmitSignaturesAsync(); - } - } - - void OpenSignaturePopupAsync() { - ActiveSignatureTab = SignatureTabDraw; - SignaturePopupVisible = true; - SignatureValidationMessage = null; - PopupValidationMessage = null; - } - - async Task OnPopupShownAsync() { - await InitializeActiveSignatureTabAsync(); - } - - async Task SetSignatureTabAsync(string tab) { - ActiveSignatureTab = tab; - PopupValidationMessage = null; - await InvokeAsync(StateHasChanged); - await Task.Delay(50); - await InitializeActiveSignatureTabAsync(); - } - - async Task InitializeActiveSignatureTabAsync() { - if(ActiveSignatureTab == SignatureTabDraw) { - await JSRuntime.InvokeVoidAsync("receiverSignature.initialize", DrawCanvasId); - } else if(ActiveSignatureTab == SignatureTabText) { - await JSRuntime.InvokeVoidAsync("receiverSignature.initializeTyped", TypedCanvasId); - await RenderTypedSignatureAsync(); - } else { - await JSRuntime.InvokeVoidAsync("receiverSignature.initializeImage", ImageInputId, ImageCanvasId); - } - } - - async Task RenewSignatureAsync() { - PopupValidationMessage = null; - - if(ActiveSignatureTab == SignatureTabDraw) { - await JSRuntime.InvokeVoidAsync("receiverSignature.clear", DrawCanvasId); - } else if(ActiveSignatureTab == SignatureTabText) { - TypedSignatureText = string.Empty; - await JSRuntime.InvokeVoidAsync("receiverSignature.clearTyped", TypedCanvasId); - } else { - await JSRuntime.InvokeVoidAsync("receiverSignature.clearImage", ImageInputId, ImageCanvasId); - } - } - - void CloseSignaturePopup() { - PopupValidationMessage = null; - SignaturePopupVisible = false; - } - - async Task OnTypedSignatureChanged(Microsoft.AspNetCore.Components.ChangeEventArgs args) { - TypedSignatureText = args.Value?.ToString() ?? string.Empty; - await RenderTypedSignatureAsync(); - } - - async Task OnTypedSignatureFontChanged(Microsoft.AspNetCore.Components.ChangeEventArgs args) { - TypedSignatureFont = args.Value?.ToString() ?? TypedSignatureFont; - await RenderTypedSignatureAsync(); - } - - async Task RenderTypedSignatureAsync() { - await JSRuntime.InvokeVoidAsync("receiverSignature.renderTypedSignature", TypedCanvasId, TypedSignatureText, TypedSignatureFont); - } - - async Task SaveSignatureAsync() { - if (string.IsNullOrWhiteSpace(SignerFullName)) { - PopupValidationMessage = "Bitte geben Sie Vor- und Nachname ein."; - return; - } - if (string.IsNullOrWhiteSpace(SignaturePlace)) { - PopupValidationMessage = "Bitte geben Sie den Ort ein."; - return; - } - var signatureDataUrl = await GetActiveSignatureDataUrlAsync(); - if (string.IsNullOrWhiteSpace(signatureDataUrl)) { - PopupValidationMessage = "Die Unterschrift ist fuer den PDF-Export erforderlich."; - return; - } - - PopupValidationMessage = null; - SignatureValidationMessage = null; - _capturedSignature = new(signatureDataUrl, SignerFullName.Trim(), SignerPosition.Trim(), SignaturePlace.Trim()); - - // If no annotations, apply immediately (no checkbox step needed) - if (_annotations.Count == 0) { - var freshReport = BuildFreshBaseReport(); - AddSignature(freshReport, _capturedSignature.DataUrl, _capturedSignature.FullName, _capturedSignature.Position, _capturedSignature.Place); - Report = freshReport; - SignatureApplied = true; - SignaturePopupVisible = false; - ViewerKey++; - return; - } - - // Close popup; checkboxes will appear on the PDF via OnAfterRenderAsync - SignaturePopupVisible = false; - _lastOverlayViewerKey = -1; // force overlay reinstall - await InvokeAsync(StateHasChanged); - } - - async Task SubmitSignaturesAsync() { - if (_checkedAnnotations.Count == 0) { - SignatureValidationMessage = "Bitte markieren Sie mindestens ein Unterschriftsfeld im Dokument."; - return; - } - if (_checkedAnnotations.Count < _annotations.Count) { - SignatureValidationMessage = $"Bitte markieren Sie alle {_annotations.Count} Unterschriftsfelder. Noch {_annotations.Count - _checkedAnnotations.Count} offen."; - return; - } - - SignatureValidationMessage = null; - var freshReport = BuildFreshBaseReport(); - foreach (var ann in _annotations) - AddSignatureAtAnnotation(freshReport, ann, _capturedSignature!.DataUrl, _capturedSignature.FullName, _capturedSignature.Position, _capturedSignature.Place); - - Report = freshReport; - SignatureApplied = true; - ViewerKey++; - await InvokeAsync(StateHasChanged); - } - - async Task GetActiveSignatureDataUrlAsync() { - if(ActiveSignatureTab == SignatureTabDraw) - return await JSRuntime.InvokeAsync("receiverSignature.getDataUrl", DrawCanvasId); - - if(ActiveSignatureTab == SignatureTabText) { - await RenderTypedSignatureAsync(); - return await JSRuntime.InvokeAsync("receiverSignature.getTypedDataUrl", TypedCanvasId); - } - - return await JSRuntime.InvokeAsync("receiverSignature.getImageDataUrl", ImageCanvasId); - } - - async Task ExportSignedPdfAsync() { - if(!SignatureApplied || Report is null) { - SignatureValidationMessage = "Bitte fuegen Sie die Unterschrift zuerst zum Bericht hinzu."; - return; - } - - try { - SignatureValidationMessage = null; - await reportViewer!.ExportToAsync(ExportFormat.Pdf); - } catch(Exception) { - SignatureValidationMessage = "Das signierte PDF konnte nicht exportiert werden. Bitte laden Sie die Seite neu und versuchen Sie es erneut."; - } + Report = BuildFreshBaseReport(); } XtraReport BuildFreshBaseReport() { @@ -530,193 +43,10 @@ Shown="OnPopupShownAsync"> return CreateReportInstance(); } - static void AddAnnotationPlaceholders(XtraReport report, IReadOnlyList annotations) { - var bottomMargin = report.Bands.OfType().FirstOrDefault(); - if (bottomMargin is null) { - bottomMargin = new BottomMarginBand(); - report.Bands.Add(bottomMargin); - } - - const float sigWidth = 230F; - const float sigHeight = 154F; - const float bottomPad = 6F; - const float defaultTopPad = 8F; - const float maxBandHeight = 210F; - - float requiredHeight = defaultTopPad + sigHeight + bottomPad; - bottomMargin.HeightF = Math.Min(maxBandHeight, Math.Max(bottomMargin.HeightF, requiredHeight)); - float topPad = Math.Max(0F, bottomMargin.HeightF - bottomPad - sigHeight); - - foreach (var ann in annotations) { - float sigX = (float)(ann.X); - var annotId = ann.Id.ToString(); - - var placeholder = new XRLabel { - Name = $"receiverSignaturePlaceholder_{annotId}", - Text = "\u270e Bitte unterschreiben", - BoundsF = new RectangleF(sigX, topPad, sigWidth, sigHeight), - Borders = BorderSide.All, - BorderColor = System.Drawing.Color.FromArgb(230, 81, 0), - BackColor = System.Drawing.Color.FromArgb(30, 255, 236, 153), - Font = new DXFont("Open Sans", 10F, DXFontStyle.Regular), - ForeColor = System.Drawing.Color.FromArgb(94, 38, 0), - TextAlignment = TextAlignment.MiddleCenter - }; - - bottomMargin.Controls.Add(placeholder); - } - } - - XtraReport CreateReportInstance() { - Console.WriteLine("Created with predefinedReports"); + XtraReport CreateReportInstance() { return ReportStorage.TryGetReport("LargeDatasetReport", out var savedReport) ? savedReport : PredefinedReports.ReportsFactory.GetReport("LargeDatasetReport"); } - - static void AddSignature(XtraReport report, string signatureDataUrl, string signerFullName, string signerPosition, string signaturePlace) { - var imageBytes = Convert.FromBase64String(signatureDataUrl[(signatureDataUrl.IndexOf(',') + 1)..]); - using var imageStream = new MemoryStream(imageBytes); - var imageSource = new ImageSource(DXImage.FromStream(imageStream)); - var bottomMargin = report.Bands.OfType().FirstOrDefault(); - - if(bottomMargin is null) { - bottomMargin = new BottomMarginBand(); - report.Bands.Add(bottomMargin); - } - - RemoveExistingSignature(bottomMargin); - - // Layout constants - const float sigX = 390F; - const float sigWidth = 230F; - const float sigImgHeight = 70F; - const float infoHeight = 65F; // up to 4 lines at 8pt - const float innerGap = 5F; - const float bottomPad = 6F; - const float defaultTopPad = 8F; - const float maxBandHeight = 210F; - - float requiredHeight = defaultTopPad + sigImgHeight + innerGap + infoHeight + bottomPad; - - // Grow band if needed, but cap at maxBandHeight to avoid overlapping page content - bottomMargin.HeightF = Math.Min(maxBandHeight, Math.Max(bottomMargin.HeightF, requiredHeight)); - - // If band is tighter than required, compress top padding so content still fits - float topPad = Math.Max(0F, bottomMargin.HeightF - bottomPad - infoHeight - innerGap - sigImgHeight); - - float imageY = topPad; - float labelY = imageY + sigImgHeight + innerGap; - - var signatureInformation = string.IsNullOrWhiteSpace(signerPosition) - ? $"{signerFullName}\n{signaturePlace}, {DateTime.Now:d}" - : $"{signerFullName}\n{signerPosition}\n{signaturePlace}, {DateTime.Now:d}"; - - var signature = new XRPictureBox { - Name = "receiverSignatureImage", - ImageSource = imageSource, - BoundsF = new RectangleF(sigX, imageY, sigWidth, sigImgHeight), - Sizing = ImageSizeMode.ZoomImage, - Borders = BorderSide.Bottom, - BorderColor = System.Drawing.Color.FromArgb(73, 80, 87) - }; - - var signatureLabel = new XRLabel { - Name = "receiverSignatureLabel", - Text = signatureInformation, - Multiline = true, - BoundsF = new RectangleF(sigX, labelY, sigWidth, infoHeight), - Font = new DXFont("Open Sans", 8F, DXFontStyle.Regular), - ForeColor = System.Drawing.Color.FromArgb(73, 80, 87), - TextAlignment = TextAlignment.TopLeft - }; - - bottomMargin.Controls.AddRange(new XRControl[] { signature, signatureLabel }); - } - - static void RemoveExistingSignature(BottomMarginBand bottomMargin) { - var controls = bottomMargin.Controls - .Cast() - .Where(control => control.Name is "receiverSignatureLabel" or "receiverSignatureImage") - .ToArray(); - - foreach(var control in controls) - bottomMargin.Controls.Remove(control); - } - - static void AddSignatureAtAnnotation(XtraReport report, AnnotationDto? annotation, string signatureDataUrl, string signerFullName, string signerPosition, string signaturePlace) { - var imageBytes = Convert.FromBase64String(signatureDataUrl[(signatureDataUrl.IndexOf(',') + 1)..]); - using var imageStream = new MemoryStream(imageBytes); - var imageSource = new ImageSource(DXImage.FromStream(imageStream)); - - var detail = report.Bands.OfType().FirstOrDefault(); - if (detail is null) return; - - var annotId = annotation?.Id.ToString() ?? "0"; - RemoveExistingSignatureById(detail, annotId); - - const float sigWidth = 230F; - const float sigImgHeight = 70F; - const float infoHeight = 48.75F; - const float innerGap = 5F; - - float sigX = (float)(annotation?.X ?? 390.0); - float imageY = (float)(annotation?.Y ?? 900.0); - float labelY = imageY + sigImgHeight + innerGap; - int targetPage = annotation?.Page ?? 1; - - var signatureInformation = string.IsNullOrWhiteSpace(signerPosition) - ? $"{signerFullName}\n{signaturePlace}, {DateTime.Now:d}" - : $"{signerFullName}\n{signerPosition}\n{signaturePlace}, {DateTime.Now:d}"; - - var signature = new XRPictureBox { - Name = $"receiverSignatureImage_{annotId}", - ImageSource = imageSource, - BoundsF = new RectangleF(sigX, imageY, sigWidth, sigImgHeight), - Sizing = ImageSizeMode.ZoomImage, - Borders = BorderSide.Bottom, - BorderColor = System.Drawing.Color.FromArgb(73, 80, 87), - BackColor = Color.FromArgb(219, 219, 219) - }; - - var signatureLabel = new XRLabel { - Name = $"receiverSignatureLabel_{annotId}", - Text = signatureInformation, - Multiline = true, - BoundsF = new RectangleF(sigX, labelY - 5, sigWidth, infoHeight), - Font = new DXFont("Open Sans", 8F, DXFontStyle.Regular), - ForeColor = System.Drawing.Color.FromArgb(73, 80, 87), - TextAlignment = TextAlignment.TopCenter, - BackColor = Color.FromArgb(219, 219, 219) - }; - - // Show each control only on the target page using an independent print counter - int sigPrintCount = 0; - signature.BeforePrint += (_, e) => { - sigPrintCount++; - e.Cancel = sigPrintCount != targetPage; - }; - - int lblPrintCount = 0; - signatureLabel.BeforePrint += (_, e) => { - lblPrintCount++; - e.Cancel = lblPrintCount != targetPage; - }; - - detail.Controls.AddRange(new XRControl[] { signature, signatureLabel }); - } - - static void RemoveExistingSignatureById(DevExpress.XtraReports.UI.DetailBand detail, string annotId) { - var controls = detail.Controls - .Cast() - .Where(c => c.Name == $"receiverSignatureImage_{annotId}" || c.Name == $"receiverSignatureLabel_{annotId}") - .ToArray(); - foreach (var c in controls) - detail.Controls.Remove(c); - } - - public void Dispose() { - _dotNetRef?.Dispose(); - } }