我想使用mvvmcross中的viewmodels从一个屏幕移动到下一个屏幕,并将一些模型传递给下一个ViewModel。但是我正在崩溃以下:
MvvmCross.Platform.Exceptions.MvxException: Failed to construct and initialize ViewModel for type iManage.ViewModels.LoginViewModel from locator MvxDefaultViewModelLocator - check InnerException for more information ---> MvvmCross.Platform.Exceptions.MvxException: Problem creating viewModel of type LoginViewModel ---> MvvmCross.Platform.Exceptions.MvxIoCResolveException: Failed to resolve parameter for parameter item of type SchoolModel when creating iManage.ViewModels.LoginViewModel at MvvmCross.Platform.IoC.MvxSimpleIoCContainer.GetIoCParameterValues (System.Type type, System.Reflection.ConstructorInfo firstConstructor) [0x00066] in <6adc0d5857264558a9d45778a78ae02a>:0 at MvvmCross.Platform.IoC.MvxSimpleIoCContainer.IoCConstruct (System.Type type) [0x0002c] in <6adc0d5857264558a9d45778a78ae02a>:0 at MvvmCross.Platform.Mvx.IocConstruct (System.Type t) [0x00006] in <6adc0d5857264558a9d45778a78ae02a>:0 at MvvmCross.Core.ViewModels.MvxDefaultViewModelLocator.Load (System.Type viewModelType, MvvmCross.Core.ViewModels.IMvxBundle parameterValues, MvvmCross.Core.ViewModels.IMvxBundle savedState) [0x00000] in :0 --- End of inner exception stack trace --- at MvvmCross.Core.ViewModels.MvxDefaultViewModelLocator.Load (System.Type viewModelType, MvvmCross.Core.ViewModels.IMvxBundle parameterValues, MvvmCross.Core.ViewModels.IMvxBundle savedState) [0x00029] in :0 at MvvmCross.Core.ViewModels.MvxViewModelLoader.LoadViewModel (MvvmCross.Core.ViewModels.MvxViewModelRequest request, MvvmCross.Core.ViewModels.IMvxBundle savedState) [0x00035] in :0 --- End of inner exception stack trace --- at MvvmCross.Core.ViewModels.MvxViewModelLoader.LoadViewModel (MvvmCross.Core.ViewModels.MvxViewModelRequest request, MvvmCross.Core.ViewModels.IMvxBundle savedState) [0x00068] in :0 at MvvmCross.iOS.Views.MvxViewControllerExtensionMethods.LoadViewModel (MvvmCross.iOS.Views.IMvxIosView iosView) [0x0005f] in <6f99728979034e579bc72f6d53e5bc35>:0 at MvvmCross.Core.Views.MvxViewExtensionMethods.OnViewCreate (MvvmCross.Core.Views.IMvxView view, System.Func`1[TResult] viewModelLoader) [0x00012] in :0 at MvvmCross.iOS.Views.MvxViewControllerExtensionMethods.OnViewCreate (MvvmCross.iOS.Views.IMvxIosView iosView) [0x00001] in <6f99728979034e579bc72f6d53e5bc35>:0 at MvvmCross.iOS.Views.MvxViewControllerAdapter.HandleViewDidLoadCalled (System.Object sender, System.EventArgs e) [0x00007] in <6f99728979034e579bc72f6d53e5bc35>:0 at at (wrapper delegate-invoke) :invoke_void_object_EventArgs (object,System.EventArgs) at MvvmCross.Platform.Core.MvxDelegateExtensionMethods.Raise (System.EventHandler eventHandler, System.Object sender) [0x00003] in <6adc0d5857264558a9d45778a78ae02a>:0 at MvvmCross.Platform.iOS.Views.MvxEventSourceViewController.ViewDidLoad () [0x00006] in <4467c42ffcc4478e847227b8e4af47fe>:0 at MvvmCross.iOS.Views.MvxViewController.ViewDidLoad () [0x00001] in <6f99728979034e579bc72f6d53e5bc35>:0 at iManage.iOS.Views.LoginView.ViewDidLoad () [0x00001] in /Users/pankajsachdeva/Projects/iManage/iOS/Views/LoginView.cs:18 at at (wrapper managed-to-native) UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr) at UIKit.UIApplication.Main (System.String[] args, System.IntPtr principal, System.IntPtr delegate) [0x00005] in /Users/builder/data/lanes/5665/f70a1348/source/xamarin-macios/src/UIKit/UIApplication.cs:79 at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x00038] in /Users/builder/data/lanes/5665/f70a1348/source/xamarin-macios/src/UIKit/UIApplication.cs:63 at iManage.iOS.Application.Main (System.String[] args) [0x00001] in /Users/pankajsachdeva/Projects/iManage/iOS/Main.cs:17
从ViewModel代码:
public class SchoolSelectionViewModel : BaseViewModel
{
private readonly ISchoolNames _schoolService;
public SchoolSelectionViewModel(ISchoolNames schoolService)
{
_schoolService = schoolService;
}
public override void Start()
{
IsLoading = true;
_schoolService.GetFeedItems(OnDilbertItems, OnError);
}
private void OnDilbertItems(List<SchoolModel> list)
{
IsLoading = false;
Items = list;
}
private void OnError(Exception error)
{
// not reported for now
IsLoading = false;
}
private List<SchoolModel> _items = new List<SchoolModel>();
public List<SchoolModel> Items
{
get { return _items; }
set { _items = value; RaisePropertyChanged(() => Items); }
}
private MvxCommand<SchoolModel> _itemSelectedCommand;
public ICommand ItemSelectedCommand
{
get
{
_itemSelectedCommand = _itemSelectedCommand ?? new MvvmCross.Core.ViewModels.MvxCommand<SchoolModel>(DoSelectItem);
return _itemSelectedCommand;
}
}
private void DoSelectItem(SchoolModel item)
{
//ShowViewModel<LoginViewModel>(item);
ShowViewModel<LoginViewModel>(new LoginViewModel(item));
}
}
要查看模型代码:
public class LoginViewModel : BaseViewModel
{
private readonly ILoginService _loginService;
private readonly IDialogService _dialogService;
public LoginViewModel(SchoolModel item)
{
//_loginService = loginService;
//_dialogService = dialogService;
School = item;
Username = "TestUser";
Password = "YouCantSeeMe";
IsLoading = false;
}
private SchoolModel _school;
public SchoolModel School
{
get
{
return _school;
}
set
{
SetProperty(ref _school, value);
RaisePropertyChanged(() => School);
}
}
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 IMvxCommand _loginCommand;
public virtual IMvxCommand LoginCommand
{
get
{
_loginCommand = _loginCommand ?? new MvxCommand(AttemptLogin, CanExecuteLogin);
return _loginCommand;
}
}
private void AttemptLogin()
{
if (_loginService.Login(Username, Password))
{
ShowViewModel<DashboardStdViewModel>();
}
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));
}
}
编辑1:
在我从ViewModel修改以下内容:
private async void DoSelectItem(SchoolModel item)
{
await _navigationService.Navigate<LoginViewModel,SchoolModel>(item);
}
更改了下一个ViewModel声明,如下所示:
public class LoginViewModel : MvxViewModel<SchoolModel>
当我尝试显示带有以下错误的下一个viewmodel时,它仍然崩溃:
你调用的对象是空的。
编辑2:
完成错误:
System.NullReferenceException: Object reference not set to an instance of an object at iManage.ViewModels.SchoolSelectionViewModel+d__19.MoveNext () [0x0000f] in /Users/pankajsachdeva/Projects/iManage/iManage/ViewModels/SchoolSelectionViewModel.cs:67 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/mcs/class/referencesource/mscorlib/system/runtime/exceptionservices/exceptionservicescommon.cs:152 at System.Runtime.CompilerServices.AsyncMethodBuilderCore+<>c.b__6_0 (System.Object state) [0x00000] in /Library/Frameworks/Xamarin.iOS.framework/Versions/11.6.1.3/src/mono/mcs/class/referencesource/mscorlib/system/runtime/compilerservices/AsyncMethodBuilder.cs:1018 at UIKit.UIKitSynchronizationContext+c__AnonStorey0.<>m__0 () [0x00000] in /Users/builder/data/lanes/5665/f70a1348/source/xamarin-macios/src/UIKit/UIKitSynchronizationContext.cs:24 at Foundation.NSAsyncActionDispatcher.Apply () [0x00000] in /Users/builder/data/lanes/5665/f70a1348/source/xamarin-macios/src/Foundation/NSAction.cs:163 at at (wrapper managed-to-native) UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr) at UIKit.UIApplication.Main (System.String[] args, System.IntPtr principal, System.IntPtr delegate) [0x00005] in /Users/builder/data/lanes/5665/f70a1348/source/xamarin-macios/src/UIKit/UIApplication.cs:79 at UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x00038] in /Users/builder/data/lanes/5665/f70a1348/source/xamarin-macios/src/UIKit/UIApplication.cs:63 at iManage.iOS.Application.Main (System.String[] args) [0x00001] in /Users/pankajsachdeva/Projects/iManage/iOS/Main.cs:17
最佳答案
MvvmCross.Platform.Exceptions.MvxIoCResolveException: Failed to resolve parameter for parameter item of type SchoolModel when creating iManage.ViewModels.LoginViewModel at MvvmCross.Platform.IoC.MvxSimpleIoCContainer.GetIoCParameterValues (System.Type type, System.Reflection.ConstructorInfo firstConstructor)
问题在于
SchoolModel
的构造函数中使用的参数LoginViewModel
的类型。尝试构造MvxSimpleIoCContainer
时,LoginViewModel
无法解析类型。所以我要谈两点
ShowViewModel
在 View 模型之间传递参数。 在MvvmCross中查看模型IoC使用情况
在MvvmCross view models are constructed via IoC中。这意味着 View 模型类的公共(public)构造函数的参数需要向IoC容器注册,以便容器构造该类。
用作构造参数的类型也很重要,因为默认情况下MvvmCross使用Service Locator pattern支持仅针对实现类型注册的接口(interface)类型。针对实现类型
Foo
和接口(interface)类型IFoo
注册的示例。Mvx.ConstructAndRegisterSingleton<IFoo, Foo>();
由于MvvmCross对 View 模型使用了构造函数注入(inject),因此无法将 View 模型类的公共(public)构造函数用于传递给 View 模型类实例的参数。构造函数参数必须能够来自IoC容器。
MvvmCross在 View 模型之间传递5个参数(Navigation Service)
在MvvmCross 5 the Navigation Service中,它是在MvvmCross中编写导航逻辑的首选方法。导航服务还提供一种在 View 模型之间传递参数的方法,以避免通过 View 模型构造函数传递参数。 MvvmCross documentation中有一个很好的示例,显示了如何传递参数。这是摘录
public class MyViewModel : MvxViewModel
{
private readonly IMvxNavigationService _navigationService;
public MyViewModel(IMvxNavigationService navigationService)
{
_navigationService = navigationService;
}
public async Task SomeMethod()
{
await _navigationService.Navigate<NextViewModel, MyObject>(new MyObject());
}
}
public class NextViewModel : MvxViewModel<MyObject>
{
private MyObject _myObject;
public override void Prepare(MyObject parameter)
{
// receive and store the parameter here
_myObject = parameter;
}
}
快速说明。从
NextViewModel
( View 模型导航)开始,您需要在继承的MvxViewModel
基类泛型中指定要传递的参数的类型,然后重写Prepare
来传递参数。在MyViewModel
方法的调用类navigate
中,您包括导航到的 View 模型的类型以及要传递的参数的类型。然后,将参数作为navigate
方法的第一个参数传递。在 View 模型(ShowViewModel)之间传递参数
在示例代码中,您仍在使用较旧的
ShowViewModel
模式进行导航,因此我将介绍如何使用ShowViewModel
方法传递参数。有关传递ShowViewModel
参数的MvvmCross文档,可以找到here for the complex parameter object和here for the simple parameter object。复杂参数对象
对于复杂的参数对象,MvvmCross要求您已安装MvvmCross Json插件。这种方法将序列化和反序列化通过的参数
public class SchoolSelectionViewModel : BaseViewModel
{
public void DoSelectItem(SchoolModel item)
{
ShowViewModel<LoginViewModel, SchoolModel>(item);
}
}
public class LoginViewModel : BaseViewModel<SchoolModel>
{
private SchoolModel _parameter;
public override Task Prepare(SchoolModel parameter)
{
// receive and store the parameter here
_parameter = parameter;
}
}
如果您无法继承
IMvxViewModel<TParameter>
的LoginViewModel
,则可能还需要使用MvxViewModel<TParameter>
契约实现自定义基类。public abstract class BaseViewModel<TParameter> : BaseViewModel, IMvxViewModel<TParameter>
{
public async Task Init(string parameter)
{
if (!string.IsNullOrEmpty(parameter))
{
IMvxJsonConverter serializer;
if (!Mvx.TryResolve(out serializer))
{
throw new MvxIoCResolveException("There is no implementation of IMvxJsonConverter registered. You need to use the MvvmCross Json plugin or create your own implementation of IMvxJsonConverter.");
}
var deserialized = serializer.DeserializeObject<TParameter>(parameter);
Prepare(deserialized);
await Initialize();
}
}
public abstract void Prepare(TParameter parameter);
}
简单参数对象
对于不需要序列化的基本类型,可以使用此方法,但会损失类型安全性参数。
public class SchoolSelectionViewModel : BaseViewModel
{
public void DoSelectItem(SchoolModel item)
{
ShowViewModel<LoginViewModel>(item);
}
}
public class LoginViewModel : BaseViewModel
{
private SchoolModel _parameter;
public override void Init(SchoolModel parameter)
{
// receive and store the parameter here
_parameter = parameter;
}
}
注意用于Simple参数对象的类型的规则
此处使用的类必须是仅用于以下导航的“简单”类:
get
和set
访问权限的公共(public)属性bool
sbyte
,short
,int
,long
,byte
,ushort
,uint
,ulong
float
,double
decimal
char
string
DateTime
Guid
最后说明
在早期版本的MvvmCross v5.x.x中,对 View 模型生命周期进行了一些更改,但是从v5.5+开始,上述模式应适用。
关于c# - 从 View 模型导航到mvvmcross中的另一个 View 模型时崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48252248/