예제 #1
0
        /// <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);
 }