一、简介
LoxodonFramework是什么,是用来干嘛的。我在这里就不介绍了,直接上链接:vovgou/loxodon-framework: An MVVM & Databinding framework that can use C# and Lua to develop games (github.com)
链接里有很全的介绍和教程,这篇文章主要记录学习理解该框架的心得。
二、快速入门
笔者之前也用过WPF的MVVM框架–Prism,所以在unity中也想找到类似的框架,那么LoxodonFramework是否也可以像Prism那么好使用呢?现在我们可以简单尝试一下。
三、示例
我们创建好上述的项目,想做这么一件事:输入框输入值后滑动条会滑动到相应的值上,滑动条滑动的时候输入框会显示相应的值。
试想,如果不适用MVVM的思想,我们可以挂载一个脚本,脚本属性中分别找到这两个控件,然后操作的时候分别给对方赋值,这应该是一个很简单的工作。但是使用MVVM思路该怎么做呢?
3.1Model
由于示例的数据模型很简单,可以使用基本数据类型,所以这一层省掉了。
3.2ViewModel
这一层就是我们的交互逻辑。数据的更新和事件响应逻辑代码都在这里。
3.3View
这里是UI层,只涉及到控件,不涉及到数据业务等。说一下思路,一般是在UI控件上挂载一个脚本,这个脚本也就是我们需要的View层,当然也会继承UIView类,然后在这里脚本中进行绑定操作。绑定主要是将UI控件的属性或者事件绑定到ViewModel中的属性或者方法中。所以ViewModel不是脚本,不需要挂载在控件上。
然后看一下代码具体实现:
public class SampleViewModel : ViewModelBase
{
private float sliderValue;
public float SliderValue
{
get { return sliderValue; }
set { Set<float>(ref sliderValue, value, "SliderValue"); }
}
public void OnSliderValueChanged(float newValue)
{
if (newValue != sliderValue)
{
this.SliderValue = newValue;
Debug.Log($"NewValue:{newValue}");
}
}
public void OnInputFieldChanged(string str)
{
this.SliderValue = int.Parse(str);
}
}
public class SampleView : UIView
{
public InputField input;
public Slider slider;
protected override void Awake()
{
//获得应用上下文
ApplicationContext context = Context.GetApplicationContext();
//启动数据绑定服务
BindingServiceBundle bindingService = new BindingServiceBundle(context.GetContainer());
bindingService.Start();
}
protected override void Start()
{
//获得数据绑定上下文
IBindingContext bindingContext = this.BindingContext();
bindingContext.DataContext = new SampleViewModel { SliderValue = 98 };
//绑定UI控件到视图模型
BindingSet<SampleView, SampleViewModel> bindingSet;
bindingSet = this.CreateBindingSet<SampleView, SampleViewModel>();
//将VM中的值绑定到UI控件上,注意这里是单向绑定vm=>v
bindingSet.Bind(this.input).For(v => v.text).To(vm => vm.SliderValue).OneWay();
bindingSet.Bind(this.slider).For(v => v.value).To(vm => vm.SliderValue).OneWay();
//然后将控件的事件绑定到vm的方法中,注意To要使用泛型,方法的参数与事件方法参数一致。
//当然也可以绑定到命令上(后文再介绍)
bindingSet.Bind(this.slider).For(v => v.onValueChanged).To<float>(vm => vm.OnSliderValueChanged);
bindingSet.Bind(this.input).For(v => v.onEndEdit).To<string>(vm=>vm.OnInputFieldChanged);
//这一句也不能忘了
bindingSet.Build();
}
}
绑定的思路大同小异。
四、关于绑定
上面示例中有这么一段代码:
//获得数据绑定上下文
IBindingContext bindingContext = this.BindingContext();
bindingContext.DataContext = new SampleViewModel { SliderValue = 98 };
上面的代码也可以修改如下:
this.SetDataContext(new SampleViewModel { SliderValue = 98 });
Behaviour类中拓展了SetDataContext方法,其内部实现也是使用了IBindingContext接口。
写过WPF绑定的同学肯定似曾相识,没错,这里也出现了DataContext的概念。关于DataContext,框架的作者在文档中有这样的描述:
一般来说数据绑定都在视图创建函数中来初始化,通过BindingSet来配置视图控件和视图模型之间的绑定关系,当调用BindingSet的Build函数时,
Binder会创建BindingSet中所有的绑定关系对,被创建的绑定对会保存在当前视图的BindingContext中。BindingContext在首次调用时自动创建,同
时自动生成了一个BindingContextLifecycle脚本,挂在当前视图对象上,由它来控制BindingContext的生命周期,当视图销毁时,BindingContext会
随之销毁,存放在BindingContext中的绑定关系对也会随之销毁。
所以,对于View层的DataContext,我们是可以在外部设置好的,或者后期改变的,不一定和示例中的一样就在build的时候设置好。