在 mvvmcross 中的视图模型之间传递多态类型
Passing polymorphic types between viewmodels in mvvmcross
我有 2 个按钮,它们都用于显示新的视图模型,但传递给视图模型的数据不同。传递的数据并不完全不同,所以它们都继承自同一个基类。不幸的是,似乎传递给 viewmodel 的 Init() 方法的数据在途中丢失了其运行时类型信息?使用调试器(或代码),传递的数据 仅 被识别为基础 - class - 而不是实际构建并传递给的派生 class ShowViewModel<>() 方法。
我想做的事情是不可能的吗?
public class BasePasser
{
}
public class PasserA : BasePasser
{
}
public class PasserB : BasePasser
{
}
public class ViewModelOne : MvxViewModel
{
// ...
private void DoSwitchViewModelA()
{
var tobepassed = new PasserA {
// ...
};
ShowViewModel<ViewModelTwo>(tobepassed);
}
private void DoSwitchViewModelB()
{
var tobepassed = new PasserB {
// ...
};
ShowViewModel<ViewModelTwo>(tobepassed);
}
}
public class ViewModelTwo : MvxViewModel
{
// ...
public async Task Init(BasePasser passed)
{
if(passed is PasserA)
{
// ...
}
else if(passed is PasserB)
{
// ...
}
else
{
// Always called/hit
throw new InvalidOperationException("Unknown data passed");
}
}
}
在 MvvmCross 中显示 ViewModel 实际上是一个相当复杂的过程。
当您调用 ShowViewModel(param) 时,Mvx 会将参数值序列化到 name/value 字典中。此时,param的Type信息丢失。
实例化 ViewModel 时,它最终会查找 ViewModel 上定义的任何 Init 方法。
如果您查看 Cirrious.MvvmCross.ViewModels.MvxViewModelExtensions.CallBundleMethod(),您会发现它首先查找具有 IMvxBundle 类型的单个参数的方法。然后它寻找一个不是简单类型(如字符串、整数等)的单个参数
如果找到此类型,它会假定它是一个已在 ShowViewModel() 调用中序列化的对象。然后它会尝试根据 Init 方法中参数的类型而不是原始类型来反序列化该值。
这就是为什么您只看到基类型的原因,因为 Mvx 没有初始调用的类型信息,并且在反序列化时,只能看到来自 Init 方法的基类型。
解决方法是将所有属性放入一个 class。只设置你需要的那些,并创建一个鉴别器 属性 来指定它是哪个 "type"。
var param = new Passer { PasserType = "A", ParamA = "ValueA", ... etc. }
您还可以选择使用命名方法参数。
请参阅 https://github.com/MvvmCross/MvvmCross/wiki/View-Model-Lifecycle
中的 Init 部分
我有 2 个按钮,它们都用于显示新的视图模型,但传递给视图模型的数据不同。传递的数据并不完全不同,所以它们都继承自同一个基类。不幸的是,似乎传递给 viewmodel 的 Init() 方法的数据在途中丢失了其运行时类型信息?使用调试器(或代码),传递的数据 仅 被识别为基础 - class - 而不是实际构建并传递给的派生 class ShowViewModel<>() 方法。
我想做的事情是不可能的吗?
public class BasePasser
{
}
public class PasserA : BasePasser
{
}
public class PasserB : BasePasser
{
}
public class ViewModelOne : MvxViewModel
{
// ...
private void DoSwitchViewModelA()
{
var tobepassed = new PasserA {
// ...
};
ShowViewModel<ViewModelTwo>(tobepassed);
}
private void DoSwitchViewModelB()
{
var tobepassed = new PasserB {
// ...
};
ShowViewModel<ViewModelTwo>(tobepassed);
}
}
public class ViewModelTwo : MvxViewModel
{
// ...
public async Task Init(BasePasser passed)
{
if(passed is PasserA)
{
// ...
}
else if(passed is PasserB)
{
// ...
}
else
{
// Always called/hit
throw new InvalidOperationException("Unknown data passed");
}
}
}
在 MvvmCross 中显示 ViewModel 实际上是一个相当复杂的过程。
当您调用 ShowViewModel(param) 时,Mvx 会将参数值序列化到 name/value 字典中。此时,param的Type信息丢失。
实例化 ViewModel 时,它最终会查找 ViewModel 上定义的任何 Init 方法。
如果您查看 Cirrious.MvvmCross.ViewModels.MvxViewModelExtensions.CallBundleMethod(),您会发现它首先查找具有 IMvxBundle 类型的单个参数的方法。然后它寻找一个不是简单类型(如字符串、整数等)的单个参数
如果找到此类型,它会假定它是一个已在 ShowViewModel() 调用中序列化的对象。然后它会尝试根据 Init 方法中参数的类型而不是原始类型来反序列化该值。
这就是为什么您只看到基类型的原因,因为 Mvx 没有初始调用的类型信息,并且在反序列化时,只能看到来自 Init 方法的基类型。
解决方法是将所有属性放入一个 class。只设置你需要的那些,并创建一个鉴别器 属性 来指定它是哪个 "type"。
var param = new Passer { PasserType = "A", ParamA = "ValueA", ... etc. }
您还可以选择使用命名方法参数。
请参阅 https://github.com/MvvmCross/MvvmCross/wiki/View-Model-Lifecycle
中的 Init 部分