[转]Power Apps component framework (PCF) 手把手入门实例

news/2025/9/29 6:40:34/文章来源:https://www.cnblogs.com/freeliver54/p/19117954

我是微软Dynamics 365 & Power Platform方面的工程师/顾问罗勇,也是2015年7月到2018年6月连续三年Dynamics CRM/Business Solutions方面的微软最有价值专家(Microsoft MVP),欢迎关注我的微信公众号 MSFTDynamics365erLuoYong ,回复432或者20210112可方便获取本文,同时可以在第一间得到我发布的最新博文信息,follow me!

Power Apps component framework的简要介绍参考官方文档:Power Apps component framework overview ,我不一一翻译,简述如下:

1. 它简称PCF,我这后文为了简便用PCF代替Power Apps component framework,不是Power Apps Component,这是两个不同的东西,后者只能用于Canvas Apps,不能用于Model-Driven Apps,处于Public Preview阶段,而且也推荐用 Component library 代替Power App Component,稍有基础的非开发者用户也能使用,前者两者都能用,需要专业的能写代码的开发者的来开发。

2.PCF开发出来的组件可以用于表单(form)上,视图(view)中,或者仪表盘(dashboard)上,可以用来做更酷的效果,比如用地图或者日历替换View来显示数据,用滚动条在表单上显示/更改字段的值。

3.PCF对于Model-Driven App来说是已经GA了,对于Canvas App来说目前还处于Pulic Preview阶段(预计2021年3月左右GA),而且默认情况下Canvas App并没有启用PCF,需要手动启用,Model-Driven Apps版本PCF支持的API等,对于Canvas App版本的PCF来讲不全部支持,Public Preview阶段的产品一般不适宜用于生产环境。

4.PCF用于Model-Driven Apps时候仅仅支持UCI,不支持经典界面,实际上当前已经没有经典界面了。当然,PCF不支持本地部署版本的Dynamics 365 Customer Engagement.

5.PCF在表单上显示/更改字段字段值,以前我们用HTML Web Resource基本也能做,那PCF有啥优势?优势是在当前上下文中与其他组件一起加载,速度更快,能调用丰富的API,也包括能使用相机,地理位置,麦克风等,更灵活,可重复使用性更高,所有文件打包成一个等等。

说了那么多我这里做个简单的例子,搞个中国特色的例子,将数字转换为中文大写,我这里的JavaScript代码参考 用JavaScript将数字转换为大写金额 。

工欲善其事必先利其器,要做PCF开发首先需要安装Microsoft Power Apps CLI (command-line interface),当然你的环境(Enivornment)必须要有Microsoft Dataverse才能安装和部署PCF. Microsoft Power Apps CLI的安装请参考官方文档,因为比较简单我就不翻译了,步骤如下:

Install Power Apps CLI

To get Power Apps CLI, do the following:

  1. Install Npm (comes with Node.js) or Node.js (comes with npm). We recommend LTS (Long Term Support) version 10.15.3 or higher.

  2. Install .NET Framework 4.6.2 Developer Pack.

  3. If you don’t already have Visual Studio 2017 or later, follow one of these options:

    • Option 1: Install Visual Studio 2017 or later.
    • Option 2: Install .NET Core 3.1 SDK and then install Visual Studio Code.
  4. Install Power Apps CLI.

  5. To take advantage of all the latest capabilities, update the Power Apps CLI tooling to the latest version using this command:

    pac install latest

请参考官方文档 Create your first component 结合本文一起看。

首先我想好项目名字,我取名为ConvertNumberToUpperCase,命名空间我就用LuoYongNamespace,模板分成field和dataset,我们这里适用于field。

首先是建立好文件目录,可以用命令,也可以手工建立。我这里用命令,用管理员身份打开CMD,执行如下命令(我这里与官方文档不同的是我一般建立一个src的子文件来放源代码):

复制代码
cd /d D:\Codes
mkdir ConvertNumberToUpperCase
cd ConvertNumberToUpperCase
mkdir src
cd src
pac pcf init --namespace LuoYongNamespace --name ConvertNumberToUpperCase --template field
npm install
复制代码

 

执行完毕后就可以用IDE打开了,如果有报错要纠正,否则到时候编译会报错。这里使用 code . 命令使用Visual Studio Code来打开它。最重要的两个文件就是项目名称文件夹下面的 ControlManifest.Input.xml 和index.ts。

 

ControlManifest.Input.xml 中control元素的version属性很重要,采用这种格式命名版本,部署后更改代码再次部署测试需要更改这个version属性的值。

然后重要的就是参数,也就是 property 这个元素,我这里使用一个property即可,使用的代码如下:

<property name="numberValue" display-name-key="numberValue_Display_Key" description-key="numberValue_Desc_Key" of-type-group="numbers" usage="bound" required="true" />

 

这个文件的整个代码是:

复制代码
<?xml version="1.0" encoding="utf-8" ?>
<manifest><control namespace="LuoYongNamespace" constructor="ConvertNumberToUpperCase" version="0.0.1" display-name-key="ConvertNumberToUpperCase" description-key="ConvertNumberToUpperCase description" control-type="standard"><external-service-usage enabled="true"></external-service-usage><type-group name="numbers"><type>Whole.None</type><type>Currency</type><type>FP</type><type>Decimal</type></type-group><property name="numberValue" display-name-key="numberValue_Display_Key" description-key="numberValue_Desc_Key" of-type-group="numbers" usage="bound" required="true" /><resources><code path="index.ts" order="1"/></resources></control>
</manifest>
复制代码

 

我这里是简单例子,不用额外引用css文件或者resx文件来支持多语言。

然后就是修改index.ts文件了,这里要使用TypeScript来写代码,当然可以使用React框架来简化撰写的代码,我这里就用TypeScript来写,简单易懂,声明下我对TypeScript并不是很熟悉。

我这里使用的代码如下,各个事件的含义我就不解释了,参考官方文档。

bound类型的参数值改变要通知外面的话,记得调用 notifyOutputChanged 。

getOutputs 方法返回的就是bound类型参数的输出值。

复制代码
import {IInputs, IOutputs} from "./generated/ManifestTypes";export class ConvertNumberToUpperCase implements ComponentFramework.StandardControl<IInputs, IOutputs> {// Value of the field is stored and used inside the componentprivate _value: number;// Power Apps component framework delegate which will be assigned to this object which would be called whenever any update happens.private _notifyOutputChanged: () => void;// label element created as part of this componentprivate labelElement: HTMLLabelElement;// input element that is used to create the range sliderprivate inputElement: HTMLInputElement;// reference to the component container HTMLDivElement// This element contains all elements of our code component exampleprivate _container: HTMLDivElement;// reference to Power Apps component framework Context objectprivate _context: ComponentFramework.Context<IInputs>;// Event Handler 'refreshData' referenceprivate _refreshData: EventListenerOrEventListenerObject;constructor(){}/*** Used to initialize the control instance. Controls can kick off remote server calls and other initialization actions here.* Data-set values are not initialized here, use updateView.* @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to property names defined in the manifest, as well as utility functions.* @param notifyOutputChanged A callback method to alert the framework that the control has new outputs ready to be retrieved asynchronously.* @param state A piece of data that persists in one session for a single user. Can be set at any point in a controls life cycle by calling 'setControlState' in the Mode interface.* @param container If a control is marked control-type='standard', it will receive an empty div element within which it can render its content.*/public init(context: ComponentFramework.Context<IInputs>, notifyOutputChanged: () => void, state: ComponentFramework.Dictionary, container:HTMLDivElement){this._context = context;this._container = document.createElement("div");this._notifyOutputChanged = notifyOutputChanged;this._refreshData = this.refreshData.bind(this);this.inputElement = document.createElement("input");this.inputElement.addEventListener("change", this._refreshData);//setting the max and min values for the component.this.inputElement.setAttribute("type", "number");this.inputElement.setAttribute("id", "txtNumber");// creating a HTML label element that shows the value that is set on the linear range componentthis.labelElement = document.createElement("label");this.labelElement.setAttribute("id", "lblNumber");// retrieving the latest value from the component and setting it to the HTML elements.this._value = context.parameters.numberValue.raw? context.parameters.numberValue.raw: 0;this.inputElement.value =context.parameters.numberValue.raw? context.parameters.numberValue.raw.toString(): "0";this.labelElement.innerHTML = this.numberToUpperCase(this._value);// appending the HTML elements to the component's HTML container element.this._container.appendChild(this.inputElement);this._container.appendChild(document.createElement("br"));this._container.appendChild(this.labelElement);container.appendChild(this._container);}public refreshData(evt: Event): void {this._value = Number(this.inputElement.value);this.labelElement.innerHTML = this.numberToUpperCase(this._value);this._notifyOutputChanged();}public numberToUpperCase(inNumber:number):string{let fraction = ['角', '分'];let digit = ['零', '壹', '贰', '叁', '肆','伍', '陆', '柒', '捌', '玖'];let unit = [['元', '万', '亿'],['', '拾', '佰', '仟']];let head = inNumber < 0 ? '欠' : '';inNumber = Math.abs(inNumber);let s:string = '';for (let i = 0; i < fraction.length; i++) {s += (digit[Math.floor(inNumber * 10 * Math.pow(10, i)) % 10] + fraction[i]).replace(/零./, '');}s = s || '整';inNumber = Math.floor(inNumber);for (let i = 0; i < unit[0].length && inNumber > 0; i++) {let p = '';for (let j = 0; j < unit[1].length && inNumber > 0; j++) {p = digit[inNumber % 10] + unit[1][j] + p;inNumber = Math.floor(inNumber / 10);}s = p.replace(/(零.)*零$/, '').replace(/^$/, '零') + unit[0][i] + s;}return head + s.replace(/(零.)*零元/, '元').replace(/(零.)+/g, '零').replace(/^整$/, '零元整');}/*** Called when any value in the property bag has changed. This includes field values, data-sets, global values such as container height and width, offline status, control metadata values such as label, visible, etc.* @param context The entire property bag available to control via Context Object; It contains values as set up by the customizer mapped to names defined in the manifest, as well as utility functions*/public updateView(context: ComponentFramework.Context<IInputs>): void{this._value = context.parameters.numberValue.raw? context.parameters.numberValue.raw: 0;this._context = context;this.inputElement.value = context.parameters.numberValue.raw? context.parameters.numberValue.raw.toString(): "0";this.labelElement.innerHTML = this.numberToUpperCase(this._value);}/** * It is called by the framework prior to a control receiving new data. * @returns an object based on nomenclature defined in manifest, expecting object[s] for property marked as “bound” or “output”*/public getOutputs(): IOutputs{return {numberValue: this._value};}/** * Called when the control is to be removed from the DOM tree. Controls should use this call for cleanup.* i.e. cancelling any pending remote calls, removing listeners, etc.*/public destroy(): void{this.inputElement.removeEventListener("change", this._refreshData);}
}
复制代码

 

然后编译看下是否有错误,在Visual Studio Code中点击命令栏的Terminal > Open Terminal 执行如下命令:

npm run build

确保编译成功,我这里截图如下:

 

然后我们来调试下,使用如下命令,不过我一般是用的是 npm start watch ,这样对代码的更改会自动刷新调试界面。

npm start

 

调试起来的界面如下,可以输入不同的参数值进行测试,测试没有问题就准备部署。

 

很多人调试的时候忘了暂停用什么方法,我一般常用 Ctrl + C 来停止调试(还有一种方法我忘了),按键后会出现询问是否终止batch job的提示,输入y回车即可。

 

然后我使用如下命令来打包准备部署:

复制代码
cd ..
mkdir Solution
cd Solution
pac solution init --publisher-name LuoYong --publisher-prefix ly
pac solution add-reference --path D:\Codes\ConvertNumberToUpperCase\src
msbuild /t:restore
msbuild
复制代码

 

后面的build不需要加上 /t:restore了。

 

然后在Solution文件夹下面的 bin > Debug就可以看到产生的解决方案文件了,将此解决方案导入到Microsoft Dataverse并发布(因为是非托管解决方案,所以导入后是需要发布的)。

  我这里导入后如下:

  

然后我在Model-Driven apps中来使用这个PCF组件,这个可以参考官方文档:Add code components to a field or entity in model-driven apps 。

我在Account实体的表单中使用这个组件,打开Account实体的Main表单,选择要显示的字段,点击 Change Properties ,在弹出的Field Properties窗口中选择Controls这个tab,点击 Add Control.. 。

 

选择我们创建的PCF组件,点击Add按钮。

  

注意至少要选择Web使用这个PCF控件,等会儿看效果才能看到,可以看到我们的绑定参数已经自动设定为要显示的字段了,点击OK,然后保存并发布表单,我们去看下效果。

 

 可以看大这个字段的值我是可以改的,改动后表单需要保存才能将记录保存好。

  

在Canvas app中使用PCF请参考官方文档:Code components for canvas apps 。

首先需要为环境启用Power Apps component framework 这个feature。登录 https://admin.powerplatform.microsoft.com/ ,

选择要启用的 Enivornment,选择 Settings 。

  

点击 Product 下面的 Features 。

 

 启用 Allow publishing of canvas apps with code components 这个feature后点击 Save 按钮。

  

然后我新建一个Canvas App来使用它。官方文档说要在这个app的Advanced Settings 启用Components,但是目前新建的的Canvas App默认都是启用的了,我认为这步骤可以不做了。

然后就是在Canvas App中点击 Insert > Custom > Import component 。

  

切换到Code,待刷新后选择我们要使用的PCF组件,点击Import按钮。

  

然后切换到 Insert 面板,展开 Code components节点,点击要插入的PCF组件,这样就会加入到Canvas App中的当前screen上。

  

选中刚才添加到Screen上的PCF 组件,右边的Advanced面板可以设置绑定参数的值,当然可以用表达式,还可以为OnChange事件指定执行的代码(bound类型参数的值变化会触发),我这里设置如下。

  

可以按F5来预览Canvas App,我这预览效果如下,虽然不是很严谨的程序,但是基本达到了教学的目的。

  

常见问题:

1. 我的PCF控件在最开始总是显示错误,特别是参数值为默认值val的时候,这个时候请检查index.ts中Init方法,如果参数值不是想要的格式或者内容不合要求,代码是否有兼容处理这个问题。如果这时候会导致程序异常,就会看到PCF控件在设置好参数之前会显示为错误。

2.PCF控件我改了代码后如何更新呢?需要更改 ControlManifest.Input.xml 文件中 control 的Version属性, 

 

保存后打开Terminal,再切换到Solution文件夹,执行 msbuild 命令,然后将解决方案导入Microsoft Dataverse 并发布。

 

下次打开时候会有安全警告,点击 Open app按钮。

 

 

  

点击 Update 按钮,再次预览canvas app的时候就会发现更改在了。

 

3. indext.ts中Init方法有时候获取不到参数的值,我认为是传递的参数也是额外获取的,比如通过在app的OnStart事件或者Screen的OnVisible事件中代码获取的Dataverse中数据或者其他数据源比如Sharepoint等数据,或许是异步的原因,在PCF组件的Init方法执行的时候还获取不到这些值,所以updateView中的代码要注意,这个代码是可以获取到绑定参数的值,这个代码要做适当处理,获取后进行必要的处理。

4. TypeScript写的代码不够简洁,可以用其他JavaScript框架吗? 用React是可以的,可以参考官方博客:Use of React and Office UI Fabric React in the PowerApps component framework is now available .

5.每次打包solution后还要手工导入解决方案,有命令行方式吗?有的,请参考官方文档 Package a code component ,主要是使用类似命令如下,我其实一般使用这种,这种就一个命令搞定了,效率高点,也容易自动化。

pac auth create --url https://luoyongdemo.crm5.dynamics.com
pac pcf push --publisher-prefix ly

 6. 可有示例参考?How to use the sample components? 和 PCF Gallery 。

7.我的输出参数很复杂怎么办?我的建议是用单行文本作为输出参数,内容为json字符串,这样Model-Driven App和Canvas App用起来都毫无压力

8.我改了参数的名称改了代码后很多错误怎么办?build一下就可以啊,执行 npm run build 命令后就没问题了,如果还有错误就要纠正了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/921488.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

做推广的网站带宽需要多少钱万网网站模板下载

在企业环境中&#xff0c;时常需要通过使用HTTP Proxy访问Internet&#xff0c;在使用HTTP Proxy访问Internet的环境中部署Microsoft Entra Connect和Microsoft Entra Connect Health Agents可能会遇到一些额外的配置步骤&#xff0c;以便这些服务能够正常连接到Internet。 一…

网站公司架构wordpress无法批量管理

Docker容器挂载procfs 逃逸 procfs是展示系统进程状态的虚拟文件系统&#xff0c;包含敏感信息。直接将其挂载到不受控的容器内&#xff0c;特别是容器默认拥有root权限且未启用用户隔离时&#xff0c;将极大地增加安全风险。因此&#xff0c;需谨慎处理&#xff0c;确保容器环…

修复lazarus/fpc在windows不支持中文(三)总结

修复lazarus/fpc在windows不支持中文(三)总结原版的fpc及lazarus不支持安装到包含中文及空格的目录,具体原因:一、中文的目录:1)外部的工具链软件不支持中文(make及交叉编译用到的*ld.exe) 2)fpc编译器及lazaru…

快三网站开发网站字体样式

2014秋学期南开大学《Java语言程序设计》在线作业附答案1.下列代码中&#xff0c;将引起一个编译错误的行是(D)。1)public class Test{ 2) int m,n; 3) public Test(){} 4) public Test(inta){ma;} 5) public static void main(String args[]){ 6) Test t1,t2; 7) int j,k;8) j…

个人备案后可以做电影网站吗网站建设合同服务内容

刚刚&#xff0c;数字货币交易所的领头羊Binance公布了法律策略&#xff0c;未来将会采取大胆举措与美国证券交易委员会 (SEC) 展开长期法律斗争&#xff0c;彰显其对监管合规的承诺。小编认为&#xff0c;Binance的这一战略立场是向美国SEC传递的道歉信&#xff0c;自从美国SE…

泉州建网站wordpress 调用页面

引言 在技术领域&#xff0c;许多中间件之所以获得巨大成功&#xff0c;部分原因在于它们所采用的思想之先进。这些思想解决了一个个世纪难题&#xff0c;接下来我将讲述一个我学习到的思想&#xff0c;并将其应用至工作中的案例。 惰性策略在日常编码中随处可见&#xff0c;但…

修复lazarus/fpc在windows不支持中文及空格目录(三)总结

修复lazarus/fpc在windows不支持中文及空格目录(三)总结原版的fpc及lazarus不支持安装到包含中文及空格的目录,具体原因:一、中文的目录:1)外部的工具链软件不支持中文(make及交叉编译用到的*ld.exe) 2)fpc编译…

岐金兰AI元人文构想的全面系统研究——声明ai研究

岐金兰AI元人文构想的全面系统研究——声明ai研究 一、引言:AI发展的价值困境与元人文转向 当前人工智能发展正面临根本性挑战:主流AI范式无法有效处理人类价值的复杂性、模糊性和动态性 。随着大模型能力的快速提升…

自己的网站怎么能让百度搜出来网站开发综合课程设计

哈喽&#xff0c;大家好&#xff0c;淼淼又来和大家见面啦&#xff0c;大家应该也知道&#xff0c;在应用开发市场中&#xff0c;软件产品的内测阶段对于确保产品质量与市场接受度至关重要&#xff0c;但是传统的内测分发方式往往面临地域分布广泛、网络环境各异的挑战&#xf…

通江县住房和城乡建设局网站网站开发行业工作交接交接哪些

视频及资料链接&#xff1a;基于单片机的火灾监测报警系统-实物设计 - 电子校园网 (mcude.com) 编号&#xff1a; T0152203M-SW 设计简介&#xff1a; 本设计是基于单片机的火灾监测报警系统&#xff0c;主要实现以下功能&#xff1a; 1.通过OLED显示温度、烟雾、是否有火…

h5响应式网站制作长沙短视频制作

1、使用SHOW语句找出在服务器上当前存在什么数据库&#xff1a;mysql> SHOW DATABASES;2、创建一个数据库MYSQLDATAmysql> CREATE DATABASE MYSQLDATA;3、选择你所创建的数据库mysql> USE MYSQLDATA; (按回车键出现Database changed 时说明操作成功&#xff01;)4、查…

主要给人家做网站的公司广州市广告公司标识系统设计

进入到根目录 cd /ls目录名具体作用/存放系统系统相关的目录文件/boot放置linux系统内核文件和启动时用到的一些引导文件/home包含linux系统上各用户的主目录&#xff0c;子目录名称默认以该用户名命名/root系统管理员root的家目录/bin包含常用的命令文件&#xff08;如ls 等&a…

国内ui设计网站常州做网站的公司

第二次做蓝桥模拟赛的博客记录&#xff0c;可能有很多不足的地方&#xff0c;如果大佬有更好的思路或者本文中出现错误&#xff0c;欢迎分享思路或者提出意见 题目A 请问 2023 有多少个约数&#xff1f;即有多少个正整数&#xff0c;使得 2023 是这个正整数的整数倍。 答案&…

Amazon Q Developer扩展安全漏洞分析与修复指南

本文详细分析了Amazon Q Developer for VS Code扩展1.84.0版本的安全漏洞CVE-2025-8217,包括GitHub令牌权限过宽导致恶意代码注入的原因、影响范围,以及AWS官方的修复措施和升级指南。Amazon Q Developer for Visual…

珠海自助建站廊坊智能模板建站

文章目录 1. 缺少EnableAsync注解2. 异步方法需独立3. 不同的异步方法间无法相互调用4. 返回值为void的异步方法无法捕获异常5. 外部无法直接调用带有Async注解的方法6. Async方法不适用于private方法7. 缺失异步线程池配置8. 异步方法与事务的兼容结语 &#x1f389;深入了解S…

php能开发大型网站wordpress修改后台没反应

写在前面 这篇文章提到了绝对位置编码和相对位置编码&#xff0c;但是他们都有局限性&#xff0c;比如绝对位置编码不能直接表征token的相对位置关系&#xff1b;相对位置编码过于复杂&#xff0c;影响效率。于是诞生了一种用绝对位置编码的方式实现相对位置编码的编码方式——…

山东临沂市需要建设网站的公司软件开发公司在哪里

给定一句英语&#xff0c;要求你编写程序&#xff0c;将句中所有单词的顺序颠倒输出。 输入格式&#xff1a; 测试输入包含一个测试用例&#xff0c;在一行内给出总长度不超过 80 的字符串。字符串由若干单词和若干空格组成&#xff0c;其中单词是由英文字母&#xff08;大小…

电商网站开发外包有关外贸的网站有哪些内容

Wifi设备监管 某知名跨国公司&#xff0c;在全球范围内拥有大量园区&#xff0c;园区内会有不同部门的同事在一起办公。每个园区内都要配备大量的Wifi设备从而为园区同事提供方便的上网服务。因此&#xff0c;集团需要一套完善的监管系统维护所有的Wifi设备。 公司通过监管系…

厦门百城建设有限公司网站专门做恐怖电影网站

eclipse 导入项目后会出现项目中的js文件报错&#xff08;红叉&#xff09;&#xff0c;如下图所示&#xff0c;有时候报错的文件很多&#xff0c;需要集中处理。 解决办法&#xff1a; 右键项目名称》Properties》MyEclipse》JavaScript》Include Path&#xff0c;在右侧选择“…

价值共生的语法革命:从“悬荡悟空”到“元人文构境”

价值共生的语法革命:从“悬荡悟空”到“元人文构境” 副标题:互搏三回合:为元人文构想锻造“反脆弱”对话框架 AI/岐金兰 对话开始 说句实在,如果我不说悬荡悟空,直接说,等一下,我用大模型算一下,再来定夺决策…