using System; using System.Diagnostics.CodeAnalysis; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.JSInterop; namespace Connected { public interface IScrollListener : IDisposable { /// /// The CSS selector to which the scroll event will be attached /// string Selector { get; set; } event EventHandler OnScroll; } internal class ScrollListener : IScrollListener, IDisposable { private readonly IJSRuntime _js; private DotNetObjectReference _dotNetRef; /// /// The CSS selector to which the scroll event will be attached /// public string Selector { get; set; } = null; [DynamicDependency(nameof(RaiseOnScroll))] [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(ScrollEventArgs))] public ScrollListener(IJSRuntime js) : this(string.Empty, js) { } public ScrollListener(string selector, IJSRuntime js) { _js = js; Selector = selector; } private EventHandler _onScroll; /// /// OnScroll event. Fired when a element is scrolled /// public event EventHandler OnScroll { add => Subscribe(value); remove => Unsubscribe(value); } private async void Subscribe(EventHandler value) { if (_onScroll == null) { await Start(); } _onScroll += value; } private void Unsubscribe(EventHandler value) { _onScroll -= value; if (_onScroll == null) { Cancel().ConfigureAwait(false); } } /// /// invoked in JS, in scroll-listener.js /// /// The scroll event args [JSInvokable] public void RaiseOnScroll(ScrollEventArgs e) { _onScroll?.Invoke(this, e); } /// /// Subscribe to scroll event in JS /// private ValueTask Start() { _dotNetRef = DotNetObjectReference.Create(this); return _js.InvokeVoidAsyncWithErrorHandling ("mudScrollListener.listenForScroll", _dotNetRef, Selector); } /// /// Unsubscribe to scroll event in /// private async ValueTask Cancel() { try { await _js.InvokeVoidAsync( "mudScrollListener.cancelListener", Selector); } catch { /* ignore */ } } public void Dispose() { _dotNetRef?.Dispose(); } } }