Skip to content

Commit

Permalink
feat: adding Forced option for ViewModelLocationBehavior
Browse files Browse the repository at this point in the history
  • Loading branch information
dansiegel committed Jan 20, 2024
1 parent 0790176 commit dfefbe3
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 4 deletions.
12 changes: 10 additions & 2 deletions src/Maui/Prism.Maui/Mvvm/ViewModelLocator.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Prism.Mvvm;
namespace Prism.Mvvm;

/// <summary>
/// This class defines the attached property and related change handler that calls the <see cref="ViewModelLocationProvider"/>.
Expand All @@ -9,7 +9,15 @@ public static class ViewModelLocator
/// Instructs Prism whether or not to automatically create an instance of a ViewModel using a convention, and assign the associated View's <see cref="BindableObject.BindingContext"/> to that instance.
/// </summary>
public static readonly BindableProperty AutowireViewModelProperty =
BindableProperty.CreateAttached("AutowireViewModel", typeof(ViewModelLocatorBehavior), typeof(ViewModelLocator), ViewModelLocatorBehavior.Automatic);
BindableProperty.CreateAttached("AutowireViewModel", typeof(ViewModelLocatorBehavior), typeof(ViewModelLocator), ViewModelLocatorBehavior.Automatic, propertyChanged: OnViewModelLocatorBehaviorChanged);

private static void OnViewModelLocatorBehaviorChanged(BindableObject bindable, object oldValue, object newValue)
{
if (newValue is ViewModelLocatorBehavior behavior && behavior == ViewModelLocatorBehavior.Forced)
{
Autowire(bindable);
}
}

internal static readonly BindableProperty ViewModelProperty =
BindableProperty.CreateAttached("ViewModelType",
Expand Down
28 changes: 27 additions & 1 deletion src/Maui/Prism.Maui/Mvvm/ViewModelLocatorBehavior.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
namespace Prism.Mvvm;

/// <summary>
/// Defines the behavior that the <see cref="ViewModelLocator"/> should use.
/// </summary>
public enum ViewModelLocatorBehavior
{
/// <summary>
/// The ViewModel will be lazily loaded by the Page/Region Navigation Services
/// or the DialogService.
/// </summary>
/// <remarks>
/// This is the default and recommended value for the ViewModelLocator. This will
/// allow the View to be fully initialized and ensure that the proper ViewModel is
/// resolved based on the route name.
/// </remarks>
Automatic,
Disabled

/// <summary>
/// This will disable Prism's automatic ViewModel Location
/// </summary>
Disabled,

/// <summary>
/// This is not recommended for most situations
/// </summary>
/// <remarks>
/// This is likely to cause breaks in the Container Scoping. It is recommended that
/// you allow Prism Page/Region Navigation Services or the Dialog Service properly
/// resolve the ViewModel.
/// </remarks>
Forced
}
11 changes: 10 additions & 1 deletion src/Maui/Prism.Maui/Navigation/Xaml/Navigation.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.ComponentModel;
using System.ComponentModel;
using Prism.Common;
using Prism.Navigation.Internals;

Expand Down Expand Up @@ -154,6 +154,15 @@ public static IContainerProvider GetContainerProvider(this BindableObject bindab
{
if (page.Parent is FlyoutPage flyout && flyout.Flyout == page)
return flyout.GetContainerProvider();

if (Mvvm.ViewModelLocator.GetAutowireViewModel(page) == Mvvm.ViewModelLocatorBehavior.Forced)
{
container = ContainerLocator.Container.CreateScope();
var accessor = container.Resolve<IPageAccessor>();
accessor.Page = page;
SetContainerProvider(page, container);
return container;
}
}
else if (bindable is Element element && element.Parent is not null)
return GetContainerProvider(element.Parent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,23 @@ public void PagesInjectScopedInstanceOfIPageAccessor(string uri)
}
}

[Fact]
public async Task ViewModelLocator_Forced_SetsContainer_ResolvedViewModel()
{
var mauiApp = CreateBuilder(prism => prism
.RegisterTypes(c => c.RegisterForNavigation<ForcedView>())
.CreateWindow("ForcedView"))
.Build();
var window = GetWindow(mauiApp);

Assert.IsType<ForcedView>(window.Page);
Assert.IsType<ForcedViewModel>(window.Page.BindingContext);

var viewModel = (ForcedViewModel)window.Page.BindingContext;
Assert.NotNull(viewModel.Page);
Assert.IsType<ForcedView>(viewModel.Page);
}

[Fact]
public async Task AddsPageFromRelativeURI()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using Prism.Common;

namespace Prism.DryIoc.Maui.Tests.Mocks.ViewModels;

internal class ForcedViewModel
{
public ForcedViewModel(IPageAccessor accessor)
{
_accessor = accessor;
}

private readonly IPageAccessor _accessor;

public Page Page => _accessor.Page;
}
9 changes: 9 additions & 0 deletions tests/Maui/Prism.DryIoc.Maui.Tests/Mocks/Views/ForcedView.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Prism.DryIoc.Maui.Tests.Mocks.Views;

internal class ForcedView : ContentPage
{
public ForcedView()
{
ViewModelLocator.SetAutowireViewModel(this, ViewModelLocatorBehavior.Forced);
}
}

0 comments on commit dfefbe3

Please sign in to comment.