MvvmCross / MvvmCross-Forms

Support for Xamarin.Forms on MvvmCross: The .NET MVVM framework for cross-platform solutions, including Xamarin.iOS, Xamarin.Android, Windows and Mac.
http://mvvmcross.com
6 stars 2 forks source link

loading views and view models from different assemblies #61

Open raV720 opened 8 years ago

raV720 commented 8 years ago

The problem in details is described here:

http://stackoverflow.com/questions/39044800/mvvmcross-loading-views-and-view-models-from-different-assemblies

Git with source: https://bitbucket.org/equo/mvvmcross_test.git

Expected behavior MVVMCROSS should be able to link View and ViewModel by naming convention.

Actual behavior MVVMCROSS does not link View and ViewModel by naming convention when are in separate assemblies.

Configuration Version: 4.4 Platform: Windows Store (other patforms not tested)

Cheesebaron commented 8 years ago

I believe this is similar to #45

The presenter need to use the registered View Assemblies to look up Views, just like for ViewModels.

raV720 commented 8 years ago

Could you be more specific? As I understand Views and ViewModels are registred via overriding GetViewAssemblies() and GetViewModelAssemblies(). And it is done correctly in provided source https://bitbucket.org/equo/mvvmcross_test.git. Then what is wrong?

Cheesebaron commented 8 years ago

The method in the presenter which locates the View.

raV720 commented 8 years ago

Could you provide some example?

Cheesebaron commented 8 years ago

Put some breakpoints in here and see what is happening https://github.com/MvvmCross/MvvmCross-Forms/blob/master/MvvmCross.Forms.Presenter.Core/MvxFormsPageLoader.cs

raV720 commented 8 years ago
protected virtual Type GetPageType(MvxViewModelRequest request)
{
    if (_viewFinder == null)
        _viewFinder = Mvx.Resolve<IMvxViewsContainer> ();

    try
    {
        return _viewFinder.GetViewType (request.ViewModelType);
    }
    catch(KeyNotFoundException) 
    {
        var pageName = GetPageName(request);
        return request.ViewModelType.GetTypeInfo().Assembly.CreatableTypes()
            .FirstOrDefault(t => t.Name == pageName);
    }
}

The above method (from MvxFormsPageLoader class) assumes that View is in ViewModel assembly. Will it be somehow fixed?

Cheesebaron commented 8 years ago

Yes, when someone rewrites it to get rid of that assumption.

tofutim commented 7 years ago

Would we have to create a way for the user to specify View location?

bruzkovsky commented 7 years ago

Doing it the Mvx-Way, I guess, is to override the CreateViewsContainer method in your Setup.cs:

protected override IMvxAndroidViewsContainer CreateViewsContainer(Context applicationContext)
{
    var viewsContainer = (IMvxViewsContainer) base.CreateViewsContainer(applicationContext);
    var viewModelTypes =
        typeof(MainViewModel).GetTypeInfo().Assembly.CreatableTypes().Where(t => t.Name.EndsWith("ViewModel")).ToDictionary(t => t.Name.Remove(t.Name.LastIndexOf("ViewModel", StringComparison.Ordinal)));
    var viewTypes =
        typeof(MainPage).GetTypeInfo().Assembly.CreatableTypes().Where(t => t.Name.EndsWith("Page")).ToDictionary(t => t.Name.Remove(t.Name.LastIndexOf("Page", StringComparison.Ordinal)));
    foreach (var viewModelTypeAndName in viewModelTypes)
    {
        Type viewType;
        if (viewTypes.TryGetValue(viewModelTypeAndName.Key, out viewType))
            viewsContainer.Add(viewModelTypeAndName.Value, viewType);
    }
    return (IMvxAndroidViewsContainer) viewsContainer;
}

You can also specify your own naming convention here.