You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Components/Services/Scroll/ScrollListener.cs

115 lines
3.0 KiB

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