1、什么是MVVM
2、MVVM在unity开发中的应用
3、uMVVM的设计与实现
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; } } }
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"); } }
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>(); }
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); } }
public class Install:MonoBehaviour { // Use this for initialization public SetupView setupView; public TestView testView; void Start() { //绑定上下文 setupView.BindingContext=new SetupViewModel(); testView.BindingContext=new TestViewModel(); } }
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 }