MVVMModel-View-ViewModel
,它是MVC的改进版。
MVVM优点:
View
)可以独立于Model
变化和修改,一个ViewModel可以绑定到不同的View
上,当View
变化的时候Model
可以不变,当Model
变化的时候View
也可以不变。ViewModel
里面,让很多view重用这段视图逻辑。ViewModel
)。ViewModel
来写。AWTK-MVVM 是一套用C语言开发的,专门为嵌入式平台优化的 MVVM 框架。它实现了数据绑定、命令绑定和窗口导航等基本功能,使用 AWTK-MVVM 开发应用程序,无需学习 AWTK 本身的 API ,只需学习绑定规则和模型的实现方式即可。
AWTK-MVVM无需手动编写和更新ViewModel
的代码,它提供一个主动代码产生器,只需在编写 Model
的代码时,按照固定的规则来编写注释(详细注释规则请点击查看model.md),就会根据Model
的代码自动生成更新ViewModel
。
编写 Model
的代码,并按照model.md的规则来编写注释。
books_manager_model.h:
/**
* @class books_manager_model_t
*
* @annotation ["model"]
* 图书管理者模型。
*
*/
typedef struct _books_manager_model_t {
/**
* @property {int32_t} find_type
* @annotation ["readable", "writable"]
* 当前查找书籍方式。
*/
int32_t find_type;
/* private */
books_manager_t* books_manager;
} books_manager_model_t;
/**
* @method books_manager_model_create
* 创建books_manager_model对象。
*
* @annotation ["constructor"]
* @return {books_manager_model_t*} 返回books_manager_model对象。
*/
books_manager_model_t* books_manager_model_create(void);
/**
* @method books_manager_model_destroy
* 销毁books_manager_model对象。
*
* @annotation ["destructor"]
* @param {books_manager_model_t*} model books_manager_model对象。
*
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
*/
ret_t books_manager_model_destroy(books_manager_model_t* model);
请查看model.md的9.3小节:代码生成器。
ret_t application_init(void) {
mvvm_init();
/* 其他初始化设置 */
/* ... */
/* 注册ViewModel,ViewModel名称为"books_manager_model" */
view_model_factory_register("books_manager_model", books_manager_model_view_model_create);
return navigator_to("home_page"); /* 通过导航器打开View */
}
home_page.xml:
<window name="home_page" v-model="books_manager_model">
<!-- 省略... -->
</window>
Model
中变量的名称。```xml
<window name="home_page" v-model="books_manager_model">
<combo_box_ex name="cmb_find" x="610" y="234" w="180" h="28" v-data:value="{find_type}"/>
<!-- 省略... -->
</window>
通过嵌入表达式实现简单的逻辑判断。
当find_type等于4时,date_picker可见:
<window name="home_page" v-model="books_manager_model">
<date_picker name="date_picker" x="606" y="272" w="188" h="201" v-data:visible="{find_type == 4}">
<!-- 省略... -->
</date_picker>
<!-- 省略... -->
</window>
当find_type等于1时,edit_data控件的input_type等于2,否则等于0:
<window name="home_page" v-model="books_manager_model">
<edit name="edit_data" x="620" y="338" w="160" h="28" v-data:input_type='{if(find_type == 1, 2, 0)}'>
</edit>
<!-- 省略... -->
</window>
由于表达式中<>"等字符对于 XML 来说是特殊字符,需要转换成对应的实体 (entity),但是转换之后表达式不太直观,此时可以把属性提出来,放在 property 标签中,并用 CDATA 把它的值包起来。
当find_type大于0且小于4时,edit_data可见:
<window name="home_page" v-model="books_manager_model">
<edit name="edit_data" x="620" y="338" w="160" h="28">
<property name="v-data:visible"><![CDATA[ {(find_type > 0 && find_type < 4) ? true : false} ]]></property>
</edit>
<!-- 省略... -->
</window>
命令绑定规则也是一个控件属性:
属性的名称由两部分组成,两者之间用英文冒号分隔。
Model
中的函数。在view中关联"btn_add"控件的点击事件和add命令:
<window name="home_page" v-model="books_manager_model">
<button name="btn_add" x="610" y="115" w="180" h="36" tr_text="add" v-on:click="{add}"/>
<!-- 省略... -->
</window>
在model中添加add命令函数(注意:每次修改model都需要使用工具更新ViewModel代码!):
/**
* @method books_manager_model_add
* 添加图书。
*
* @annotation ["command:add"]
* @param {books_manager_model_t*} model books_manager_model对象。
*
* @return {ret_t} 返回RET_OK表示成功,否则表示失败。
*/
ret_t books_manager_model_add(books_manager_model_t* model);
目前支持的事件有(以后更加需要增加):
事件 | |
---|---|
click | 点击事件 |
pointer_down | 指针按下事件 |
pointer_up | 指针松开事件 |
key_down | 按键按下事件 |
key_long_press | 按键长按事件 |
key_up | 按键松开事件 |
global_key_down | 全局按键按下事件 |
global_key_long_press | 全局按键长按事件 |
global_key_up | 全局按键松开事件 |
value_changed | 值改变事件 |
value_changed_by_ui | 值(通过 UI 修改)改变事件 |
详细内容请参考:
命令绑定:command_binding.md