如何为Xamarin原生iOS的新页面添加ViewModel&;Android应用程序

如何为Xamarin原生iOS的新页面添加ViewModel&;Android应用程序,xamarin,mvvm,xamarin.android,xamarin.ios,Xamarin,Mvvm,Xamarin.android,Xamarin.ios,上下文:我收到了这个庞大的企业iOS和Android Xamarin本机应用程序,它不使用ViewModels或任何MVVM框架。它确实有一个独立的网络服务层,并且有很多页面,所以从头开始没有任何意义 为什么需要更改:没有MVVM,直接从UI类(片段和视图控制器)调用服务层,并且没有良好的抽象。因此,我将从1视图开始,然后创建TechDebt来转换应用程序的其余部分 我所知道的: 添加MVVM框架需要创建大量更改,尤其是使用导航服务来导航视图,如果在绿色部署应用程序时添加,则最好这样做 如图所示

上下文:我收到了这个庞大的企业iOS和Android Xamarin本机应用程序,它不使用ViewModels或任何MVVM框架。它确实有一个独立的网络服务层,并且有很多页面,所以从头开始没有任何意义

为什么需要更改:没有MVVM,直接从UI类(片段和视图控制器)调用服务层,并且没有良好的抽象。因此,我将从1视图开始,然后创建TechDebt来转换应用程序的其余部分

我所知道的

  • 添加MVVM框架需要创建大量更改,尤其是使用导航服务来导航视图,如果在绿色部署应用程序时添加,则最好这样做
  • 如图所示,Android有一种使用ViewModel的简单方法,但我无法在iOS上使用它
  • 我还知道,我可以启动一个Xamarin表单页面,这将为MVVM做好准备,因为我可以将BindingContext属性分配给ViewModel的一个实例
  • 我需要什么:我需要为iOS和Android创建一个新页面。我希望能够创建iOS和Android之间共享的ViewModel。我希望能够将它用于我正在创建的单个视图,并在加载页面时初始化它


    如何添加ViewController和片段共享的1个viewmodel?我是不是遗漏了什么,是不是比我做的容易多了?

    不幸的是,你没有遗漏任何东西,你所有的主张都是正确的,你正确地列出了你可以采取的各种方向(以及你不喜欢的方向)

    Android和Xamarin.iOS并没有考虑数据绑定,而是使用本机接口,只为数据绑定制作了Xamarin.Forms。本机平台使用数据绑定的能力是有限的(如果存在数据绑定,则平台之间不兼容,您必须创建单独的视图模型,并且到目前为止,iOS还没有数据绑定)


    因此,Xamarin.iOS和Xamarin.Android中基本上没有数据绑定。完全由您来抽象共享业务模型并将其与用户界面连接。

    最终能够使用MvvmLight实现这一点。将Nuget包添加到项目中,在核心共享库项目中创建了ViewModelBase:

    public abstract class ViewModelBase : GalaSoft.MvvmLight.ViewModelBase
    {
            private PropertyChangedEventHandler propertyChangedEventHandler;
    
            protected bool IsLoading { get; set; }
    
            public bool RegisteredPropertyEventHandler { get; set; }
    
            public const string ErrorMessagePropertyName = "ErrorMessage";
    
            public string ErrorMessage { get; set; }
    
            public string SuccessMessage { get; set; }
    
            public void RegisterPropertyEventHandler(PropertyChangedEventHandler propertyChangedEventHandler)
            {
                this.propertyChangedEventHandler = propertyChangedEventHandler;
                this.PropertyChanged += propertyChangedEventHandler;
                this.RegisteredPropertyEventHandler = true;
            }
    
            public void UnegisterPropertyEventHandler()
            {
                if (this.RegisteredPropertyEventHandler)
                {
                    this.PropertyChanged -= propertyChangedEventHandler;
                    this.RegisteredPropertyEventHandler = false;
                    this.propertyChangedEventHandler = null;
                }
            }
    
            public void TearDown()
            {
                this.UnegisterPropertyEventHandler();
            }
    
            protected void NotifyError (string message)
            {
                this.ErrorMessage = message;
                RaisePropertyChanged (() => ErrorMessage);
            }
    }
    
    和一个ViewModelLocator

    public class ViewModelLocator
    {
            public const string ABCPageKey = "ABCPage";
    
            public ABCViewModel ABC 
            {
                get 
                {
                    return ServiceLocator.Current.GetInstance<ABCViewModel> ();
                }
            }
    
            public ViewModelLocator ()
            {
                ServiceLocator.SetLocatorProvider (() => SimpleIoc.Default);
    
                // Register all of the view models
                SimpleIoc.Default.Register<ABCViewModel> ();
            }
    
            public static void Cleanup ()
            {
            }
    
            public T GetViewModel<T> ()
            {
                return ServiceLocator.Current.GetInstance<T> ();
            }
    }
    
    公共类ViewModelLocator
    {
    public const string ABCPageKey=“ABCPage”;
    公共ABCViewModel ABC
    {
    得到
    {
    返回ServiceLocator.Current.GetInstance();
    }
    }
    公共ViewModelLocator()
    {
    ServiceLocator.SetLocatorProvider(()=>SimpleIoc.Default);
    //注册所有视图模型
    SimpleIoc.Default.Register();
    }
    公共静态无效清除()
    {
    }
    公共T GetViewModel()
    {
    返回ServiceLocator.Current.GetInstance();
    }
    }
    
    在iOS方面,我已经有了一个BaseUIViewController,所以我在它上面创建了一个BaseViewModelUIViewController

    public abstract partial class BaseViewModelUIViewController<T> : BaseUIViewController where T : ViewModelBase
        {
            public T ViewModel 
            {
                get 
                {
                    return App.Locator.GetViewModel<T> ();
                }
            }
    
            public BaseViewModelUIViewController (IntPtr handle) : base (handle)
            {
            }
    
            internal virtual void ViewModelPropertyChangedHandler (object sender, PropertyChangedEventArgs e)
            {
                Console.WriteLine (string.Format ("****** Property Changed for {0} in {1}", e.PropertyName, this.GetType ().Name));
                switch (e.PropertyName) 
                {
                default:
                    break;
                }
            }
    }
    
    public class BaseViewModelFragment<T> : BaseFragment where T : ViewModelBase
    {
            public T ViewModel 
            {
                get 
                {
                    return App.Locator.GetViewModel<T> ();
                }
            }
    
            public BaseViewModelFragment (string title) : base (title)
            {
            }
    
            internal virtual void ViewModelPropertyChangedHandler (object sender, PropertyChangedEventArgs e)
            {
                Console.WriteLine (string.Format ("****** Property Changed for {0} in {1}", e.PropertyName, this.GetType ().Name));
                switch (e.PropertyName) 
                {
                default:
                    break;
                }
            }
    
            public override void OnDestroyView ()
            {
                this.ViewModel.TearDown ();
    
                base.OnDestroyView ();
            }
    }
    
    公共抽象部分类BaseViewModelUIViewController:BaseUIViewController其中T:ViewModelBase
    {
    公共视图模型
    {
    得到
    {
    返回App.Locator.GetViewModel();
    }
    }
    公共BaseViewModelUIViewController(IntPtr句柄):基本(句柄)
    {
    }
    内部虚拟void ViewModelPropertyChangedHandler(对象发送者,PropertyChangedEventArgs e)
    {
    Console.WriteLine(string.Format(“{1}中{0}的******属性已更改”,e.PropertyName,this.GetType().Name));
    开关(如PropertyName)
    {
    违约:
    打破
    }
    }
    }
    
    然后是Android,类似地,我已经有了一个BaseFragment,所以我在它上面创建了一个BaseViewModelFragment

    public abstract partial class BaseViewModelUIViewController<T> : BaseUIViewController where T : ViewModelBase
        {
            public T ViewModel 
            {
                get 
                {
                    return App.Locator.GetViewModel<T> ();
                }
            }
    
            public BaseViewModelUIViewController (IntPtr handle) : base (handle)
            {
            }
    
            internal virtual void ViewModelPropertyChangedHandler (object sender, PropertyChangedEventArgs e)
            {
                Console.WriteLine (string.Format ("****** Property Changed for {0} in {1}", e.PropertyName, this.GetType ().Name));
                switch (e.PropertyName) 
                {
                default:
                    break;
                }
            }
    }
    
    public class BaseViewModelFragment<T> : BaseFragment where T : ViewModelBase
    {
            public T ViewModel 
            {
                get 
                {
                    return App.Locator.GetViewModel<T> ();
                }
            }
    
            public BaseViewModelFragment (string title) : base (title)
            {
            }
    
            internal virtual void ViewModelPropertyChangedHandler (object sender, PropertyChangedEventArgs e)
            {
                Console.WriteLine (string.Format ("****** Property Changed for {0} in {1}", e.PropertyName, this.GetType ().Name));
                switch (e.PropertyName) 
                {
                default:
                    break;
                }
            }
    
            public override void OnDestroyView ()
            {
                this.ViewModel.TearDown ();
    
                base.OnDestroyView ();
            }
    }
    
    公共类BaseViewModelFragment:BaseFragment,其中T:ViewModelBase
    {
    公共视图模型
    {
    得到
    {
    返回App.Locator.GetViewModel();
    }
    }
    公共BaseViewModelFragment(字符串标题):基本(标题)
    {
    }
    内部虚拟void ViewModelPropertyChangedHandler(对象发送者,PropertyChangedEventArgs e)
    {
    Console.WriteLine(string.Format(“{1}中{0}的******属性已更改”,e.PropertyName,this.GetType().Name));
    开关(如PropertyName)
    {
    违约:
    打破
    }
    }
    公共覆盖无效OnDestroyView()
    {
    this.ViewModel.TearDown();
    base.OnDestroyView();
    }
    }
    
    我希望这对其他寻求解决方案的人来说是有意义的

    创建ViewModels:很自然,对于创建的每个新ViewModel,我都必须在ViewModelLocator中注册它


    使用ViewModels:就用法而言,您只需通过从iOS的“:BaseViewModelUIViewController”或Android的“:BaseViewModelFragment”继承,在UI中使用ViewModel即可

    以自定义ListView为例。iOS和Android都可以使用listview模型。这需要在本地渲染器中使用表单模型,到目前为止还不错。该应用程序没有太多更新@markwardell,所以我只是将其添加到自述文件中,以便将来的开发人员进行任何更改。如果想要简单,我可能只需要执行一个实现INotifyPropertyChanged的简单BaseViewModel类,并以这种方式执行。