Передача сложных навигационных параметров с помощью MvvmCross ShowViewModel

Мой сложный тип не будет передаваться из метода Show to Init даже с настроенным MvxJsonNavigationSerializer, как указано здесь Пользовательские типы в параметрах навигации в версии 3

public class A
{
 public string String1 {get;set;}
 public string String2 {get;set;}
 public B ComplexObject1 {get;set;}
}

public class B
{
 public double Double1 {get;set;}
 public double Double2 {get;set;}
}

Когда я передаю экземпляр объекта A в метод ShowViewModel, я получаю этот объект с десериализацией String1 и String2 правильно, но CopmlexObject1 имеет значение null.

Как работать со сложной сериализацией MvvmCross объекта?

Ответы

Ответ 1

Я считаю, что в этом предыдущем ответе могут быть некоторые гремлины - будет регистрироваться как проблема:/


Существуют и другие возможные пути для реализации этого типа комплексной сериализуемой навигации по объектам, все еще использующей Json и переопределяющие части структуры, но на самом деле я думаю, что было бы лучше просто использовать собственный BaseViewModel для сериализации и десериализации. используйте код сериализации, например:

public class BaseViewModel
    : MvxViewModel
{
    private const string ParameterName = "parameter";

    protected void ShowViewModel<TViewModel>(object parameter)
        where TViewModel : IMvxViewModel
    {
        var text = Mvx.Resolve<IMvxJsonConverter>().SerializeObject(parameter);
        base.ShowViewModel<TViewModel>(new Dictionary<string, string>()
            {
                {ParameterName, text}
            });
    }
}

с десериализацией вроде:

public abstract class BaseViewModel<TInit>
    : MvxViewModel
{
    public void Init(string parameter)
    {
        var deserialized = Mvx.Resolve<IMvxJsonConverter>().DeserializeObject<TInit>(parameter);
        RealInit(deserialized);
    }

    protected abstract void RealInit(TInit parameter);
}

то viewModel, как это:

public class FirstViewModel
    : BaseViewModel
{
    public IMvxCommand Go
    {
        get
        {
            return new MvxCommand(() =>
                {
                    var parameter = new A()
                        {
                            String1 = "Hello",
                            String2 = "World",
                            ComplexObject = new B()
                                {
                                    Double1 = 42.0,
                                    Double2 = -1
                                }
                        };
                    ShowViewModel<SecondViewModel>(parameter);
                });
        }
    }
}

может перейти к чему-то вроде:

public class SecondViewModel
    : BaseViewModel<A>
{
    public A A { get; set; }

    protected override void RealInit(A parameter)
    {
        A = parameter;
    }
}

Ответ 2

Небольшое дополнение к ответу Стюарта для добавления безопасности типа:

public class BaseViewModel: MvxViewModel {

    protected bool ShowViewModel<TViewModel, TInit>(TInit parameter) where TViewModel: BaseViewModel<TInit> {
        var text = Mvx.Resolve<IMvxJsonConverter>().SerializeObject(parameter);
        return base.ShowViewModel<TViewModel>(new Dictionary<string, string> { {"parameter", text} });
    }
}

public abstract class BaseViewModel<TInit> : BaseViewModel {

    public void Init(string parameter)
    {
        var deserialized = Mvx.Resolve<IMvxJsonConverter>().DeserializeObject<TInit>(parameter);
        RealInit(deserialized);
    }

    protected abstract void RealInit(TInit parameter);
}

ShowViewModel теперь использует тот же тип параметра, что и метод RealInit вместо типа object. Кроме того, BaseViewModel<TInit> наследует от BaseViewModel, поэтому их экземпляры также могут вызвать новый метод ShowViewModel.

Единственным недостатком является то, что вы должны явно указывать тип параметра в вызове следующим образом:

ShowViewModel<StoreInfoViewModel, Store>(store);