背景:实际项目中,架构组成是一个主工程,多个子工程,主工程通过
Prefab View 2D|Prefab Placeholder 2D
引用子工程预设件。
多个工程之间直接无法消息互通,比如子工程想绑定主工程某节点某属性,或者子工程内不同预设件间属性绑定,用别名或者相对路径都会发生kanzi爆红报错(如果子工程创建同名属性,外加别名方式,可以解决爆红报错。但是要额外创建属性和别名,不方便),而且如果节点改动,又要重新改相对路径,十分的不方便。
为此,我设计了插件PluginDataSourceGlobal
,利用datasource机制实现全局变量访问。
1. 创建插件
2. 搭建多工程环境
新建子工程UntitleTest
,UntitleTest2
,并引用kanzi 案例XML_data_source
的插件,并设置xml。DataSource插件使用参考官方本地文档即可。
主工程结构
子工程1结构
子工程2结构
xml内容
3. 设计插件
3.1 NodeRefByStringProperty
NodeRefByStringProperty
属性用来绑定带有Data Context
属性的节点,一般是主工程RootPage
3.2 TestIntProperty
TestIntProperty
属性用来更新datasource值
3.3 时序
4. 实现插件
更新datasource方案,参考kanzi 3.9.8 DataSource动态预览
void PluginDataSourceGlobal::onNodePropertyChanged(kanzi::AbstractPropertyType propertyType, kanzi::PropertyNotificationReason reason)
{
if (NodeRefByStringProperty == propertyType) {
kzLogDebug(("NodeRefByStringProperty = {}", getProperty(NodeRefByStringProperty)));
}
else if (TestIntProperty == propertyType) {
kzLogDebug(("TestIntProperty = {}", getProperty(TestIntProperty)));
string str = getProperty(TestIntProperty);
handleIntInput(str);
}
Node2D::onNodePropertyChanged(propertyType, reason);
}
TestIntProperty
变化后调用handleIntInput
更新对应的datasource
,这里只演示了int
类型。
void PluginDataSourceGlobal::handleIntInput(std::string value)
{
int index = value.find("=");
if (index >= 0) {
string name = value.substr(0, index);
string valuestr = value.substr(index + 1, value.size());
int val = Str2Numberi(valuestr);
kzLogDebug(("TestIntProperty Name={}, value={}, v={}", name, valuestr, val));
if (m_lastDataSourceName == name && m_destObjectInt) {
//if (!m_destObjectInt) return;
if (val != m_destObjectInt->getValue()) {
m_destObjectInt->setValue(val);
}
return;
}
m_lastDataSourceName = name;
NodeSharedPtr node = lookupNode<Node>(getProperty(NodeRefByStringProperty));
if (!node) return;
const ResourceSharedPtr root = node->getProperty(DataContext::DataContextProperty);
if (!root) return;
DataContextSharedPtr data = dynamic_pointer_cast<DataContext>(root);
m_root = data->getData();
if (!m_root) return;
std::shared_ptr<DataObjectInt> p = m_root->lookupDataContextOfType<DataObjectInt>(name);
m_destObjectInt = p.get();
if (!m_destObjectInt) return;
if (val != m_destObjectInt->getValue()) {
m_destObjectInt->setValue(val);
}
}
}
这个函数就是查找datasource,然后设置新值。
举例:gauges.battery=10
,把=
裁切后,获得datasource标签gauges.battery
和新值10
,这里做了一个优化,备份DataObjectInt
,不用每次查找。
5. kanzi使用插件
子工程untitledTest
,点击按钮,设置临时属性NewPropertyType
,
插件绑定属性TestIntProperty
=
"gauges.battery=" + STRING({@./UntitledTest.NewPropertyType})
子工程untitledTest
和untitledTest2
,Text Block 2D各自绑定
"Test1 Result=" + STRING({DataContext.gauges.battery})
"Test2 Result="+STRING({DataContext.gauges.battery})
主工程使用子工程预设件
6. kanzi演示
7. vs debug演示
8. 总结
这个方案能够很简单的解决预设件之间,工程之间属性绑定问题。
可以方便的拓展float
,string
等类型。