99 lines
2.5 KiB
C#
99 lines
2.5 KiB
C#
using System.ComponentModel;
|
|
using Microsoft.AspNetCore.Components;
|
|
using OpenCvSharp;
|
|
using VisionBuilder.UI.Blazor.Helpers;
|
|
using VisionBuilder.UI.Common.ViewModel;
|
|
|
|
namespace VisionBuilder.UI.Blazor.Components;
|
|
|
|
public partial class PreviewWindow : ComponentBase, IDisposable
|
|
{
|
|
[Parameter] public PreviewVM? ViewModel { get; set; }
|
|
|
|
private string _dataUri = string.Empty;
|
|
private bool _isError;
|
|
private DateTime _lastRenderTime = DateTime.MinValue;
|
|
private Timer? _pendingTimer;
|
|
private PreviewVM? _subscribedVm;
|
|
private bool _disposed;
|
|
|
|
protected override void OnParametersSet()
|
|
{
|
|
if (_subscribedVm != ViewModel)
|
|
{
|
|
Unsubscribe();
|
|
Subscribe();
|
|
}
|
|
}
|
|
|
|
private void Subscribe()
|
|
{
|
|
_subscribedVm = ViewModel;
|
|
if (ViewModel != null)
|
|
ViewModel.PropertyChanged += OnPropertyChanged;
|
|
}
|
|
|
|
private void Unsubscribe()
|
|
{
|
|
if (_subscribedVm != null)
|
|
_subscribedVm.PropertyChanged -= OnPropertyChanged;
|
|
_subscribedVm = null;
|
|
}
|
|
|
|
private async void OnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
|
{
|
|
if (e.PropertyName != nameof(PreviewVM.ImagePreview) && e.PropertyName != nameof(PreviewVM.IsError))
|
|
return;
|
|
|
|
var now = DateTime.UtcNow;
|
|
var elapsed = (now - _lastRenderTime).TotalMilliseconds;
|
|
|
|
if (elapsed < 100)
|
|
{
|
|
// Schedule a render for when the throttle window expires,
|
|
// so we always show the latest frame.
|
|
_pendingTimer?.Dispose();
|
|
_pendingTimer = new Timer(_ => RenderLatest(), null,
|
|
(int)(100 - elapsed) + 1, Timeout.Infinite);
|
|
return;
|
|
}
|
|
|
|
await RenderCurrentFrame();
|
|
}
|
|
|
|
private async void RenderLatest()
|
|
{
|
|
_pendingTimer?.Dispose();
|
|
_pendingTimer = null;
|
|
await RenderCurrentFrame();
|
|
}
|
|
|
|
private async Task RenderCurrentFrame()
|
|
{
|
|
if (_disposed) return;
|
|
|
|
_lastRenderTime = DateTime.UtcNow;
|
|
|
|
var mat = ViewModel?.ImagePreview;
|
|
var isError = ViewModel?.IsError ?? false;
|
|
|
|
string dataUri = string.Empty;
|
|
if (mat != null && !mat.Empty())
|
|
{
|
|
dataUri = mat.ToBase64DataUri();
|
|
}
|
|
|
|
_dataUri = dataUri;
|
|
_isError = isError;
|
|
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_disposed = true;
|
|
_pendingTimer?.Dispose();
|
|
Unsubscribe();
|
|
}
|
|
}
|