• MVVM框架在unity开发中的使用


    1、什么是MVVM

    借用一下百度百科上对MVVM的介绍,MVVM是Model-View-ViewModel的简写,它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。当然这些事 ViewModel 已经帮我们做了,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。
     

    2、MVVM在unity开发中的应用

    MVVM框架应用面十分广泛,通常在前端开发中应用很广,最近看到周围同事在开发WPF时用到了这个框架,抱着好奇的态度来学习一下这个框架,MVVM框架在unity开发中同样适用,在unity中,将每个UI抽象成一个个View,通常我们为每一个UI面板定义一个View,View中包含了该面板中涉及到的UI元素,比如一个Text,一个Button;每一个View都有独立的ViewModel来管理,ViewModel中提供必要的属性和方法来控制View, 而Model只是单纯的定义一个数据模型。前两天在github上发现了这个叫uMVVM的框架,拿来试用了一下,下面分析一下该框架对MVVM模式的设计。
     

    3、uMVVM的设计与实现

    下载uMVVM后,它提供了一些使用示例:

    在这个示例中,有两个panel,就定义了两个view,每个view中定义该界面的元素,比如SetupView:

    public class SetupView:UnityGuiView<SetupViewModel>
        {
    
            public InputField nameInputField;
            public Text nameMessageText;
    
            public InputField jobInputField;
            public Text jobMessageText;
    
            public InputField atkInputField;
            public Text atkMessageText;
    
            public Slider successRateSlider;
            public Text successRateMessageText;
    
            public Toggle joinToggle;
            public Button joinInButton;
            public Button waitButton;
            
            public SetupViewModel ViewModel { get { return (SetupViewModel)BindingContext; } }
    
            }
    可以看到,View中需要指定对应的ViewModel来管理该View,ViewModel中定义的属性需要具备当数据改变时通知订阅者的功能,因此uMVVM对这种属性进行了一层封装,具体设计如下:

    public class BindableProperty<T>
        {
            public delegate void ValueChangedHandler(T oldValue, T newValue);
    
            public ValueChangedHandler OnValueChanged;
    
            private T _value;
            public T Value
            {
                get
                {
                    return _value;
                }
                set
                {
                    if (!Equals(_value, value))
                    {
                        T old = _value;
                        _value = value;
                        ValueChanged(old, _value);
                    }
                }
            }
    
            private void ValueChanged(T oldValue, T newValue)
            {
                if (OnValueChanged != null)
                {
                    OnValueChanged(oldValue, newValue);
                }
            }
    
            public override string ToString()
            {
                return (Value != null ? Value.ToString() : "null");
            }
        }
    可以看到,BindableProperty类中维护一个T类型数据,当T发生变化时,可以通知到订阅者,有了这种属性之后,那么ViewModel就是这样的了:

    public class SetupViewModel:ViewModelBase
        {
            public readonly BindableProperty<string> Name = new BindableProperty<string>();
            public readonly BindableProperty<string> Job=new BindableProperty<string>(); 
            public readonly BindableProperty<int> ATK = new BindableProperty<int>();
            public readonly BindableProperty<float> SuccessRate=new BindableProperty<float>(); 
            public readonly BindableProperty<State> State=new BindableProperty<State>();
    }
    uMVVM的设计中,每个View都继承UnityGuiView这个泛型类,UnityGuiView大概的内容是这样:

    public abstract class UnityGuiView<T>:MonoBehaviour,IView<T> where T:ViewModelBase
        {
            private bool _isInitialized;
            public bool destroyOnHide;
            protected readonly PropertyBinder<T> Binder=new PropertyBinder<T>();
            public readonly BindableProperty<T> ViewModelProperty = new BindableProperty<T>();
     
            public T BindingContext
            {
                get { return ViewModelProperty.Value; }
                set
                {
                    if (!_isInitialized)
                    {
                        OnInitialize();
                        _isInitialized = true;
                    }
                    //触发OnValueChanged事件
                    ViewModelProperty.Value = value;
                }
            }
    
            /// <summary>
            /// 初始化View,当BindingContext改变时执行
            /// </summary>
            protected virtual void OnInitialize()
            {
                //无所ViewModel的Value怎样变化,只对OnValueChanged事件监听(绑定)一次
                ViewModelProperty.OnValueChanged += OnBindingContextChanged;
            }
            
            /// <summary>
            /// 当gameObject将被销毁时,这个方法被调用
            /// </summary>
            public virtual void OnDestroy()
            {
                if (BindingContext.IsRevealed)
                {
                    Hide(true);
                }
                BindingContext.OnDestory();
                BindingContext = null;
                ViewModelProperty.OnValueChanged = null;
            }
    
            /// <summary>
            /// 绑定的上下文发生改变时的响应方法
            /// 利用反射+=/-=OnValuePropertyChanged
            /// </summary>
            public virtual void OnBindingContextChanged(T oldValue, T newValue)
            {
                Binder.Unbind(oldValue);
                Binder.Bind(newValue);
            }
        }
    UnityGuiView中有一个BindingContext的属性, 当使用框架时,需要给View的BindingContext指定对应的ViewModel:

      public class Install:MonoBehaviour
        {
            // Use this for initialization
            public SetupView setupView;
            public TestView testView;
            void Start()
            {
                //绑定上下文
                setupView.BindingContext=new SetupViewModel();
                testView.BindingContext=new TestViewModel();
            }
        }
    在View中,就订阅model数据改变的消息,并定义相应的响应函数:

     public class SetupView:UnityGuiView<SetupViewModel>
        {
            //......省略ui元素的定义
            
            protected override void OnInitialize()
            {
                base.OnInitialize();
                Binder.Add<string>("Name", OnNamePropertyValueChanged);
                Binder.Add<string>("Job",OnJobPropertyValueChanged);
                Binder.Add<int>("ATK",OnATKPropertyValueChanged);
                Binder.Add<float>("SuccessRate",OnSuccessRatePropertyValueChanged);
                Binder.Add<State>("State",OnStatePropertyValueChanged);
            }
    
    
            private void OnSuccessRatePropertyValueChanged(float oldValue, float newValue)
            {
                successRateMessageText.text = newValue.ToString("F2");
            }
    
            private void OnATKPropertyValueChanged(int oldValue, int newValue)
            {
                atkMessageText.text = newValue.ToString();
            }
    
            private void OnJobPropertyValueChanged(string oldValue, string newValue)
            {
                jobMessageText.text = newValue.ToString();
            }
    
            private void OnNamePropertyValueChanged(string oldValue, string newValue)
            {
                nameMessageText.text = newValue.ToString();
            }
            private void OnStatePropertyValueChanged(State oldValue, State newValue)
            {
               //dosomething
            }
    

    最后看一下其中一个model的定义:

     public class Combatant
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public string Job { get; set; }
            public float SuccessRate { get; set; }
            public State State { get; set; }
        }
        public enum State
        {
            JoinIn,
            Wait
        }

    4、总结

    本文只大概写了一下uMVVM框架的一些设计和使用方法,不全面,如果感兴趣,可以自行阅读源码,github地址为https://github.com/MEyes/uMVVM
     
    如有错误,欢迎指正!

  • 相关阅读:
    转 无障碍阅读 role aria-*
    (转)edm注意事项
    Spring IOC机制之使用注解配置bean
    Spring IOC机制使用SpEL
    使用Spring IOC容器引用外部属性文件
    如何将属性文件中的值保存到类中
    基于XML的类的属性的装配
    Java——事务
    Eclipse中使用Spring IOC容器的具体方法
    Java之批处理的实现
  • 原文地址:https://www.cnblogs.com/IAMTOM/p/10303392.html
Copyright © 2020-2023  润新知