Created
April 19, 2022 12:52
-
-
Save runceel/ef624a6d6e8a3b2b8ceb47a3fe269562 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.AspNetCore.Components; | |
using Microsoft.AspNetCore.Components.Forms; | |
using Reactive.Bindings; | |
using Reactive.Bindings.Extensions; | |
using System.Reactive.Disposables; | |
using System.Reflection.Metadata; | |
namespace BlazorApp1.Shared; | |
public class ReactivePropertyValidator : ComponentBase, IDisposable | |
{ | |
private readonly CompositeDisposable _disposable = new(); | |
[CascadingParameter] | |
public EditContext CurrentEditContext { get; set; } = default!; | |
private EditContext _originalEditContext = default!; | |
protected override void OnParametersSet() | |
{ | |
if (_originalEditContext != CurrentEditContext) | |
throw new InvalidOperationException(); | |
} | |
protected override void OnInitialized() | |
{ | |
if (CurrentEditContext == null) | |
throw new InvalidOperationException(); | |
_originalEditContext = CurrentEditContext; | |
_disposable.Add(new ReactivePropertyEventSubscription(_originalEditContext)); | |
} | |
public void Dispose() => _disposable.Dispose(); | |
} | |
class ReactivePropertyEventSubscription : IDisposable | |
{ | |
private readonly CompositeDisposable _disposables = new(); | |
private readonly IReadOnlyList<(FieldIdentifier FieldIdentifier, IReactiveProperty ReactiveProperty)> _properties; | |
private readonly EditContext _editContext; | |
private readonly ValidationMessageStore _messages; | |
public ReactivePropertyEventSubscription(EditContext editContext) | |
{ | |
_editContext = editContext; | |
_messages = new ValidationMessageStore(_editContext); | |
_properties = CollectReactiveProperties(); | |
SubscribeHasErrorsChanged(); | |
} | |
private IReadOnlyList<(FieldIdentifier FieldIdentifier, IReactiveProperty ReactiveProperty)> CollectReactiveProperties() | |
{ | |
return _editContext.Model.GetType() | |
.GetProperties() | |
.Where(x => x.PropertyType.IsGenericType && x.PropertyType.IsAssignableTo(typeof(IReactiveProperty))) | |
.Select(x => (Name: x.Name, ReactiveProperty: (IReactiveProperty?)x.GetValue(_editContext.Model))) | |
.Where(x => x.ReactiveProperty != null) | |
.Select(x => ( | |
FieldIdentifier: new FieldIdentifier(x.ReactiveProperty!, nameof(IReactiveProperty.Value)), | |
ReactiveProperty: x.ReactiveProperty!)) | |
.ToList(); | |
} | |
private void SubscribeHasErrorsChanged() | |
{ | |
foreach (var property in _properties) | |
{ | |
property.ReactiveProperty | |
.ObserveErrorChanged | |
.Subscribe(x => | |
{ | |
_messages.Clear(property.FieldIdentifier); | |
if (x is not null) | |
{ | |
foreach (var message in x.OfType<string>()) | |
{ | |
_messages.Add(property.FieldIdentifier, message); | |
} | |
} | |
_editContext.NotifyValidationStateChanged(); | |
}) | |
.AddTo(_disposables); | |
} | |
} | |
public void Dispose() | |
{ | |
_messages.Clear(); | |
_disposables.Dispose(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment