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();
}
}
}