MvvmCross MvxWindowsPage compilation e

2019-02-27 23:39发布

问题:

I am writing a Xamarin.iOS, Xamarin.Android and UWP cross-platform application with the MvvmCross framework.

I am making a LoginPage which has a LoginViewModel. In the Xamarin.iOS, Xamarin.Android projects, the binding of the ViewModel and the View with below works just fine

public class LoginActivity : MvxAppCompatActivity<LoginViewModel> 
public partial class LoginViewController : MvxViewController<LoginViewModel>  

Trying to do the same as above on UWP project, I get some error.

In XAML:

<views:MvxWindowsPage
x:TypeArguments="viewModels:LoginViewModel" x:Class="MyApp.UWP.Views.LoginView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="using:MvvmCross.WindowsUWP.Views"
xmlns:viewModels="using:MyApp.PresentationCore.ViewModels"
mc:Ignorable="d">

And my C# code is

public sealed partial class LoginView : MvxWindowsPage<LoginViewModel>

But I get compilation errors. How can I resolve them?

  • `Unknown member 'TypeArguments' on element 'MvxWindowsPage'
  • The name "LoginViewModel" does not exist in the namespace "using:MyApp.PresentationCore.ViewModels".
  • GenericArguments[0], 'System.Object', on 'MvvmCross.WindowsUWP.Views.MvxWindowsPage`1[TViewModel]' violates the constraint of type 'TViewModel'.

I think the errors are a little ambiguous because at the first error there is no templated version, but the third error is about a template constraint violation.

I know there is an option binding the ViewModel and the View with naming convention or attributes, but I would like to use this strongly typed solution.

回答1:

Unfortunately I believe UWP does not support TypeArguments and subsequently generic types parameters for a base pages. You can check out the Prism GitHub thread where they discuss it. So you will have to go with one of the other registration options.


Mvvmcross offers various alternative approaches for registering your View to a ViewModel. During initialisation of Mvvmcross it will attempt to register your ViewModel to your View using MvxViewModelViewTypeFinder in the following order:

Attribute based registration:

You can add MvxViewFor attribute to your page class.

[MvxViewFor(typeof(FirstViewModel))]
public sealed partial class FirstView : MvxWindowsPage
{
    public FirstView()
    {
        this.InitializeComponent();
    }
}

Concrete type based registration:

You can register your View to your ViewModel by specifying the concrete type of the ViewModel.

public sealed partial class FirstView : MvxWindowsPage
{
    public new FirstViewModel ViewModel => base.ViewModel as FirstViewModel;

    public FirstView()
    {
        this.InitializeComponent();
    }
}

Or in the case of Android and iOS where generic base class can be used:

// Android
public class FirstActivity : MvxAppCompatActivity<FirstViewModel>

// iOS
public class FirstViewController : MvxViewController<FirstViewModel>

Convention based registration:

You can have your view and ViewModel follow the same naming convention and Mvvmcross will map them for you (xxxView and xxxViewModel)

View

public sealed partial class FirstView : MvxWindowsPage
{
    public FirstView()
    {
        this.InitializeComponent();
    }
}

ViewModel

public class FirstViewModel : MvxViewModel