/// <summary> /// Adds a <see cref="IDataLoaderTrigger"/> in <see cref="IDataLoaderBuilder.TriggerProviders"/>. /// </summary> /// <typeparam name="TData">The type of data.</typeparam> /// <param name="builder">The <see cref="IDataLoaderBuilder"/> reference.</param> /// <param name="triggerProvider">The new <see cref="IDataLoaderTrigger"/> to add.</param> public static IDataLoaderBuilder <TData> WithTrigger <TData>(this IDataLoaderBuilder <TData> builder, Func <IDataLoader <TData>, IDataLoaderTrigger> triggerProvider) { builder.TriggerProviders.Add(GetTriggerProvider); return(builder); IDataLoaderTrigger GetTriggerProvider(IDataLoader dataLoader) { return(triggerProvider(dataLoader.AsOf <TData>())); } }
/// <inheritdoc cref="IDataLoaderBuilder.LoadMethod"/> public static IDataLoaderBuilder <TData> WithLoadMethod <TData>(this IDataLoaderBuilder <TData> builder, DataLoaderDelegate <TData> loadMethod) { builder.LoadMethod = InnerLoad; return(builder); async Task <object> InnerLoad(CancellationToken ct, IDataLoaderRequest request) { return(await loadMethod(ct, request)); } }
/// <summary> /// Automatically re-evaluates <see cref="IDataLoaderState.IsEmpty"/> when <see cref="INotifyCollectionChanged.CollectionChanged"/> is raised. /// </summary> /// <typeparam name="TData">Any type implementing <see cref="INotifyCollectionChanged"/>.</typeparam> /// <param name="builder">The builder.</param> /// <returns>The original builder.</returns> public static IDataLoaderBuilder <TData> UpdateOnCollectionChanged <TData>( this IDataLoaderBuilder <TData> builder) where TData : INotifyCollectionChanged { return(builder.SubscribeToData <TData>(Subscribe)); IDisposable Subscribe(TData data, IDataLoaderSetter setter) { return(data.SubscribeToCollectionChanged(setter)); } }
/// <summary> /// Subscribes to the data produced by the <see cref="IDataLoader"/> in order to update its state without reloading the <see cref="IDataLoader"/>. /// </summary> /// <remarks> /// This makes sense when <typeparamref name="TData"/> is something observable such as <see cref="INotifyCollectionChanged"/>. /// </remarks> /// <typeparam name="TData">The type of data.</typeparam> /// <param name="builder">The builder.</param> /// <param name="subscribeToData"> /// The method subscribing to the data. /// Use that method to subscribe to events available on <typeparamref name="TData"/> and return an IDisposable that unsubscribes from events. /// Your event handlers should leverage <see cref="IDataLoaderSetter.SetData(object)"/> and <see cref="IDataLoaderSetter.SetError(Exception)"/>. /// </param> /// <returns>The original <paramref name="builder"/>.</returns> public static IDataLoaderBuilder <TData> SubscribeToData <TData>( this IDataLoaderBuilder <TData> builder, Func <TData, IDataLoaderSetter, IDisposable> subscribeToData) { var namePrefix = builder.Name == null ? string.Empty : builder.Name + "."; var trigger = new SubscribeToDataTrigger(namePrefix + nameof(SubscribeToDataTrigger)); var strategy = new SubscribeToDataStrategy(data => subscribeToData((TData)data, trigger)); return(builder .WithTrigger(trigger) .WithStrategy(strategy)); }
/// <summary> /// Tries to subscribe to the data produced by the <see cref="IDataLoader"/> in order to update its state without reloading the <see cref="IDataLoader"/>. /// </summary> /// <remarks> /// This makes sense when <typeparamref name="TData"/> is something observable such as <see cref="INotifyCollectionChanged"/>. /// You should use this method with <see cref="DataLoaderBuilderFactory.DataLoaderBuilderFactory(Func{IDataLoaderBuilder, IDataLoaderBuilder})"/> so that all DataLoaders of <typeparamref name="TData"/> subscribe to their data automatically. /// </remarks> /// <typeparam name="TData">The type of data.</typeparam> /// <param name="builder">The builder.</param> /// <param name="subscribeToData"> /// The method subscribing to the data. /// Use that method to subscribe to events available on <typeparamref name="TData"/> and return an IDisposable that unsubscribes from events. /// Your event handlers should leverage <see cref="IDataLoaderSetter.SetData(object)"/> and <see cref="IDataLoaderSetter.SetError(Exception)"/>. /// </param> /// <returns>The original <paramref name="builder"/>.</returns> public static IDataLoaderBuilder TrySubscribeToData <TData>( this IDataLoaderBuilder builder, Func <TData, IDataLoaderSetter, IDisposable> subscribeToData) { // Early-out 1: The SubscribeToData delegating strategy is already present in the builder. if (builder.DelegatingStrategies.Any(s => s is SubscribeToDataStrategy)) { return(builder); } // Early-out 2: The builder isn't typed. if (builder.DataType == null) { if (typeof(SubscribeToDataExtensions).Log().IsEnabled(LogLevel.Error)) { typeof(SubscribeToDataExtensions).Log().LogError("Can't validate type. Make sure the 'IDataLoaderBuilder.DataType' property is set before calling 'TrySubscribeToData'."); } return(builder); } var dataType = typeof(TData); // Early-out 3: The builder type doesn't match TData. if (!dataType.IsAssignableFrom(builder.DataType)) { // If TData doesn't match the builder type, we don't do anything. return(builder); } var namePrefix = builder.Name == null ? string.Empty : builder.Name + "."; var trigger = new SubscribeToDataTrigger(namePrefix + nameof(SubscribeToDataTrigger)); var strategy = new SubscribeToDataStrategy(data => subscribeToData((TData)data, trigger)); return(builder .WithTrigger(trigger) .WithStrategy(strategy)); }
/// <inheritdoc cref="IDataLoaderBuilder.EmptySelector"/> public static IDataLoaderBuilder <TData> WithEmptySelector <TData>(this IDataLoaderBuilder <TData> builder, Func <IDataLoaderState <TData>, bool> emptySelector) { builder.EmptySelector = emptySelector; return(builder); }
/// <inheritdoc cref="IDataLoaderBuilder.EmptySelector"/> public static IDataLoaderBuilder WithEmptySelector(this IDataLoaderBuilder builder, Func <IDataLoaderState, bool> emptySelector) { builder.EmptySelector = emptySelector; return(builder); }
/// <summary> /// Adds a <see cref="IDataLoaderTrigger"/> in <see cref="IDataLoaderBuilder.TriggerProviders"/>. /// </summary> /// <param name="builder">The <see cref="IDataLoaderBuilder"/> reference.</param> /// <param name="triggerProvider">The new <see cref="IDataLoaderTrigger"/> to add.</param> public static IDataLoaderBuilder WithTrigger(this IDataLoaderBuilder builder, Func <IDataLoader, IDataLoaderTrigger> triggerProvider) { builder.TriggerProviders.Add(triggerProvider); return(builder); }
/// <inheritdoc cref="IDataLoaderBuilder.LoadMethod"/> public static IDataLoaderBuilder WithLoadMethod(this IDataLoaderBuilder builder, DataLoaderDelegate loadMethod) { builder.LoadMethod = loadMethod; return(builder); }