【问题标题】:Unable to construct and initialize viewModel无法构造和初始化 viewModel
【发布时间】:2018-06-16 18:51:18
【问题描述】:

我正在开发我的第一个 Xamarin 应用程序。我正在尝试显示我的第一页,但在 base.ViewDidLoad(); 上出现以下错误ViewDidLoad() 中的一行

MvvmCross.Platform.Exceptions.MvxException 已被抛出

无法从定位器 MvxDefaultViewModelLocator 构造和初始化 iManage.ViewModels.LoginViewModel 类型的 ViewModel - 检查 InnerException 了解更多信息

LoginView.cs:

public partial class LoginView : MvxViewController<LoginViewModel>
{
    public LoginView() : base("LoginView", null)
    {
    }

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
        txtUser.Layer.CornerRadius = 15;
        txtPassword.Layer.CornerRadius = 15;
        btnLogin.Layer.CornerRadius = 20;

        var set = this.CreateBindingSet<LoginView, LoginViewModel>();
        set.Bind(txtUser).To(vm => vm.Username);
        set.Bind(txtPassword).To(vm => vm.Password);
        set.Bind(btnLogin).To(vm => vm.LoginCommand);
        //set.Bind(btnLogin).To(vm => vm.AttemptLogin());
        set.Apply();
    }

    public override void DidReceiveMemoryWarning()
    {
        base.DidReceiveMemoryWarning();
        // Release any cached data, images, etc that aren't in use.
    }
}

LoginViewModel.cs:

public class LoginViewModel : BaseViewModel
{
    private readonly ILoginService _loginService;

    private readonly IDialogService _dialogService;

    public LoginViewModel(ILoginService loginService, IDialogService dialogService)
    {
        _loginService = loginService;
        _dialogService = dialogService;

        Username = "TestUser";
        Password = "YouCantSeeMe";
        IsLoading = false;
    }

    private string _username;
    public string Username
    {
        get
        {
            return _username;
        }

        set
        {
            SetProperty(ref _username, value);
            RaisePropertyChanged(() => Username);
        }
    }

    private string _password;
    public string Password
    {
        get
        {
            return _password;
        }

        set
        {
            SetProperty(ref _password, value);
            RaisePropertyChanged(() => Password);
        }
    }

    private bool _isLoading;

    public bool IsLoading
    {
        get
        {
            return _isLoading;
        }

        set
        {
            SetProperty(ref _isLoading, value);
        }
    }

    private IMvxCommand _loginCommand;
    public virtual IMvxCommand LoginCommand
    {
        get
        {
            _loginCommand = _loginCommand ?? new MvxCommand(AttemptLogin, CanExecuteLogin);
            return _loginCommand;
        }
    }

    private void AttemptLogin()
    {
        if (_loginService.Login(Username, Password))
        {
            ShowViewModel<DashboardEmpViewModel>();
        }
        else
        {
            _dialogService.Alert("We were unable to log you in!", "Login Failed", "OK");
        }
    }

    private bool CanExecuteLogin()
    {
        return (!string.IsNullOrEmpty(Username) || !string.IsNullOrWhiteSpace(Username))
               && (!string.IsNullOrEmpty(Password) || !string.IsNullOrWhiteSpace(Password));
    }
}

LoginService.cs:

public class LoginService : ILoginService
{
    /// <summary>Initializes a new instance of the <see cref="LoginService"/> class.</summary>
    public LoginService() // e.g. LoginService(IMyApiClient client)
    {
        // this constructor would most likely contain some form of API Client that performs
        // the message creation, sending and deals with the response from a remote API
    }

    /// <summary>
    /// Gets a value indicating whether the user is authenticated.
    /// </summary>
    public bool IsAuthenticated { get; private set; }

    /// <summary>Gets the error message.</summary>
    /// <value>The error message.</value>
    public string ErrorMessage { get; private set; }

    /// <summary>
    /// Attempts to log the user in using stored credentials if present
    /// </summary>
    /// <returns> <see langword="true"/> if the login is successful, false otherwise </returns>
    public bool Login()
    {
        // get the stored username from previous sessions
        // var username = Settings.UserName;
        // var username = _settingsService.GetValue<string>(Constants.UserNameKey);

        // force return of false just for demo purposes
        IsAuthenticated = false;
        return IsAuthenticated;
    }

    /// <summary>The login method to retrieve OAuth2 access tokens from an API. </summary>
    /// <param name="userName">The user Name (email address) </param>
    /// <param name="password">The users <paramref name="password"/>. </param>
    /// <param name="scope">The required scopes. </param>
    /// <returns>The <see cref="bool"/>. </returns>
    public bool Login(string userName, string password, string scope)
    {
        try
        {
            //IsAuthenticated = _apiClient.ExchangeUserCredentialsForTokens(userName, password, scope);
            return IsAuthenticated;
        }
        catch (ArgumentException argex)
        {
            ErrorMessage = argex.Message;
            IsAuthenticated = false;
            return IsAuthenticated;
        }
    }

    /// <summary>
    /// Logins the specified user name.
    /// </summary>
    /// <param name="userName">Name of the user.</param>
    /// <param name="password">The users password.</param>
    /// <returns></returns>
    public bool Login(string userName, string password)
    {
        // this simply returns true to mock a real login service call
        return true;
    }
}

Setup.cs:

public class Setup : MvxIosSetup
{
    public Setup(IMvxApplicationDelegate applicationDelegate, IMvxIosViewPresenter presenter) : base(applicationDelegate, presenter)
    {

    }

    protected override IMvxApplication CreateApp()
    {
        return new App();
    }
}

我已经使用this url来实现了。

编辑1:

编辑2: 内部异常:

MvvmCross.Platform.Exceptions.MvxException:无法从定位器 MvxDefaultViewModelLocator 构造和初始化 iManage.ViewModels.LoginViewModel 类型的 ViewModel - 检查 InnerException 以获取更多信息 ---> MvvmCross.Platform.Exceptions.MvxException:创建类型的 viewModel 时出现问题LoginViewModel ---> MvvmCross.Platform.Exceptions.MvxIoCResolveException:创建 iManage.ViewModels.LoginViewModel 时无法解析类型为 IDialogService 的参数 dialogService 的参数 在 MvvmCross.Platform.IoC.MvxSimpleIoCContainer.GetIoCParameterValues(System.Type 类型,System.Reflection.ConstructorInfo firstConstructor)[0x00066] 在 :0 在 MvvmCross.Platform.IoC.MvxSimpleIoCContainer.IoCConstruct (System.Type 类型) [0x0002c] 在 :0 在 MvvmCross.Platform.Mvx.IocConstruct (System.Type t) [0x00006] 在 :0 在 MvvmCross.Core.ViewModels.MvxDefaultViewModelLocator.Load (System.Type viewModelType, MvvmCross.Core.ViewModels.IMvxBundle parameterValues, MvvmCross.Core.ViewModels.IMvxBundle savedState) [0x00000] in :0 --- 内部异常堆栈跟踪结束 --- 在 MvvmCross.Core.ViewModels.MvxDefaultViewModelLocator.Load (System.Type viewModelType, MvvmCross.Core.ViewModels.IMvxBundle parameterValues, MvvmCross.Core.ViewModels.IMvxBundle savedState) [0x00029] in :0 在 MvvmCross.Core.ViewModels.MvxViewModelLoader.LoadViewModel (MvvmCross.Core.ViewModels.MvxViewModelRequest 请求,MvvmCross.Core.ViewModels.IMvxBundle savedState)[0x00035] 在:0 --- 内部异常堆栈跟踪结束 --- 在 MvvmCross.Core.ViewModels.MvxViewModelLoader.LoadViewModel (MvvmCross.Core.ViewModels.MvxViewModelRequest 请求,MvvmCross.Core.ViewModels.IMvxBundle savedState)[0x00068] 在:0 在 MvvmCross.iOS.Views.MvxViewControllerExtensionMethods.LoadViewModel (MvvmCross.iOS.Views.IMvxIosView iosView) [0x0005f] 在 :0 在 MvvmCross.Core.Views.MvxViewExtensionMethods.OnViewCreate (MvvmCross.Core.Views.IMvxView 视图,System.Func`1[TResult] viewModelLoader) [0x00012] in :0 在 MvvmCross.iOS.Views.MvxViewControllerExtensionMethods.OnViewCreate (MvvmCross.iOS.Views.IMvxIosView iosView) [0x00001] 在 :0 在 中的 MvvmCross.iOS.Views.MvxViewControllerAdapter.HandleViewDidLoadCalled (System.Object sender, System.EventArgs e) [0x00007]:0 在(包装器委托调用):invoke_void_object_EventArgs(对象,System.EventArgs) 在 MvvmCross.Platform.Core.MvxDelegateExtensionMethods.Raise (System.EventHandler eventHandler, System.Object sender) [0x00003] in :0 在 MvvmCross.Platform.iOS.Views.MvxEventSourceViewController.ViewDidLoad () [0x00006] 在 :0 在 MvvmCross.iOS.Views.MvxViewController.ViewDidLoad () [0x00001] 在 :0 在 iManage.iOS.Views.LoginView.ViewDidLoad () [0x00001] 在 /Users/pankajsachdeva/Projects/iManage/iOS/Views/LoginView.cs:18 at at (wrapper managed-to-native) UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr) 在 /Users/builder/data/lanes/5665/6857dfcc/source/xamarin-macios/src/UIKit 中的 UIKit.UIApplication.Main(System.String[] args,System.IntPtr 主体,System.IntPtr 委托)[0x00005] /UIApplication.cs:79 在 /Users/builder/data/lanes/5665/6857dfcc/source/xamarin-macios/src/UIKit 中的 UIKit.UIApplication.Main (System.String [] args, System.String principalClassName, System.String delegateClassName) [0x00038] /UIApplication.cs:63 在 iManage.iOS.Application.Main (System.String[] args) [0x00001] 在 /Users/pankajsachdeva/Projects/iManage/iOS/Main.cs:17

【问题讨论】:

  • "检查 InnerException 以获取更多信息",我在您的问题中没有看到 InnerException
  • 嗨,Camilo,我应该如何查看 InnerException?很抱歉,我是 Xamarin 的新手。
  • 调试到抛出异常的地方,在调试器中你会看到异常的详细信息,InnerException 属性有实际的错误
  • 我刚刚添加了它的屏幕截图,请检查
  • 鉴于报错信息,您似乎没有在容器中注册IDialogService

标签: c# xamarin mvvm xamarin.ios mvvmcross


【解决方案1】:

您必须在 IoC 容器中注册服务的实现,以便在需要时解决它们。这通常可以在两个地方完成:

对于App.csInitialize 方法中的平台无关服务:

public class App : MvxApplication
{
   public override void Initialize()
   {
      ...
      Mvx.ConstructAndRegisterSingleton<IDialogService,DialogService>();
      ...
   }
}

(注意这应该是默认完成的,因为默认的App类已经包含了一个自动注册所有带有“Service”后缀的类型的块)

对于InitializeFirstChance 方法中平台的Setup.cs 中的平台特定服务,例如对于Windows,它将是:

public class Setup : MvxWindowsSetup
{
   protected override void InitializeFirstChance()
   {
       Mvx.ConstructAndRegisterSingleton<IDialogService,DialogService>();
       base.InitializeFirstChance();
   }
}

我猜DialogService 将取决于平台,所以第二种解决方案会更合适。

您可以使用LazyConstructAndRegisterSingleton 确保仅在第一次实际需要时才创建实例。您也可以使用RegisterType 来注册类型并在每次需要时创建一个新实例。

更多关于 MvvmCross IoC 的信息是available in the documentation

【讨论】:

  • @pankaj 如果这解决了您的问题,请考虑接受答案作为解决方案,以便问题得到解决。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-04
  • 2020-07-12
  • 2012-05-03
  • 2021-12-20
  • 2019-10-07
  • 2021-02-07
  • 1970-01-01
相关资源
最近更新 更多