diff --git a/RxBlazorLightCore/Component/RxBLServiceStateSubscriber.cs b/RxBlazorLightCore/Component/RxBLServiceStateSubscriber.cs index 899916a..b191166 100644 --- a/RxBlazorLightCore/Component/RxBLServiceStateSubscriber.cs +++ b/RxBlazorLightCore/Component/RxBLServiceStateSubscriber.cs @@ -1,23 +1,22 @@ using Microsoft.AspNetCore.Components; -namespace RxBlazorLightCore +namespace RxBlazorLightCore; + +public class RxBLServiceChangeSubscriber : ComponentBase where T : IRxBLService { - public class RxBLServiceChangeSubscriber : ComponentBase where T : IRxBLService - { - [CascadingParameter] - public required T Service { get; init; } + [CascadingParameter] + public required T Service { get; init; } - [Parameter] - public double SampleRateMS { get; set; } = 100; + [Parameter] + public double SampleRateMS { get; set; } = 100; - protected override void OnInitialized() - { - base.OnInitialized(); - Service.Subscribe(cr => ServiceStateHasChanged(cr.ID, cr.Reason), SampleRateMS); - } + protected override void OnInitialized() + { + base.OnInitialized(); + Service.Subscribe(cr => ServiceStateHasChanged(cr.ID, cr.Reason), SampleRateMS); + } - protected virtual void ServiceStateHasChanged(Guid id, ChangeReason changeReason) - { - } + protected virtual void ServiceStateHasChanged(Guid id, ChangeReason changeReason) + { } } diff --git a/RxBlazorLightCore/Core/Interfaces.cs b/RxBlazorLightCore/Core/Interfaces.cs index 27cf771..f8dd4f7 100644 --- a/RxBlazorLightCore/Core/Interfaces.cs +++ b/RxBlazorLightCore/Core/Interfaces.cs @@ -18,7 +18,6 @@ public void EnterScope() { } public void LeaveScope() { } } - public interface IRxBLService { public ValueTask OnContextReadyAsync(); @@ -81,14 +80,18 @@ public interface IStateProvideTransformBase public interface IStateTransformer : IStateProvideTransformBase { public void Transform(T value); + + public bool CanTransform(T value); } public interface IStateProvider : IStateProvideTransformBase { public void Provide(); + + public bool CanProvide(T value); } - public interface IServiceStateProvider : IStateTransformer + public interface IServiceStateTransformer : IStateTransformer { } diff --git a/RxBlazorLightCore/Core/ServiceExtensions.cs b/RxBlazorLightCore/Core/ServiceExtensions.cs index b542d7b..6c5a268 100644 --- a/RxBlazorLightCore/Core/ServiceExtensions.cs +++ b/RxBlazorLightCore/Core/ServiceExtensions.cs @@ -34,7 +34,7 @@ public static class ServiceExtensions return services; } - public static IServiceCollection AddRxBLService(this IServiceCollection services, Func serviceFactory, double sampleMS = 100) where T : RxBLService + public static IServiceCollection AddRxBLService(this IServiceCollection services, Func serviceFactory, double sampleMS = 100) where T : RxBLService { services.TryAddSingleton(); diff --git a/RxBlazorLightCore/Core/State.cs b/RxBlazorLightCore/Core/State.cs index d37aa4d..cbed436 100644 --- a/RxBlazorLightCore/Core/State.cs +++ b/RxBlazorLightCore/Core/State.cs @@ -13,6 +13,11 @@ public class State : IState public bool CanRun => _valueProvider.CanRun; public bool LongRunning => _valueProvider.LongRunning; public bool CanCancel => _valueProvider.CanCancel; + public virtual bool CanTransform(TType _) + { + return _valueProvider.CanRun; + } + public StateChangePhase Phase => _valueProvider.Phase; public Guid ID => _valueProvider.ID; @@ -22,14 +27,14 @@ protected internal State(S service, TType? value, Func { Value = value; _valueProvider = valueProviderFactory is null ? - new StateTransformDirect(service, this) : valueProviderFactory(this); + new StateTransformerDirect(service, this) : valueProviderFactory(this); } protected internal State(S service, TType? value, Func, IStateTransformer>? valueProviderFactory = null) { Value = value; _valueProvider = valueProviderFactory is null ? - new StateTransformDirect(service, this) : valueProviderFactory((IState)this); + new StateTransformerDirect(service, this) : valueProviderFactory((IState)this); } public bool HasValue() @@ -76,7 +81,7 @@ public static IState Create(S service, TType? value, Func, public class State : State, IState where S : RxBLService { - private State(S service) : base (service, IState.Default, null) { } + private State(S service) : base(service, IState.Default, null) { } public static IState Create(S service) { @@ -239,31 +244,46 @@ protected void StateChanged(StateChangePhase phase, Exception? exception = null) } - public class StateTransformDirect(S service, IState state) : + public class StateTransformerDirect(S service, IState state) : StateProvideTransformBase(service, state, true, true), IStateTransformer where S : RxBLService where TType : TInterface { + public virtual bool CanTransform(TType _) + { + return CanRun; + } + public void Transform(TType value) { TransformBaseSync(value); } } - public class StateTransformDirect(S service, IState state) : - StateProvideTransformBase(service, state, true, true), IStateTransformer + public class StateTransformerDirect(S service, IState state) : + StateProvideTransformBase(service, state, true, true), IStateTransformer where S : RxBLService { - public void Transform(TType value) + public virtual bool CanTransform(T _) + { + return CanRun; + } + + public void Transform(T value) { TransformBaseSync(value); } } - public abstract class StateTransformAsync(S service, IState state) : + public abstract class StateTransformerAsync(S service, IState state) : StateProvideTransformBase(service, state, true, true), IStateTransformer where S : RxBLService { + public virtual bool CanTransform(T _) + { + return CanRun; + } + public void Transform(T value) { TransformBaseAsync(value); @@ -282,10 +302,15 @@ public void Transform(T value) protected abstract Task TransformStateAsync(T value, CancellationToken cancellationToken); } - public abstract class StateTransform(S service, IState state) : + public abstract class StateTransformer(S service, IState state) : StateProvideTransformBase(service, state, true, false), IStateTransformer where S : RxBLService { + public virtual bool CanTransform(T _) + { + return CanRun; + } + public void Transform(T value) { try @@ -301,10 +326,15 @@ public void Transform(T value) protected abstract TType? TransformState(T value); } - public abstract class ValueProviderAsync(S service, IState state) : + public abstract class StateProviderAsync(S service, IState state) : StateProvideTransformBase(service, state, true, true), IStateProvider where S : RxBLService { + public virtual bool CanProvide(T _) + { + return CanRun; + } + public void Provide() { TransformBaseAsync(default); @@ -318,10 +348,15 @@ public void Provide() protected abstract Task ProvideValueAsync(CancellationToken cancellationToken); } - public abstract class ValueProvider(S service, IState state) : + public abstract class StateProvider(S service, IState state) : StateProvideTransformBase(service, state, true, false), IStateProvider where S : RxBLService { + public virtual bool CanProvide(T _) + { + return CanRun; + } + public void Provide() { try @@ -337,11 +372,16 @@ public void Provide() protected abstract T ProvideValue(); } - public abstract class StateRefTransformAsync(S service, IState state) : + public abstract class StateRefTransformerAsync(S service, IState state) : StateProvideTransformBase(service, state, false, true), IStateTransformer where S : RxBLService where TType : class, TInterface { + public virtual bool CanTransform(T _) + { + return CanRun; + } + public void Transform(T value) { TransformBaseAsync(value); @@ -362,11 +402,16 @@ public void Transform(T value) protected abstract Task TransformStateAsync(T value, TType stateRef, CancellationToken cancellationToken); } - public abstract class StateRefTransform(S service, IState state) : + public abstract class StateRefTransformer(S service, IState state) : StateProvideTransformBase(service, state, false, false), IStateTransformer where S : RxBLService where TType : class, TInterface { + public virtual bool CanTransform(T _) + { + return CanRun; + } + public void Transform(T value) { ArgumentNullException.ThrowIfNull(State.Value); @@ -384,11 +429,16 @@ public void Transform(T value) protected abstract void TransformState(T value, TType stateRef); } - public abstract class ServiceProviderAsync(S service) : - StateProvideTransformBase(service, null, true, true), IServiceStateProvider + public abstract class ServiceStateTransformerAsync(S service) : + StateProvideTransformBase(service, null, true, true), IServiceStateTransformer where T : notnull where S : RxBLService { + public virtual bool CanTransform(T _) + { + return CanRun; + } + public void Transform(T value) { TransformBaseAsync(value); @@ -408,11 +458,16 @@ public void Transform(T value) protected abstract Task TransformStateAsync(T value, CancellationToken cancellationToken); } - public abstract class ServiceProvider(S service) : - StateProvideTransformBase(service, null, true, false), IServiceStateProvider - where T : notnull - where S : RxBLService + public abstract class ServiceStateTransformer(S service) : + StateProvideTransformBase(service, null, true, false), IServiceStateTransformer + where T : notnull + where S : RxBLService { + public virtual bool CanTransform(T _) + { + return CanRun; + } + public void Transform(T value) { try @@ -429,10 +484,15 @@ public void Transform(T value) protected abstract void TransformState(T value); } - public abstract class ServiceProviderAsync(S service) : + public abstract class ServiceStateProviderAsync(S service) : StateProvideTransformBase(service, null, true, true), IServiceStateProvider where S : RxBLService { + public bool CanProvide(object? _) + { + return CanRun; + } + public void Provide() { TransformBaseAsync(IState.Default); @@ -450,10 +510,15 @@ public void Provide() protected abstract Task ProvideStateAsync(CancellationToken cancellationToken); } - public abstract class ServiceProvider(S service) : + public abstract class ServiceStateProvider(S service) : StateProvideTransformBase(service, null, false, false), IServiceStateProvider where S : RxBLService { + public bool CanProvide(object? _) + { + return CanRun; + } + public void Provide() { try diff --git a/RxBlazorLightCoreTestBase/ServiceFixture.State.cs b/RxBlazorLightCoreTestBase/ServiceFixture.State.cs index eb71634..7639357 100644 --- a/RxBlazorLightCoreTestBase/ServiceFixture.State.cs +++ b/RxBlazorLightCoreTestBase/ServiceFixture.State.cs @@ -1,12 +1,12 @@  using RxBlazorLightCore; -using static RxBlazorLightCoreTestBase.ServiceFixture.IntListVP; +using System.Collections.Generic; namespace RxBlazorLightCoreTestBase { public partial class ServiceFixture { - public class IncremementVP(ServiceFixture service, IState state) : ValueProviderAsync(service, state) + public class IncremementVP(ServiceFixture service, IState state) : StateProviderAsync(service, state) { protected override Task ProvideValueAsync(CancellationToken cancellationToken) { @@ -14,7 +14,7 @@ protected override Task ProvideValueAsync(CancellationToken cancellationTok } } - public class AddVP(ServiceFixture service, IState state) : StateTransformAsync(service, state) + public class AddVP(ServiceFixture service, IState state) : StateTransformerAsync(service, state) { protected override async Task TransformStateAsync(int value, CancellationToken cancellationToken) { @@ -28,7 +28,7 @@ protected override async Task TransformStateAsync(int value, CancellationTo } } - public class AsyncIntX(ServiceFixture service, IState state) : StateTransformAsync(service, state) + public class AsyncIntX(ServiceFixture service, IState state) : StateTransformerAsync(service, state) { protected override async Task TransformStateAsync(int value, CancellationToken cancellationToken) { @@ -37,7 +37,7 @@ protected override async Task TransformStateAsync(int value, CancellationTo } } - public class ChangeTestSP(ServiceFixture service) : ServiceProviderAsync(service) + public class ChangeTestSP(ServiceFixture service) : ServiceStateTransformerAsync(service) { public override bool CanCancel => true; @@ -49,7 +49,7 @@ protected override async Task TransformStateAsync(string? valueIn, CancellationT } } - public class ChangeTestSyncSP(ServiceFixture service) : ServiceProvider(service) + public class ChangeTestSyncSP(ServiceFixture service) : ServiceStateProvider(service) { protected override void ProvideState() { @@ -57,10 +57,10 @@ protected override void ProvideState() } } - public class IntListVP(ServiceFixture service, IState, IList> state) : - StateRefTransformAsync, IList>(service, state) + public class IntListVP(ServiceFixture service, IState, List> state) : + StateRefTransformerAsync, List>(service, state) { - public enum CMD + public enum CMD_LIST { ADD, UPDATE, @@ -68,14 +68,14 @@ public enum CMD CLEAR } - protected override async Task TransformStateAsync((CMD CMD, CRUDTest? ITEM) value, IList stateRef, CancellationToken cancellationToken) + protected override async Task TransformStateAsync((CMD_LIST CMD, CRUDTest? ITEM) value, List stateRef, CancellationToken cancellationToken) { - if (value.CMD is CMD.ADD) + if (value.CMD is CMD_LIST.ADD) { ArgumentNullException.ThrowIfNull(value.ITEM); stateRef.Add(value.ITEM); } - else if (value.CMD is CMD.UPDATE) + else if (value.CMD is CMD_LIST.UPDATE) { ArgumentNullException.ThrowIfNull(value.ITEM); var item = stateRef.Where(i => i.Id == value.ITEM.Id).FirstOrDefault(); @@ -84,12 +84,55 @@ protected override async Task TransformStateAsync((CMD CMD, CRUDTest? ITEM) valu stateRef.Remove(item); stateRef.Add(value.ITEM); } - else if (value.CMD is CMD.DELETE) + else if (value.CMD is CMD_LIST.DELETE) { ArgumentNullException.ThrowIfNull(value.ITEM); stateRef.Remove(value.ITEM); } - else if (value.CMD is CMD.CLEAR) + else if (value.CMD is CMD_LIST.CLEAR) + { + stateRef.Clear(); + } + else + { + throw new ArgumentOutOfRangeException(nameof(value)); + } + + await Task.Delay(5, cancellationToken); + } + } + + public class IntDictVP(ServiceFixture service, IState>, Dictionary> state) : + StateRefTransformerAsync>, Dictionary>(service, state) + { + public enum CMD_DICT + { + ADD, + UPDATE, + DELETE, + CLEAR + } + + protected override async Task TransformStateAsync((CMD_DICT CMD, Guid? ID, CRUDTest? ITEM) value, Dictionary stateRef, CancellationToken cancellationToken) + { + if (value.CMD is CMD_DICT.ADD) + { + ArgumentNullException.ThrowIfNull(value.ITEM); + ArgumentNullException.ThrowIfNull(value.ID); + stateRef.Add(value.ID.Value, value.ITEM); + } + else if (value.CMD is CMD_DICT.UPDATE) + { + ArgumentNullException.ThrowIfNull(value.ITEM); + ArgumentNullException.ThrowIfNull(value.ID); + stateRef[value.ID.Value] = value.ITEM; + } + else if (value.CMD is CMD_DICT.DELETE) + { + ArgumentNullException.ThrowIfNull(value.ID); + stateRef.Remove(value.ID.Value); + } + else if (value.CMD is CMD_DICT.CLEAR) { stateRef.Clear(); } diff --git a/RxBlazorLightCoreTestBase/ServiceFixture.cs b/RxBlazorLightCoreTestBase/ServiceFixture.cs index 1875bc9..b68bcf6 100644 --- a/RxBlazorLightCoreTestBase/ServiceFixture.cs +++ b/RxBlazorLightCoreTestBase/ServiceFixture.cs @@ -1,6 +1,5 @@  using RxBlazorLightCore; -using static RxBlazorLightCoreTestBase.ServiceFixture.IntListVP; namespace RxBlazorLightCoreTestBase { @@ -12,14 +11,16 @@ public partial class ServiceFixture : RxBLService public IState IntStateAsyncX { get; } - public IState, IList> CRUDListState { get; } + public IState, List> CRUDListState { get; } + public IState>, Dictionary> CRUDDictState { get; } public IStateProvider Increment { get; } public IStateTransformer Add { get; } - public IServiceStateProvider ChangeTest { get; } + public IServiceStateTransformer ChangeTest { get; } public IServiceStateProvider ChangeTestSync { get; } - public IStateTransformer<(CMD CMD, CRUDTest? ITEM)> CRUDListCmds { get; } + public IStateTransformer<(IntListVP.CMD_LIST CMD, CRUDTest? ITEM)> CRUDListCmds { get; } + public IStateTransformer<(IntDictVP.CMD_DICT CMD, Guid? ID, CRUDTest? ITEM)> CRUDDictCmds { get; } public string Test { get; private set; } = string.Empty; @@ -29,9 +30,12 @@ public ServiceFixture() IntStateAsyncX = this.CreateState(10, s => new AsyncIntX(this, s)); - CRUDListState = this.CreateState, IList>(new List()); + CRUDListState = this.CreateState, List>([]); CRUDListCmds = new IntListVP(this, CRUDListState); + CRUDDictState = this.CreateState>, Dictionary>([]); + CRUDDictCmds = new IntDictVP(this, CRUDDictState); + Increment = new IncremementVP(this, IntState); Add = new AddVP(this, IntState); ChangeTest = new ChangeTestSP(this); diff --git a/RxBlazorLightCoreTests/StateTests.cs b/RxBlazorLightCoreTests/StateTests.cs index af452a9..bd35efb 100644 --- a/RxBlazorLightCoreTests/StateTests.cs +++ b/RxBlazorLightCoreTests/StateTests.cs @@ -288,7 +288,7 @@ IDisposable subscribeTest() } var disposable = subscribeTest(); - fixture.CRUDListCmds.Transform((ServiceFixture.IntListVP.CMD.CLEAR, null)); + fixture.CRUDListCmds.Transform((ServiceFixture.IntListVP.CMD_LIST.CLEAR, null)); while (!done) ; disposable.Dispose(); @@ -300,7 +300,7 @@ IDisposable subscribeTest() { Assert.Empty(fixture.CRUDListState.Value); disposable = subscribeTest(); - fixture.CRUDListCmds.Transform((ServiceFixture.IntListVP.CMD.ADD, new CRUDTest("Item1", Guid.NewGuid()))); + fixture.CRUDListCmds.Transform((ServiceFixture.IntListVP.CMD_LIST.ADD, new CRUDTest("Item1", Guid.NewGuid()))); while (!done) ; disposable.Dispose(); @@ -309,7 +309,7 @@ IDisposable subscribeTest() Assert.True(stateChangeCount > 0 && stateChangeCount <= 2); disposable = subscribeTest(); - fixture.CRUDListCmds.Transform((ServiceFixture.IntListVP.CMD.ADD, new CRUDTest("Item2", Guid.NewGuid()))); + fixture.CRUDListCmds.Transform((ServiceFixture.IntListVP.CMD_LIST.ADD, new CRUDTest("Item2", Guid.NewGuid()))); while (!done) ; disposable.Dispose(); @@ -321,7 +321,7 @@ IDisposable subscribeTest() var updateItem = lastItem with { Item = "Item3" }; disposable = subscribeTest(); - fixture.CRUDListCmds.Transform((ServiceFixture.IntListVP.CMD.UPDATE, updateItem)); + fixture.CRUDListCmds.Transform((ServiceFixture.IntListVP.CMD_LIST.UPDATE, updateItem)); while (!done) ; disposable.Dispose(); @@ -330,7 +330,7 @@ IDisposable subscribeTest() Assert.True(stateChangeCount > 0 && stateChangeCount <= 2); disposable = subscribeTest(); - fixture.CRUDListCmds.Transform((ServiceFixture.IntListVP.CMD.DELETE, updateItem)); + fixture.CRUDListCmds.Transform((ServiceFixture.IntListVP.CMD_LIST.DELETE, updateItem)); while (!done) ; disposable.Dispose(); @@ -338,7 +338,7 @@ IDisposable subscribeTest() Assert.True(stateChangeCount > 0 && stateChangeCount <= 2); disposable = subscribeTest(); - fixture.CRUDListCmds.Transform((ServiceFixture.IntListVP.CMD.CLEAR, null)); + fixture.CRUDListCmds.Transform((ServiceFixture.IntListVP.CMD_LIST.CLEAR, null)); while (!done) ; disposable.Dispose(); @@ -346,5 +346,95 @@ IDisposable subscribeTest() Assert.True(stateChangeCount > 0 && stateChangeCount <= 2); } } + + [Fact] + public void TestCRUDDict() + { + ServiceFixture fixture = new(); + var stateChangeCount = 0; + var done = false; + + IDisposable subscribeTest() + { + done = false; + stateChangeCount = 0; + + return fixture.Subscribe(sc => + { + if (!done && sc.ID == fixture.CRUDDictCmds.ID) + { + stateChangeCount++; + } + + _output.WriteLine($"Done {fixture.CRUDDictCmds.Done()}, CC {stateChangeCount} Reason {sc.Reason}, Phase {fixture.CRUDDictCmds.Phase}, ID {sc.ID}, VPID {fixture.CRUDDictCmds.ID}"); + + if (fixture.CRUDDictCmds.Done()) + { + done = true; + } + }, 0); + } + + var disposable = subscribeTest(); + fixture.CRUDDictCmds.Transform((ServiceFixture.IntDictVP.CMD_DICT.CLEAR, default, null)); + while (!done) ; + disposable.Dispose(); + + Assert.True(fixture.CRUDDictState.HasValue()); + Assert.True(stateChangeCount > 0 && stateChangeCount <= 2); + disposable.Dispose(); + + if (fixture.CRUDDictState.HasValue()) + { + Assert.Empty(fixture.CRUDDictState.Value); + disposable = subscribeTest(); + var addGuid1 = Guid.NewGuid(); + fixture.CRUDDictCmds.Transform((ServiceFixture.IntDictVP.CMD_DICT.ADD, addGuid1, new CRUDTest("Item1", addGuid1))); + while (!done) ; + disposable.Dispose(); + + Assert.Single(fixture.CRUDDictState.Value); + Assert.Equal("Item1", fixture.CRUDDictState.Value.Last().Value.Item); + Assert.True(stateChangeCount > 0 && stateChangeCount <= 2); + + disposable = subscribeTest(); + var addGuid2 = Guid.NewGuid(); + fixture.CRUDDictCmds.Transform((ServiceFixture.IntDictVP.CMD_DICT.ADD, addGuid2, new CRUDTest("Item2", addGuid2))); + while (!done) ; + disposable.Dispose(); + + Assert.Equal(2, fixture.CRUDDictState.Value.Count()); + Assert.Equal("Item2", fixture.CRUDDictState.Value.Last().Value.Item); + Assert.True(stateChangeCount > 0 && stateChangeCount <= 2); + + var lastItem = fixture.CRUDDictState.Value.Last().Value; + var updateItem = lastItem with { Item = "Item3" }; + + disposable = subscribeTest(); + fixture.CRUDDictCmds.Transform((ServiceFixture.IntDictVP.CMD_DICT.UPDATE, updateItem.Id, updateItem)); + while (!done) ; + disposable.Dispose(); + + Assert.Equal(2, fixture.CRUDDictState.Value.Count()); + Assert.Equal("Item3", fixture.CRUDDictState.Value.Last().Value.Item); + Assert.True(stateChangeCount > 0 && stateChangeCount <= 2); + + disposable = subscribeTest(); + fixture.CRUDDictCmds.Transform((ServiceFixture.IntDictVP.CMD_DICT.DELETE, updateItem.Id, null)); + while (!done) ; + disposable.Dispose(); + + Assert.Single(fixture.CRUDDictState.Value); + Assert.True(stateChangeCount > 0 && stateChangeCount <= 2); + + disposable = subscribeTest(); + fixture.CRUDDictCmds.Transform((ServiceFixture.IntDictVP.CMD_DICT.CLEAR, default, null)); + while (!done) ; + disposable.Dispose(); + + Assert.Empty(fixture.CRUDDictState.Value); + Assert.True(stateChangeCount > 0 && stateChangeCount <= 2); + } + } } } \ No newline at end of file diff --git a/RxMudBlazorLight/ButtonBase/ButtonPRx.cs b/RxMudBlazorLight/ButtonBase/ButtonPRx.cs index 66ad22a..432ed1f 100644 --- a/RxMudBlazorLight/ButtonBase/ButtonPRx.cs +++ b/RxMudBlazorLight/ButtonBase/ButtonPRx.cs @@ -12,18 +12,20 @@ internal class ButtonPRx : ButtonBaseRx public EventCallback? OnTouch { get; private set; } private readonly Func, Task> _valueFactoryAsync; + private readonly Func? _disabledFactory; private ButtonPRx(MBButtonType type, Func, Task> valueFactoryAsync, Color buttonColor, - RenderFragment? buttonChildContent, string? cancelText, Color? cancelColor) : + RenderFragment? buttonChildContent, string? cancelText, Color? cancelColor, Func? disabledFactory) : base(type, buttonColor, buttonChildContent, cancelText, cancelColor) { _valueFactoryAsync = valueFactoryAsync; + _disabledFactory = disabledFactory; } public static ButtonPRx Create(MBButtonType type, Func, Task> valueFactoryAsync, Color buttonColor, - RenderFragment ? buttonChildContent = null, string? cancelText = null, Color? cancelColor = null) + RenderFragment ? buttonChildContent = null, string? cancelText = null, Color? cancelColor = null, Func? disabledFactory = null) { - return new ButtonPRx(type, valueFactoryAsync, buttonColor, buttonChildContent, cancelText, cancelColor); + return new ButtonPRx(type, valueFactoryAsync, buttonColor, buttonChildContent, cancelText, cancelColor, disabledFactory); } [MemberNotNull(nameof(OnClick))] @@ -54,14 +56,14 @@ public void SetParameter(IStateTransformer stateTransformer) ChildContent = stateTransformer.Changing() && stateTransformer.LongRunning ? RenderProgress() : _buttonChildContent; } - OnClick = EventCallback.Factory.Create(this, () => ExecuteValueProvider(stateTransformer)); - OnTouch = EventCallback.Factory.Create(this, () => ExecuteValueProvider(stateTransformer)); + OnClick = EventCallback.Factory.Create(this, () => ExecuteStateProvider(stateTransformer)); + OnTouch = EventCallback.Factory.Create(this, () => ExecuteStateProvider(stateTransformer)); - Disabled = !stateTransformer.CanRun; + Disabled = _disabledFactory is null ? !stateTransformer.CanRun : _disabledFactory(); } } - private async Task ExecuteValueProvider(IStateTransformer stateTransformer) + private async Task ExecuteStateProvider(IStateTransformer stateTransformer) { await _valueFactoryAsync(stateTransformer); } diff --git a/RxMudBlazorLight/ButtonBase/ButtonRx.cs b/RxMudBlazorLight/ButtonBase/ButtonRx.cs index 5dd96f9..e0238a6 100644 --- a/RxMudBlazorLight/ButtonBase/ButtonRx.cs +++ b/RxMudBlazorLight/ButtonBase/ButtonRx.cs @@ -12,18 +12,20 @@ internal class ButtonRx : ButtonBaseRx public EventCallback? OnTouch { get; private set; } private readonly Func>? _confirmExecutionAsync; + private readonly Func? _disabledFactory; - private ButtonRx(MBButtonType type, Func>? confirmExecutionAsync, Color buttonColor, - RenderFragment? buttonChildContent, string? cancelText, Color? cancelColor) : + private ButtonRx(MBButtonType type, Func>? confirmExecutionAsync, Color buttonColor, + RenderFragment? buttonChildContent, string? cancelText, Color? cancelColor, Func? disabledFactory) : base(type, buttonColor, buttonChildContent, cancelText, cancelColor) { _confirmExecutionAsync = confirmExecutionAsync; + _disabledFactory = disabledFactory; } public static ButtonRx Create(MBButtonType type, Func>? confirmExecutionAsync, Color buttonColor, - RenderFragment? buttonChildContent = null, string? cancelText = null, Color? cancelColor = null) + RenderFragment? buttonChildContent = null, string? cancelText = null, Color? cancelColor = null, Func? disabledFactory = null) { - return new ButtonRx(type, confirmExecutionAsync, buttonColor, buttonChildContent, cancelText, cancelColor); + return new ButtonRx(type, confirmExecutionAsync, buttonColor, buttonChildContent, cancelText, cancelColor, disabledFactory); } [MemberNotNull(nameof(OnClick))] @@ -54,14 +56,14 @@ public void SetParameter(IStateProvider stateProvider) ChildContent = stateProvider.Changing() && stateProvider.LongRunning ? RenderProgress() : _buttonChildContent; } - OnClick = EventCallback.Factory.Create(this, () => ExecuteValueProvider(stateProvider)); - OnTouch = EventCallback.Factory.Create(this, () => ExecuteValueProvider(stateProvider)); + OnClick = EventCallback.Factory.Create(this, () => ExecuteStateProvider(stateProvider)); + OnTouch = EventCallback.Factory.Create(this, () => ExecuteStateProvider(stateProvider)); - Disabled = !stateProvider.CanRun; + Disabled = _disabledFactory is null ? !stateProvider.CanRun : _disabledFactory(); } } - private async Task ExecuteValueProvider(IStateProvider stateProvider) + private async Task ExecuteStateProvider(IStateProvider stateProvider) { if (_confirmExecutionAsync is null || await _confirmExecutionAsync()) { diff --git a/RxMudBlazorLight/Buttons/MudButtonPRx.razor b/RxMudBlazorLight/Buttons/MudButtonPRx.razor index ec33afa..b76007e 100644 --- a/RxMudBlazorLight/Buttons/MudButtonPRx.razor +++ b/RxMudBlazorLight/Buttons/MudButtonPRx.razor @@ -16,13 +16,16 @@ [Parameter] public Color? CancelColor { get; set; } + [Parameter] + public Func? DisabledFactory { get; set; } + private RenderFragment RenderBase() => builder => base.BuildRenderTree(builder); private ButtonPRx? _buttonPRx; private Color _buttonColor; protected override void OnInitialized() { - _buttonPRx = ButtonPRx.Create(MBButtonType.DEFAULT, ValueFactoryAsync, Color, ChildContent, CancelText, CancelColor); + _buttonPRx = ButtonPRx.Create(MBButtonType.DEFAULT, ValueFactoryAsync, Color, ChildContent, CancelText, CancelColor, DisabledFactory); _buttonColor = Color; base.OnInitialized(); diff --git a/RxMudBlazorLight/Buttons/MudButtonRx.razor b/RxMudBlazorLight/Buttons/MudButtonRx.razor index afa08f6..7e010c7 100644 --- a/RxMudBlazorLight/Buttons/MudButtonRx.razor +++ b/RxMudBlazorLight/Buttons/MudButtonRx.razor @@ -16,13 +16,16 @@ [Parameter] public Color? CancelColor { get; set; } + [Parameter] + public Func? DisabledFactory { get; set; } + private RenderFragment RenderBase() => builder => base.BuildRenderTree(builder); private ButtonRx? _buttonRx; private Color _buttonColor; protected override void OnInitialized() { - _buttonRx = ButtonRx.Create(MBButtonType.DEFAULT, ConfirmExecutionAsync, Color, ChildContent, CancelText, CancelColor); + _buttonRx = ButtonRx.Create(MBButtonType.DEFAULT, ConfirmExecutionAsync, Color, ChildContent, CancelText, CancelColor, DisabledFactory); _buttonColor = Color; base.OnInitialized(); diff --git a/RxMudBlazorLight/Dialogs/DialogAsyncPRx.razor b/RxMudBlazorLight/Dialogs/DialogAsyncPRx.razor index 3efdcdc..ba393e7 100644 --- a/RxMudBlazorLight/Dialogs/DialogAsyncPRx.razor +++ b/RxMudBlazorLight/Dialogs/DialogAsyncPRx.razor @@ -11,7 +11,7 @@ @CancelButton + CancelColor=@CancelColor CancelText=@CancelText DisabledFactory=@DisabledFactory> @ConfirmButton diff --git a/RxMudBlazorLight/Dialogs/DialogAsyncPRx.razor.cs b/RxMudBlazorLight/Dialogs/DialogAsyncPRx.razor.cs index 5e3a606..a3c2b0c 100644 --- a/RxMudBlazorLight/Dialogs/DialogAsyncPRx.razor.cs +++ b/RxMudBlazorLight/Dialogs/DialogAsyncPRx.razor.cs @@ -34,6 +34,9 @@ public partial class DialogAsyncPRx : RxBLServiceChangeSubscri [Parameter] public Color? CancelColor { get; set; } + [Parameter] + public Func? DisabledFactory { get; set; } + private MudButtonPRx? _buttonRef; private IDisposable? _buttonDisposable; private bool _canceled = false; @@ -41,18 +44,19 @@ public partial class DialogAsyncPRx : RxBLServiceChangeSubscri public static async Task Show(IDialogService dialogService, IStateTransformer stateTransformer, Func, Task> valueFactoryAsync, string title, string message, string confirmButton, string cancelButton, bool successOnConfirm, - string? cancelText = null, Color? cancelColor = null) + string? cancelText = null, Color? cancelColor = null, Func ? disabledFactory = null) { var parameters = new DialogParameters { ["StateTransformer"] = stateTransformer, ["ValueFactoryAsync"] = valueFactoryAsync, + ["CancelText"] = cancelText, + ["CancelColor"] = cancelColor, + ["DisabledFactory"] = disabledFactory, ["Message"] = message, ["ConfirmButton"] = confirmButton, ["CancelButton"] = cancelButton, - ["SuccessOnConfirm"] = successOnConfirm, - ["CancelColor"] = cancelColor, - ["CancelText"] = cancelText + ["SuccessOnConfirm"] = successOnConfirm }; var dialog = dialogService.Show>(title, parameters); diff --git a/RxMudBlazorLight/Dialogs/DialogAsyncRx.razor b/RxMudBlazorLight/Dialogs/DialogAsyncRx.razor index 469caa9..3bf9ce1 100644 --- a/RxMudBlazorLight/Dialogs/DialogAsyncRx.razor +++ b/RxMudBlazorLight/Dialogs/DialogAsyncRx.razor @@ -10,8 +10,7 @@ Cancel + StateProvider=@StateProvider CancelColor=@CancelColor CancelText=@CancelText DisabledFactory=@DisabledFactory> @ConfirmButton diff --git a/RxMudBlazorLight/Dialogs/DialogAsyncRx.razor.cs b/RxMudBlazorLight/Dialogs/DialogAsyncRx.razor.cs index d055a87..afd84d7 100644 --- a/RxMudBlazorLight/Dialogs/DialogAsyncRx.razor.cs +++ b/RxMudBlazorLight/Dialogs/DialogAsyncRx.razor.cs @@ -25,18 +25,15 @@ public partial class DialogAsyncRx : RxBLServiceChangeSubscrib [Parameter, EditorRequired] public required IStateProvider StateProvider { get; init; } - [Parameter] - public Action? BeforeExecution { get; set; } - - [Parameter] - public Action? AfterExecution { get; set; } - [Parameter] public string? CancelText { get; set; } [Parameter] public Color? CancelColor { get; set; } + [Parameter] + public Func? DisabledFactory { get; set; } + private MudButtonRx? _buttonRef; private IDisposable? _buttonDisposable; private bool _canceled = false; @@ -44,17 +41,18 @@ public partial class DialogAsyncRx : RxBLServiceChangeSubscrib public static async Task Show(IDialogService dialogService, IStateProvider stateProvider, string title, string message, string confirmButton, string cancelButton, bool successOnConfirm, - string? cancelText = null, Color? cancelColor = null) + string? cancelText = null, Color? cancelColor = null, Func? disabledFactory = null) { var parameters = new DialogParameters { ["StateProvider"] = stateProvider, + ["CancelColor"] = cancelColor, + ["CancelText"] = cancelText, + ["DisabledFactory"] = disabledFactory, ["Message"] = message, ["ConfirmButton"] = confirmButton, ["CancelButton"] = cancelButton, - ["SuccessOnConfirm"] = successOnConfirm, - ["CancelColor"] = cancelColor, - ["CancelText"] = cancelText + ["SuccessOnConfirm"] = successOnConfirm }; var dialog = dialogService.Show>(title, parameters); diff --git a/RxMudBlazorLight/FabButtons/MudFabPRx.razor b/RxMudBlazorLight/FabButtons/MudFabPRx.razor index 4a0d13c..9af6eb2 100644 --- a/RxMudBlazorLight/FabButtons/MudFabPRx.razor +++ b/RxMudBlazorLight/FabButtons/MudFabPRx.razor @@ -19,6 +19,9 @@ [Parameter] public Color? CancelColor { get; set; } + [Parameter] + public Func? DisabledFactory { get; set; } + [Parameter] public MBIconVariant? IconVariant { get; set; } @@ -28,7 +31,7 @@ protected override void OnInitialized() { - _buttonPRx = ButtonPRx.Create(MBButtonType.FAB, ValueFactoryAsync, Color, null, CancelText, CancelColor); + _buttonPRx = ButtonPRx.Create(MBButtonType.FAB, ValueFactoryAsync, Color, null, CancelText, CancelColor, DisabledFactory); base.OnInitialized(); } diff --git a/RxMudBlazorLight/FabButtons/MudFabRx.razor b/RxMudBlazorLight/FabButtons/MudFabRx.razor index a290ea3..52a40bd 100644 --- a/RxMudBlazorLight/FabButtons/MudFabRx.razor +++ b/RxMudBlazorLight/FabButtons/MudFabRx.razor @@ -19,6 +19,9 @@ [Parameter] public Color? CancelColor { get; set; } + [Parameter] + public Func? DisabledFactory { get; set; } + [Parameter] public MBIconVariant? IconVariant { get; set; } @@ -27,7 +30,7 @@ protected override void OnInitialized() { - _buttonRx = ButtonRx.Create(MBButtonType.FAB, ConfirmExecutionAsync, Color, null, CancelText, CancelColor); + _buttonRx = ButtonRx.Create(MBButtonType.FAB, ConfirmExecutionAsync, Color, null, CancelText, CancelColor, DisabledFactory); base.OnInitialized(); } diff --git a/RxMudBlazorLight/IconButtons/MudIconButtonPRx.razor b/RxMudBlazorLight/IconButtons/MudIconButtonPRx.razor index f3d1067..241e871 100644 --- a/RxMudBlazorLight/IconButtons/MudIconButtonPRx.razor +++ b/RxMudBlazorLight/IconButtons/MudIconButtonPRx.razor @@ -16,12 +16,15 @@ [Parameter] public MBIconVariant? IconVariant { get; set; } + [Parameter] + public Func? DisabledFactory { get; set; } + private RenderFragment RenderBase() => builder => base.BuildRenderTree(builder); private ButtonPRx? _buttonPRx; protected override void OnInitialized() { - _buttonPRx = ButtonPRx.Create(MBButtonType.ICON, ValueFactoryAsync, Color); + _buttonPRx = ButtonPRx.Create(MBButtonType.ICON, ValueFactoryAsync, Color, null, null, null, DisabledFactory); base.OnInitialized(); } diff --git a/RxMudBlazorLight/IconButtons/MudIconButtonRx.razor b/RxMudBlazorLight/IconButtons/MudIconButtonRx.razor index e582a8a..366c965 100644 --- a/RxMudBlazorLight/IconButtons/MudIconButtonRx.razor +++ b/RxMudBlazorLight/IconButtons/MudIconButtonRx.razor @@ -16,12 +16,15 @@ [Parameter] public MBIconVariant? IconVariant { get; set; } + [Parameter] + public Func? DisabledFactory { get; set; } + private RenderFragment RenderBase() => builder => base.BuildRenderTree(builder); private ButtonRx? _buttonRx; protected override void OnInitialized() { - _buttonRx = ButtonRx.Create(MBButtonType.ICON, ConfirmExecutionAsync, Color); + _buttonRx = ButtonRx.Create(MBButtonType.ICON, ConfirmExecutionAsync, Color, null, null, null, DisabledFactory); base.OnInitialized(); } diff --git a/RxMudBlazorLight/Menus/MudMenuItemPRx.razor b/RxMudBlazorLight/Menus/MudMenuItemPRx.razor index b8e796c..304dd3e 100644 --- a/RxMudBlazorLight/Menus/MudMenuItemPRx.razor +++ b/RxMudBlazorLight/Menus/MudMenuItemPRx.razor @@ -10,12 +10,15 @@ [Parameter, EditorRequired] public required Func, Task> ValueFactoryAsync { get; init; } + [Parameter] + public Func? DisabledFactory { get; set; } + private RenderFragment RenderBase() => builder => base.BuildRenderTree(builder); private ButtonPRx? _buttonPRx; protected override void OnInitialized() { - _buttonPRx = ButtonPRx.Create(MBButtonType.DEFAULT, ValueFactoryAsync, Color.Default); + _buttonPRx = ButtonPRx.Create(MBButtonType.DEFAULT, ValueFactoryAsync, Color.Default, null, null, null, DisabledFactory); base.OnInitialized(); } diff --git a/RxMudBlazorLight/Menus/MudMenuItemRx.razor b/RxMudBlazorLight/Menus/MudMenuItemRx.razor index d530c36..b638d10 100644 --- a/RxMudBlazorLight/Menus/MudMenuItemRx.razor +++ b/RxMudBlazorLight/Menus/MudMenuItemRx.razor @@ -10,12 +10,15 @@ [Parameter] public Func>? ConfirmExecutionAsync { get; init; } + [Parameter] + public Func? DisabledFactory { get; set; } + private RenderFragment RenderBase() => builder => base.BuildRenderTree(builder); private ButtonRx? _buttonRx; protected override void OnInitialized() { - _buttonRx = ButtonRx.Create(MBButtonType.DEFAULT, ConfirmExecutionAsync, Color.Default); + _buttonRx = ButtonRx.Create(MBButtonType.DEFAULT, ConfirmExecutionAsync, Color.Default, null, null, null, DisabledFactory); base.OnInitialized(); } diff --git a/RxMudBlazorLight/RxMudBlazorLight.csproj b/RxMudBlazorLight/RxMudBlazorLight.csproj index 5586c18..5a3256d 100644 --- a/RxMudBlazorLight/RxMudBlazorLight.csproj +++ b/RxMudBlazorLight/RxMudBlazorLight.csproj @@ -20,7 +20,7 @@ Blazor,MudBlazor,Rx,Reactive true ..\Nuget - 0.7.9 + 0.9.0 diff --git a/RxMudBlazorLightTestBase/Components/ButtonTest.razor b/RxMudBlazorLightTestBase/Components/ButtonTest.razor index 98aa8c5..c610795 100644 --- a/RxMudBlazorLightTestBase/Components/ButtonTest.razor +++ b/RxMudBlazorLightTestBase/Components/ButtonTest.razor @@ -14,7 +14,7 @@ Increment Add 5 - IncrementAsync + Service.IncrementAsync.CanProvide(4))>IncrementAsync AddAsync 2 @@ -116,12 +116,10 @@ var res = await dialog.Result; - if (res.Canceled) + if (!res.Canceled) { - return; + st.Transform(value); } - - st.Transform(value); } private async Task CmdDialogClick(int? parameter = null) @@ -129,11 +127,11 @@ if (parameter is null) { return await DialogAsyncRx.Show(DialogService, Service.IncrementAsync, - "Increment", "Increment counter.", "Increment", "Cancel", false); + "Increment", "Increment counter.", "Increment", "Cancel", false, null, null, () => Service.CountState.Value > 2); } return await DialogAsyncPRx.Show(DialogService, Service.AddAsync, DVFA.Factory((int)parameter), - $"Add {parameter}", $"Add {parameter} to counter?", $"Add {parameter}", "Cancel", true, "Cancel adding!", Color.Error); + $"Add {parameter}", $"Add {parameter} to counter?", $"Add {parameter}", "Cancel", true, "Cancel adding!", Color.Error, () => Service.CountState.Value > 3); } private async Task DoPrepareAddRemoveAsync(IStateTransformer st) diff --git a/RxMudBlazorLightTestBase/Service/TestService.ProvidersTransformers.cs b/RxMudBlazorLightTestBase/Service/TestService.ProvidersTransformers.cs index 23e7b91..3d2a966 100644 --- a/RxMudBlazorLightTestBase/Service/TestService.ProvidersTransformers.cs +++ b/RxMudBlazorLightTestBase/Service/TestService.ProvidersTransformers.cs @@ -5,7 +5,7 @@ namespace RxMudBlazorLightTestBase.Service { public sealed partial class TestService { - public class EqualsTestVP(TestService service) : ServiceProvider(service) + public class EqualsTestVP(TestService service) : ServiceStateProvider(service) { public override bool CanRun => Service._equalTestValue < 1; @@ -15,7 +15,7 @@ protected override void ProvideState() } } - public class EqualsTestSPAsync(TestService service) : ServiceProviderAsync(service) + public class EqualsTestSPAsync(TestService service) : ServiceStateTransformerAsync(service) { public override bool CanRun => Service._equalTestAsyncValue < 2; @@ -26,7 +26,7 @@ protected override async Task TransformStateAsync(int value, CancellationToken c } } - public class ExceptionVP(TestService service, IState state) : ValueProvider(service, state) + public class ExceptionVP(TestService service, IState state) : StateProvider(service, state) { protected override int ProvideValue() { @@ -34,7 +34,7 @@ protected override int ProvideValue() } } - public class IncrementVP(TestService service, IState state) : ValueProvider(service, state) + public class IncrementVP(TestService service, IState state) : StateProvider(service, state) { public override bool CanRun => Service._canIncrement; @@ -44,7 +44,7 @@ protected override int ProvideValue() } } - public class AddSP(TestService service, IState state) : StateTransform(service, state) + public class AddSP(TestService service, IState state) : StateTransformer(service, state) { public override bool CanRun => State.Value > 1; @@ -54,7 +54,7 @@ protected override int TransformState(int value) } } - public class IncrementVPAsync(TestService service, IState state) : ValueProviderAsync(service, state) + public class IncrementVPAsync(TestService service, IState state) : StateProviderAsync(service, state) { public override bool CanRun => Service._canIncrement; @@ -63,9 +63,14 @@ protected override async Task ProvideValueAsync(CancellationToken cancellat await Task.Delay(500, cancellationToken); return State.Value + 1; } + + public override bool CanProvide(int v) + { + return Service.CountState.Value > v; + } } - public class AddSPAsync(TestService service, IState state) : StateTransformAsync(service, state) + public class AddSPAsync(TestService service, IState state) : StateTransformerAsync(service, state) { public override bool CanRun => State.Value > 2; @@ -78,7 +83,7 @@ protected override async Task TransformStateAsync(int value, CancellationTo public override bool LongRunning => true; } - public class AddRemoveAsyncSP(TestService service, IState state) : StateTransformAsync(service, state) + public class AddRemoveAsyncSP(TestService service, IState state) : StateTransformerAsync(service, state) { protected override async Task TransformStateAsync(int value, CancellationToken cancellationToken) { diff --git a/RxMudBlazorLightTestBase/Service/TestService.State.cs b/RxMudBlazorLightTestBase/Service/TestService.State.cs index a533697..961e76e 100644 --- a/RxMudBlazorLightTestBase/Service/TestService.State.cs +++ b/RxMudBlazorLightTestBase/Service/TestService.State.cs @@ -4,7 +4,7 @@ namespace RxMudBlazorLightTestBase.Service { public sealed partial class TestService { - public class IncrementStateVP(TestService service, IState state) : StateTransformAsync(service, state) + public class IncrementStateVP(TestService service, IState state) : StateTransformerAsync(service, state) { protected override async Task TransformStateAsync(int value, CancellationToken cancellationToken) { @@ -18,7 +18,7 @@ protected override async Task TransformStateAsync(int value, CancellationTo public override bool LongRunning => true; } - public class IncrementStateAddVP(TestService service, IState state) : StateTransform(service, state) + public class IncrementStateAddVP(TestService service, IState state) : StateTransformer(service, state) { public override bool CanRun => State.Value > 5; @@ -28,12 +28,12 @@ protected override int TransformState(int value) } } - public class AddModeVP(TestService service, IState state) : StateTransformDirect(service, state) + public class AddModeVP(TestService service, IState state) : StateTransformerDirect(service, state) { public override bool CanRun => !Service.AddAsync.Changing(); } - public class RatingValueVP(TestService service, IState state) : StateTransformDirect(service, state) + public class RatingValueVP(TestService service, IState state) : StateTransformerDirect(service, state) { public override bool CanRun => Service.GetRadio().Value?.Color is ColorEnum.GREEN; } diff --git a/RxMudBlazorLightTestBase/Service/TestService.cs b/RxMudBlazorLightTestBase/Service/TestService.cs index 62f3481..75fedea 100644 --- a/RxMudBlazorLightTestBase/Service/TestService.cs +++ b/RxMudBlazorLightTestBase/Service/TestService.cs @@ -1,5 +1,4 @@ -using Microsoft.AspNetCore.Components.Routing; -using RxBlazorLightCore; +using RxBlazorLightCore; namespace RxMudBlazorLightTestBase.Service { @@ -71,7 +70,7 @@ public void LiveScope() public IStateTransformer AddAsync { get; } public IServiceStateProvider EqualsTest { get; } - public IServiceStateProvider EqualsTestAsync { get; } + public IServiceStateTransformer EqualsTestAsync { get; } public IStateTransformer Add { get; } public IStateProvider IncrementAsync { get; } @@ -94,7 +93,7 @@ public void LiveScope() private int _equalTestValue = 0; private int _equalTestAsyncValue = 0; - public TestService(System.IServiceProvider _) + public TestService(IServiceProvider _) { Console.WriteLine("TestService Create");