C# 在MVVMCross中查看已实例化的ViewModel

C# 在MVVMCross中查看已实例化的ViewModel,c#,mvvm,mvvmcross,C#,Mvvm,Mvvmcross,有人知道如何查看现有的IMvxViewModel吗 在我的应用程序中,我已经在另一个视图模型中创建了一组视图模型(PhotoViewModel)。它们作为父视图模型(AlbumViewModel)上的属性存在。如果只显示PhotoViewModel的特定实例,而不是在我想要查看它时创建该视图模型的新实例,那将非常好 public class AlbumViewModel : MvxViewModel { public ObservableCollection<PhotoViewMo

有人知道如何查看现有的IMvxViewModel吗

在我的应用程序中,我已经在另一个视图模型中创建了一组视图模型(PhotoViewModel)。它们作为父视图模型(AlbumViewModel)上的属性存在。如果只显示PhotoViewModel的特定实例,而不是在我想要查看它时创建该视图模型的新实例,那将非常好

public class AlbumViewModel : MvxViewModel {
    public ObservableCollection<PhotoViewModel> Photos
    {
        get { return GetValue(() => Photos); }
        set { SetValue(value, () => Photos); }
    }
}

public class PhotoViewModel : MvxViewModel { }
公共类AlbumViewModel:MvxViewModel{ 公众可观察收集照片 { 获取{return GetValue(()=>Photos);} 设置{SetValue(value,()=>照片);} } } 公共类PhotoViewModel:MvxViewModel{}
我想知道除了创建自己的IMvxViewModelLocator之外,是否还有其他方法来完成这项任务。我认为在MvxNavigationObject上有一个名为View的受保护方法对使用该框架的新开发人员和性能都非常有帮助。我们可以跳过当前为实例化视图模型所做的所有反射。

MvvmCross中默认的
ShowViewModel
机制使用基于页面的导航-此导航必须在WindowsPhone上使用
Uri
s,在Android上使用
Intent
s

因此,MvvmCross不允许通过“富”对象进行导航-简单的可序列化POCO可以,但不支持复杂的“富”对象

这一点更为重要,因为“逻辑删除”——如果您的应用程序/页面/活动后来被重新水化,那么您无法确定历史视图或ViewModel对象实际上在您的历史“后退”堆栈中


如果要按富对象导航,最好的方法是将这些富对象存储在查找服务中,然后按某个键/索引导航到查找中。但是,我个人将这些lookedup对象称为
Model
s,而不是
ViewModel
s(但边界有时会变得模糊!)


尽管基于MvvmCross v1代码,这个问题仍然提供了一个很好的背景-

一些最新的解释包括:

  • (在建)

最后一件事

。。。MvvmCross宣言坚持MvvmCross对定制非常开放


因此,如果需要,可以覆盖MvvmCross导航和查看模型位置。为此,创建自己的
IMvxViewModelLocator
可能是一个很好的开始方式。

经过一些测试后,下面是一个建议的解决方案。我不是百分之百地喜欢它,但它确实有效,并提供了我所寻找的类型开发人员体验。所以让我们开始吧

首先,我的所有ViewModels(VM)都继承自基本VM AVM。这个抽象基类支持作为公共静态方法查找对象。这有点恶心,但如果你愿意喝一口可乐,效果会很好。以下是课程中与此问题相关的部分:

public abstract class AVM : MvxViewModel {
    private static readonly Dictionary<Guid, WeakReference> ViewModelCache = new Dictionary<Guid, WeakReference>();
    private static readonly string BUNDLE_PARAM_ID = @"AVM_ID";

    private Guid AVM_ID = Guid.NewGuid();
    private Type MyType;

    protected AVM()
    {
        MyType = this.GetType();
        ViewModelCache.Add(AVM_ID, new WeakReference(this));
    }

    public static bool TryLoadFromBundle(IMvxBundle bundle, out IMvxViewModel viewModel)
    {
        if (null != bundle && bundle.Data.ContainsKey(BUNDLE_PARAM_ID))
        {
            var id = Guid.Parse(bundle.Data[BUNDLE_PARAM_ID]);
            viewModel = TryLoadFromCache(id);
            return true;
        }

        viewModel = null;

        return false;
    }

    private static IMvxViewModel TryLoadFromCache(Guid Id)
    {
        if (ViewModelCache.ContainsKey(Id))
        {
            try
            {
                var reference = ViewModelCache[Id];
                if (reference.IsAlive)
                    return (IMvxViewModel)reference.Target;
            }
            catch (Exception exp) { Mvx.Trace(exp.Message); }
        }

        return null;
    }


    protected void View()
    {
        var param = new Dictionary<string, string>();
        param.Add(BUNDLE_PARAM_ID, AVM_ID.ToString());
        ShowViewModel(MyType, param);
    }
最后你得把电线接上。为此,请进入App.cs并覆盖CreateDefaultViewModelLocator,如下所示:

    protected override IMvxViewModelLocator CreateDefaultViewModelLocator()
    {
        return new AVMLocator();
    }
你都准备好了。现在,在任何已处于活动状态的派生ViewModel中,可以执行以下操作:

myDerivedVM.View();
我还需要做更多的事情(比如确保weakreference完成它们的工作,并且我没有内存泄漏和一些额外的错误处理),但至少这是我想要的经验。我做的最后一件事是向AVM基类添加以下命令:

public MvxCommand ViewCommand
{
    get { return new MvxCommand(View); }
}
现在,您可以将该命令绑定到任何UI对象,当被调用时,它将使用VM的实例启动该视图

斯图尔特,谢谢你帮我指引方向。我很想听听您对我提供的解决方案的反馈。感谢您为MVVMCross所做的所有工作。这确实是一段非常漂亮的代码


干杯。

斯图尔特,非常感谢你的帮助。我实际上是沿着你描述的道路走的,我想我已经想出了一个相当好的解决方案。我已经修改了我的问题以显示建议的解决方案。我很想听听你的想法。再次感谢你的帮助。
public MvxCommand ViewCommand
{
    get { return new MvxCommand(View); }
}