Esempio n. 1
0
        /// <summary>
        /// Gets or creates a <see cref="IDynamicCommand"/> that will be attached to the <paramref name="viewModel"/>.
        /// </summary>
        /// <param name="viewModel">This <see cref="IViewModel"/>.</param>
        /// <param name="name">The command name.</param>
        /// <param name="factory">The command factory.</param>
        /// <param name="configure">The optional function to configure the command builder.</param>
        /// <returns>The attached <see cref="IDynamicCommand"/>. Null is returned if the <see cref="IViewModel"/> is disposed.</returns>
        public static IDynamicCommand GetOrCreateCommand(
            this IViewModel viewModel,
            string name,
            Func <string, IDynamicCommandBuilder> factory,
            Func <IDynamicCommandBuilder, IDynamicCommandBuilder> configure = null
            )
        {
            if (viewModel.IsDisposed)
            {
                return(null);
            }

            if (!viewModel.TryGetDisposable <IDynamicCommand>(name, out var command))
            {
                var builder = factory(name);
                if (configure != null)
                {
                    builder = configure(builder);
                }
                command = builder.Build();

                viewModel.AddDisposable(command.Name, command);
            }

            return(command);
        }
        /// <summary>
        /// Attaches a child <see cref="IViewModel"/> to a parent <see cref="IViewModel"/>.
        /// By being attached, the child will be disposed when the parent is disposed.
        /// Both also share the same <see cref="IViewModelView"/>.
        /// A child can only be attached once to a single <see cref="IViewModel"/>.
        /// </summary>
        /// <typeparam name="TChildViewModel">The type of child viewmodel.</typeparam>
        /// <param name="viewModel">The parent <see cref="IViewModel"/>.</param>
        /// <param name="childViewModel">The child <see cref="IViewModel"/> to attach.</param>
        /// <param name="name">The child ViewModel's name. This defaults to <paramref name="childViewModel"/>.Name when not provided.</param>
        /// <returns>The attached child <see cref="IViewModel"/>.</returns>
        public static TChildViewModel AttachChild <TChildViewModel>(this IViewModel viewModel, TChildViewModel childViewModel, string name = null)
            where TChildViewModel : IViewModel
        {
            if (childViewModel == null)
            {
                throw new ArgumentNullException(nameof(childViewModel));
            }

            name = name ?? childViewModel.Name;

            if (viewModel.TryGetDisposable(name, out var _))
            {
                throw new InvalidOperationException($"A child ViewModel with the name '{name}' is already attached to this ViewModel.");
            }

            viewModel.AddDisposable(name, childViewModel);

            childViewModel.View = viewModel.View;

            var parentViewChangedDisposable = new ParentViewChangedDisposable(viewModel, childViewModel);

            childViewModel.AddDisposable(ParentViewChangedSubscriptionKey, parentViewChangedDisposable);
            childViewModel.AddDisposable(RemoveSelfFromParentSubscriptionKey, new ActionDisposable(() => viewModel.RemoveDisposable(name)));

            return(childViewModel);
        }
        /// <summary>
        /// Gets or creates a property of the specified <paramref name="name"/>.
        /// </summary>
        /// <param name="viewModel">The <see cref="IViewModel"/> owning the property.</param>
        /// <param name="name">The property's name.</param>
        /// <param name="factory">The property factory.</param>
        /// <returns>The <see cref="IDynamicProperty"/> matching the specified <paramref name="name"/>. Null is returned if the <see cref="IViewModel"/> is disposed.</returns>
        public static IDynamicProperty GetOrCreateDynamicProperty(this IViewModel viewModel, string name, Func <string, IDynamicProperty> factory)
        {
            if (viewModel.IsDisposed)
            {
                return(null);
            }

            if (!viewModel.TryGetDisposable <IDynamicProperty>(name, out var property))
            {
                property = factory(name);
                property.ValueChanged += OnDynamicPropertyChanged;

                // We check the same condition twice because it's possible that the factory invocation already added the property.
                // This can happen when the property implements IViewModel and was added using AttachChild.
                if (!viewModel.TryGetDisposable <IDynamicProperty>(name, out var _))
                {
                    viewModel.AddDisposable(name, property);
                }
            }

            return(property);

            void OnDynamicPropertyChanged(IDynamicProperty dynamicProperty)
            {
                viewModel.RaisePropertyChanged(dynamicProperty.Name);
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Gets or creates a <see cref="IDataLoader"/>.
        /// </summary>
        /// <param name="viewModel">The <see cref="IViewModel"/>.</param>
        /// <param name="key">The key holding the <see cref="IDataLoader"/> in the containing <see cref="IViewModel"/>. This also serves as the default name of the <see cref="IDataLoader"/>.</param>
        /// <param name="factory">The <see cref="IDataLoader"/> Factory.</param>
        /// <returns>The <see cref="IDataLoader"/>. Null is returned if the <see cref="IViewModel"/> is disposed.</returns>
        public static IDataLoader GetOrCreateDataLoader(
            this IViewModel viewModel,
            string key,
            Func <string, IDataLoader> factory
            )
        {
            if (viewModel.IsDisposed)
            {
                return(null);
            }

            if (!viewModel.TryGetDisposable <IDataLoader>(key, out var dataLoader))
            {
                dataLoader = factory(key);

                viewModel.AddDisposable(key, dataLoader);
            }

            return(dataLoader);
        }
        /// <summary>
        /// Registers a custom back button handler for this ViewModel.
        /// </summary>
        /// <param name="vm">The ViewModel.</param>
        /// <param name="handle">The async handler method.</param>
        /// <param name="canHandle">The optional canHandle function. When null is provided, the default behavior is applied (canHandle returns true only when the current ViewModel is active in the <see cref="ISectionsNavigator"/>).</param>
        /// <param name="handlerName">The optional name of the handler. When null is provided, the ViewModel type name is used.</param>
        /// <param name="priority">The optional priority. (See <see cref="IBackButtonManager.AddHandler(IBackButtonHandler, int?)"/> for more info.)</param>
        public static void RegisterBackHandler(this IViewModel vm, Func <CancellationToken, Task> handle, Func <bool> canHandle = null, string handlerName = null, int?priority = null)
        {
            vm          = vm ?? throw new ArgumentNullException(nameof(vm));
            handlerName = handlerName ?? vm.GetType().Name;
            handle      = handle ?? throw new ArgumentNullException(nameof(handle));
            canHandle   = canHandle ?? DefaultCanHandle;

            var backButtonManager = vm.GetService <IBackButtonManager>();
            var handler           = new BackButtonHandler(handlerName, canHandle, handle);
            var registration      = backButtonManager.RegisterHandler(handler, priority);

            vm.AddDisposable("BackButtonHandler_" + handlerName, registration);

            bool DefaultCanHandle()
            {
                var navigator = vm.GetService <ISectionsNavigator>();

                // The handler can handle the back only if the associated ViewModel is the one currently active in the navigator.
                return(navigator.GetActiveViewModel() == vm);
            }
        }
Esempio n. 6
0
        public static TDisposable GetOrCreateDisposable <TDisposable>(this IViewModel vm, Func <TDisposable> create, [CallerMemberName] string key = null)
            where TDisposable : IDisposable
        {
            if (vm is null)
            {
                throw new ArgumentNullException(nameof(vm));
            }

            if (create is null)
            {
                throw new ArgumentNullException(nameof(create));
            }

            if (vm.TryGetDisposable(key, out var existingDisposable))
            {
                return((TDisposable)existingDisposable);
            }
            else
            {
                var disposable = create();
                vm.AddDisposable(key, disposable);
                return(disposable);
            }
        }