Skip to content

Commit

Permalink
Merge pull request #2886 from PrismLibrary/dev/ds/vml-update
Browse files Browse the repository at this point in the history
Move ViewRegistry to Prism.Core
  • Loading branch information
dansiegel committed Jun 13, 2023
2 parents 734ff63 + 3533542 commit 8f217dd
Show file tree
Hide file tree
Showing 21 changed files with 296 additions and 180 deletions.
2 changes: 1 addition & 1 deletion src/Maui/Prism.Maui/Ioc/DialogRegistrationExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Prism.Common;
using Prism.Mvvm;
using Prism.Services;

namespace Prism.Ioc;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Prism.Common;
using Prism.Mvvm;

namespace Prism.Ioc;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Prism.Common;
using Prism.Mvvm;

namespace Prism.Ioc;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Microsoft.Maui.Controls.Compatibility;
using Prism.Common;
using Prism.Mvvm;
using Prism.Regions;
using Prism.Regions.Adapters;
using Prism.Regions.Behaviors;
Expand Down
19 changes: 0 additions & 19 deletions src/Maui/Prism.Maui/Mvvm/IViewRegistry.cs

This file was deleted.

18 changes: 0 additions & 18 deletions src/Maui/Prism.Maui/Mvvm/ViewModelCreationException.cs

This file was deleted.

145 changes: 13 additions & 132 deletions src/Maui/Prism.Maui/Mvvm/ViewRegistryBase.cs
Original file line number Diff line number Diff line change
@@ -1,154 +1,35 @@
using System.Text.RegularExpressions;
using System.Xml.Linq;
using Prism.Common;
using Prism.Ioc;
using Prism.Ioc;
using Prism.Navigation.Xaml;

namespace Prism.Mvvm;

public abstract class ViewRegistryBase : IViewRegistry
public abstract class ViewRegistryBase : ViewRegistryBase<BindableObject>
{
private readonly IEnumerable<ViewRegistration> _registrations;
private readonly ViewType _registryType;

protected ViewRegistryBase(ViewType registryType, IEnumerable<ViewRegistration> registrations)
: base(registryType, registrations)
{
_registrations = registrations;
_registryType = registryType;
}

public IEnumerable<ViewRegistration> Registrations =>
_registrations.Where(x => x.Type == _registryType);

public Type GetViewType(string name) =>
GetRegistration(name)?.View;

public object CreateView(IContainerProvider container, string name)
protected override void Autowire(BindableObject view)
{
try
{
var registration = GetRegistration(name);
if (registration is null)
throw new KeyNotFoundException($"No view with the name '{name}' has been registered");

var view = container.Resolve(registration.View) as BindableObject;
view.SetValue(ViewModelLocator.NavigationNameProperty, registration.Name);

view.SetContainerProvider(container);
ConfigureView(view, container);

if (registration.ViewModel is not null)
view.SetValue(ViewModelLocator.ViewModelProperty, registration.ViewModel);

Autowire(view);
if (view.BindingContext is not null)
return;

return view;
}
catch (KeyNotFoundException)
{
throw;
}
catch (ViewModelCreationException)
{
throw;
}
catch (Exception ex)
{
throw new ViewCreationException(name, _registryType, ex);
}
ViewModelLocator.Autowire(view);
}

private IEnumerable<Type> GetCandidates(Type viewModelType)
protected override void SetContainerProvider(BindableObject view, IContainerProvider container)
{
var names = new List<string>
{
Regex.Replace(viewModelType.Name, @"ViewModel$", string.Empty),
Regex.Replace(viewModelType.Name, @"Model$", string.Empty),
};

if (_registryType == ViewType.Page)
names.Add(Regex.Replace(viewModelType.Name, @"ViewModel$", "Page"));
else if (_registryType == ViewType.Region)
names.Add(Regex.Replace(viewModelType.Name, @"ViewModel$", "Region"));
else if (_registryType == ViewType.Dialog)
names.Add(Regex.Replace(viewModelType.Name, @"ViewModel$", "Dialog"));

names = names.Where(x => !x.EndsWith("PagePage")).ToList();

var namespaces = _registryType switch
{
ViewType.Page => new[]
{
viewModelType.Namespace.Replace("ViewModels", "Views"),
viewModelType.Namespace.Replace("ViewModels", "Pages")
},
ViewType.Region => new[]
{
viewModelType.Namespace.Replace("ViewModels", "Views"),
viewModelType.Namespace.Replace("ViewModels", "Regions")
},
ViewType.Dialog => new[]
{
viewModelType.Namespace.Replace("ViewModels", "Views"),
viewModelType.Namespace.Replace("ViewModels", "Dialogs")
},
_ => new[]
{
viewModelType.Namespace.Replace("ViewModels", "Views"),
}
};

var candidates = namespaces.Select(@namespace => names.Select(name => $"{@namespace}.{name}"))
.SelectMany(x => x)
.Select(x => viewModelType.AssemblyQualifiedName.Replace(viewModelType.FullName, x));
return candidates
.Select(x => Type.GetType(x, false))
.Where(x => x is not null);
view.SetContainerProvider(container);
}

public string GetViewModelNavigationKey(Type viewModelType)
protected override void SetNavigationNameProperty(BindableObject view, string name)
{
var registration = Registrations.LastOrDefault(x => x.ViewModel == viewModelType);
if (registration is not null)
return registration.Name;

var candidates = GetCandidates(viewModelType);
registration = Registrations.LastOrDefault(x => candidates.Any(c => c == x.View));
if (registration is not null)
{
return registration.Name;
}

throw new KeyNotFoundException($"No View with the ViewModel '{viewModelType.Name}' has been registered");
view.SetValue(ViewModelLocator.NavigationNameProperty, name);
}

public IEnumerable<ViewRegistration> ViewsOfType(Type baseType) =>
Registrations.Where(x => x.View == baseType || x.View.IsAssignableTo(baseType));

public bool IsRegistered(string name) =>
GetRegistration(name) is not null;

protected ViewRegistration GetRegistration(string name) =>
Registrations.LastOrDefault(x => x.Name == name);

protected abstract void ConfigureView(BindableObject bindable, IContainerProvider container);

protected void Autowire(BindableObject view)
protected override void SetViewModelProperty(BindableObject view, Type viewModelType)
{
if (view.BindingContext is not null)
return;

ViewModelLocator.Autowire(view);
view.SetValue(ViewModelLocator.ViewModelProperty, viewModelType);
}

//public static Type GetPageType(string name)
//{
// var registrations = _registrations.Where(x => x.Name == name);
// if (!registrations.Any())
// throw new KeyNotFoundException(name);
// if (registrations.Count() > 1)
// throw new InvalidOperationException(string.Format(Resources.MultipleViewsRegisteredForNavigationKey, name, string.Join(", ", registrations.Select(x => x.View.FullName))));

// return registrations.First().View;
//}
}
8 changes: 8 additions & 0 deletions src/Maui/Prism.Maui/PrismAppBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ internal PrismAppBuilder(IContainerExtension containerExtension, MauiAppBuilder
_registrations = new List<Action<IContainerRegistry>>();
_initializations = new List<Action<IContainerProvider>>();

ViewModelCreationException.SetViewNameDelegate(view =>
{
if (view is BindableObject bindable)
return Mvvm.ViewModelLocator.GetNavigationName(bindable);
return $"View is not a BindableObject: '{view.GetType().FullName}";
});

MauiBuilder = builder;
MauiBuilder.ConfigureContainer(new PrismServiceProviderFactory(RegistrationCallback));
MauiBuilder.ConfigureLifecycleEvents(lifecycle =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Prism.Common;
using Prism.Ioc;
using Prism.Ioc.Internals;
using Prism.Mvvm;
using Prism.Properties;

namespace Prism.Regions.Navigation;
Expand Down
3 changes: 1 addition & 2 deletions src/Maui/Prism.Maui/Regions/RegionNavigationRegistry.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using Prism.Common;
using Prism.Ioc;
using Prism.Ioc;
using Prism.Mvvm;

namespace Prism.Regions;
Expand Down
1 change: 1 addition & 0 deletions src/Maui/Prism.Maui/Regions/RegionViewRegistry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Prism.Common;
using Prism.Events;
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Properties;

namespace Prism.Regions;
Expand Down
1 change: 0 additions & 1 deletion src/Maui/Prism.Maui/Services/Dialogs/DialogViewRegistry.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using Prism.Ioc;
using Prism.Mvvm;
using Prism.Common;

namespace Prism.Services;

Expand Down
File renamed without changes.
52 changes: 52 additions & 0 deletions src/Prism.Core/Mvvm/IViewRegistry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using Prism.Ioc;

namespace Prism.Mvvm;

/// <summary>
/// Provides an abstraction layer for ViewRegistration that can be mocked
/// </summary>
public interface IViewRegistry
{
/// <summary>
/// The existing ViewRegistrations
/// </summary>
IEnumerable<ViewRegistration> Registrations { get; }

/// <summary>
/// Creates a view given a specified instance of the Container and a navigation name
/// </summary>
/// <param name="container"></param>
/// <param name="name"></param>
/// <returns></returns>
object CreateView(IContainerProvider container, string name);

/// <summary>
/// Gets the ViewType for a specified navigation name
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
Type GetViewType(string name);

/// <summary>
/// Gets the navigation name for a specified ViewModelType
/// </summary>
/// <param name="viewModelType"></param>
/// <returns></returns>
string GetViewModelNavigationKey(Type viewModelType);

/// <summary>
/// Gets the Registrations where the View is of a given base type
/// </summary>
/// <param name="baseType"></param>
/// <returns></returns>
IEnumerable<ViewRegistration> ViewsOfType(Type baseType);

/// <summary>
/// Confirms whether the given navigation name has been registered
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
bool IsRegistered(string name);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Prism.Common;
using System;

namespace Prism.Mvvm;

Expand Down
24 changes: 24 additions & 0 deletions src/Prism.Core/Mvvm/ViewModelCreationException.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.ComponentModel;

namespace Prism.Mvvm;

public class ViewModelCreationException : Exception

Check warning on line 6 in src/Prism.Core/Mvvm/ViewModelCreationException.cs

View workflow job for this annotation

GitHub Actions / build-prism-maui / Build Prism.Maui

Missing XML comment for publicly visible type or member 'ViewModelCreationException'

Check warning on line 6 in src/Prism.Core/Mvvm/ViewModelCreationException.cs

View workflow job for this annotation

GitHub Actions / build-prism-core / Build Prism.Core

Missing XML comment for publicly visible type or member 'ViewModelCreationException'

Check warning on line 6 in src/Prism.Core/Mvvm/ViewModelCreationException.cs

View workflow job for this annotation

GitHub Actions / build-prism-uno / Build Prism.Uno

Missing XML comment for publicly visible type or member 'ViewModelCreationException'

Check warning on line 6 in src/Prism.Core/Mvvm/ViewModelCreationException.cs

View workflow job for this annotation

GitHub Actions / build-prism-wpf / Build Prism.Wpf

Missing XML comment for publicly visible type or member 'ViewModelCreationException'
{
private static Func<object, string> _viewNameDelegate = null;
private static string GetViewName(object view) => _viewNameDelegate is null ? "Platform not initialized" : _viewNameDelegate(view);

[EditorBrowsable(EditorBrowsableState.Never)]
public static void SetViewNameDelegate(Func<object, string> viewNameDelegate) => _viewNameDelegate = viewNameDelegate;

Check warning on line 12 in src/Prism.Core/Mvvm/ViewModelCreationException.cs

View workflow job for this annotation

GitHub Actions / build-prism-maui / Build Prism.Maui

Missing XML comment for publicly visible type or member 'ViewModelCreationException.SetViewNameDelegate(Func<object, string>)'

Check warning on line 12 in src/Prism.Core/Mvvm/ViewModelCreationException.cs

View workflow job for this annotation

GitHub Actions / build-prism-core / Build Prism.Core

Missing XML comment for publicly visible type or member 'ViewModelCreationException.SetViewNameDelegate(Func<object, string>)'

Check warning on line 12 in src/Prism.Core/Mvvm/ViewModelCreationException.cs

View workflow job for this annotation

GitHub Actions / build-prism-uno / Build Prism.Uno

Missing XML comment for publicly visible type or member 'ViewModelCreationException.SetViewNameDelegate(Func<object, string>)'

Check warning on line 12 in src/Prism.Core/Mvvm/ViewModelCreationException.cs

View workflow job for this annotation

GitHub Actions / build-prism-wpf / Build Prism.Wpf

Missing XML comment for publicly visible type or member 'ViewModelCreationException.SetViewNameDelegate(Func<object, string>)'

public ViewModelCreationException(object view, Exception innerException)

Check warning on line 14 in src/Prism.Core/Mvvm/ViewModelCreationException.cs

View workflow job for this annotation

GitHub Actions / build-prism-maui / Build Prism.Maui

Missing XML comment for publicly visible type or member 'ViewModelCreationException.ViewModelCreationException(object, Exception)'

Check warning on line 14 in src/Prism.Core/Mvvm/ViewModelCreationException.cs

View workflow job for this annotation

GitHub Actions / build-prism-core / Build Prism.Core

Missing XML comment for publicly visible type or member 'ViewModelCreationException.ViewModelCreationException(object, Exception)'

Check warning on line 14 in src/Prism.Core/Mvvm/ViewModelCreationException.cs

View workflow job for this annotation

GitHub Actions / build-prism-uno / Build Prism.Uno

Missing XML comment for publicly visible type or member 'ViewModelCreationException.ViewModelCreationException(object, Exception)'

Check warning on line 14 in src/Prism.Core/Mvvm/ViewModelCreationException.cs

View workflow job for this annotation

GitHub Actions / build-prism-wpf / Build Prism.Wpf

Missing XML comment for publicly visible type or member 'ViewModelCreationException.ViewModelCreationException(object, Exception)'
: base($"Unable to Create ViewModel for '{view.GetType().FullName}'.", innerException)
{
View = view;
ViewName = GetViewName(view);
}

public string ViewName { get; }

public object View { get; }
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Prism.Common;
using System;

namespace Prism.Mvvm;

public record ViewRegistration
{
Expand Down

0 comments on commit 8f217dd

Please sign in to comment.