Transcript for:
Guide to Custom Components in PowerApps

Yeah. Greg Hellman, let's get hands-on with it. All right.

Thank you. Thank you very much, everybody. My name is Greg Hellman. I'm a member of the PowerApps product team.

I'm actually on the PowerApps component framework feature group. So what I'm about to teach you about today is something that I'm literally working on every day. to try to make better for all of you and everybody internal to Microsoft who's using this every day to build the products themselves. But all that said, no good presentation doesn't start with some slides.

So let me go ahead and share my screen. Get some Teams-ception. Oh, there we go.

Get that out of the way. Move Teams over to the other monitor because I have two of those and I can do that. Okay. So building your own components for PowerApps.

What we're basically looking at today. is what it would look like to build your own UI inside PowerApps. We'll give you a bunch of controls, but maybe you want to build your own control. You want to build a map control.

You want to build something that can display barcodes. You want to build something that's like a validator for credit cards or an emoji picker or who knows. This is how you would do it inside PowerApps.

If I click on the slide, something is supposed to happen PowerPoint. Let's see. How about now?

There we go. Our mission at Power Apps is to empower every developer to achieve more. The citizen developers get a lot of attention from Power Apps, but we do mean every developer, including those IT and pro developers. What's the difference between IT and a pro developer?

I have honestly no idea. But we're talking about people that are traditional developers, folks that are developers with code that you might recognize as code, JavaScript, TypeScript, HTML, CSS. good old modern web developer stuff. It's what we're going to be talking about today for PowerApps. But starting off, what is the PowerApps component framework?

Well, it's a framework we use to build controls inside PowerApps, as I said. It's our unified framework for building those components, and it does support model-driven PowerApps and Canvas-built PowerApps. Canvas-built PowerApps get all the attention, they get all the spotlight, they make for the better demos, a very shiny model-driven PowerApps. If you ask anybody who's ever been working in Dynamics for a long time, have a lot of power behind them as well. The Power Apps Component Framework actually was built for Dynamics, was part of Dynamics, and was taken from Dynamics and made more generally available towards Power Apps in general.

It is available for first and third-party developers, which is a weird thing to say. But it's because those first-party developers that are building Dynamics, that are building Power Apps, are building new controls with the Power Apps Component Framework. Inside Canvas apps, if you've used any of the AI builder controls, if you use any of the mixed reality controls that are there now, those are all built on top of the Power Apps component framework.

These are professionally developed controls or amateur developed controls depending on how you are, with a full modern web development lifecycle and model. There's better performance, reliability, and diagnostics, everything you'd get from modern-mode development. It does include a CLI for scaffolding your projects, get a new project spun up for building those projects, projects for deploying those components out to development and debugging all those components locally before you deploy to make sure you get everything just right.

We'll get through all of that today. But where can we add everything? This is mostly for model-driven apps. On a Canvas app, you can add Add a component anywhere you can add anything on a Canvas app. You've got control of the whole UI.

In model-driven apps, it's a little more locked down UI-wise, and so you have to pick and choose where you put these components. So you can replace a field control on a form with something that looks a little more useful for your users. You can replace a whole entity grid or subgrid with something that is more useful. Business process steps, we can get some PCF inside there as well.

I can just display external content as we've seen with a lot of LinkedIn integrations that we've had. You can use external services, bring in Azure Maps, bring in Bing Maps, bring in whatever maps, just bring them in, all kinds of good stuff. Really, at the end of the day, we're like, this halfway turns into a code, ain't it great kind of presentation.

But we'll get to the Power Apps stuff in particular in a minute. For to build these custom components. There's really three main pieces.

But before I get into those, I want to do just a quick talk about components versus code components. You might see in demos inside documentation, where somebody just mentions components or even maybe canvas components. Those are components that are built with controls out of the box inside Power Apps that are just grouped together to be one thing inside Power Apps.

That's a low code way to build custom UI. What we're talking about today might be referred to as code components. Those code components are the ones we're going to be talking about that are built with HTML, CSS, JavaScript, TypeScript to build out those really custom UI experiences. So if you see these both in documentation or in blog posts, just understand that components is out of the box. Code components is stuff built on top of the component framework.

So what makes a framework component? There's three main pieces that really starts out with manifest input file. This is an XML file that defines your control, your name, what version this control is, all the properties that you're going to expose or that you're going to bind to, and then file references to your resource files. And those are going to be your static resources, CSS files, localization files, images, and so on. So when I say localization, I do mean those Microsoft-y language files, those.resx files.

We do support those for supporting more than one language out of the box. And then, of course, it's got all your implementations, got your code, your TypeScript, your UI, your functionality. It's all HTML, CSS, JS that you build.

And we'll show you how. It does come with that CLI, as I mentioned before. It does have, when you...

build your components, it's not just compiling your TypeScript to JavaScript and make sure that you got all the semicolons in the right place, but it does have built-in validations to make sure that your component manifest is proper and isn't missing anything or has too much in any event. It makes sure that everything that you've built and the way that you've built it will actually work inside our products. So you want to make sure you use it. It includes a local debug harness to render and test that control. So we actually do spin up a local host website for you to use.

build out your component and test on before you ever have to deploy it anywhere, which is really good, especially in those early dev iterations when you're trying to just troubleshoot UI and get something built, and get it to look the way you want before you're even trying to bind it to any data. There is support for solution packaging. Everything that you would deploy into a PowerApps environment, especially into production, probably should be inside a solution.

We do support including the controls built on top of PCF into your your Common Data Service or your DataFlex Pro solutions. The PowerApps CLI as time goes on, will support other component types like plugins and web resources for model-driven apps. But right now, we do have an awful lot. This is our main CLI for PCF. So that was a lot of slides and a lot of talking.

So let's get into our actual demo here. Let me bring up those windows. And I'm going to go ahead and put it into the chat as well.

This link, if I can find the chat, there it is. That is where we're going to be starting. And if you want to walk through and do this, we can.

I know that on the Meetup site, there was a list of prerequisites, things that you'd need to have installed. And those are reiterated here. So if you're coming in later, you can still follow.

So you do need... NPM and Node. It is modern web development, so we do use all the modern JavaScript community of things, including NPM packages, including using Node to actually run everything. You do need to install a very particular version of the framework, the.NET Framework 4.6.2 developer pack, and that is primarily for the solution deployment things. If you want to use the CDS SDK to deploy, which is how the tool does it, you have to be on this particular developer pack.

That is something that the product team overall is working on to move towards something on.NET Core. But that is underway and not ready for consumption yet. But for now, you do need 4.6.2.

If you don't have Visual Studio 2017 or later, you can install that. We're actually going to be using Visual Studio Code today. They do recommend you do need the.NET Core 3.1 SDK if you do use Visual Studio Code.

What they really want you to have is something that has MSBuild, the command line tool. If you don't have, Visual Studio full and expensive. You can actually just get the Visual Studio 2019 build tools as a separate download that includes MSBuild, and that'll allow you to package everything up inside of a solution on your machine that then deploy it.

Once you've got everything installed, you have to install the Microsoft Power Apps CLI. Once you have that, we're good to go. I've already done that, so if I run.

PAC pack for PowerApps CLI. It'll return back, okay, we've got all our good stuff here. I'm not going to go through everything in the CLI, that would take too much time, but I will point out telemetry here at the bottom.

If you're somebody who doesn't want to let anybody know about what you're doing at all, you can just put in pack telemetry, disable, and it will do the thing and turn off sending us all that. If you decide you want to keep it, You can either just leave it alone or turn it back on. We're not gathering anything about you or what you're doing particular, we're just gathering up how many times people are creating projects, how many times people are deploying things. We're counting, not writing things down, if that makes any sense. But anyway, I wanted to point that out because I've gotten questions in the past.

So we have the CLI, it's installed, everything else is installed. So we're going to create our new component project. So step one, we actually need to just create a folder to put that project in. So I will do that. I will just use the maker command and we will call it demo.

So I'm actually running PowerShell with a fancy font that makes everything look scripty. If you're using a regular Windows command prompt, all these commands will still work just fine as they are. but my prompt might look a little bit different than yours.

We're in our empty directory, there's nothing in there. Let's go ahead and create our project. I'll just click on the copy button there and I will paste it in and just walk through what we're looking at real quick.

We're going to call PackPCF init. That's telling the CLI we want a new project. We give it a namespace, in this case, sample namespace, and a name, in this case, TSLinearInputComponent, we're going to create a slider.

We ask for a template of field. There are two different kinds of templates. There's field and there's dataset right now, which you need that space.

If you are creating something for Canvas, and you only have plain properties, you don't have any collections of properties you want to bind to, you want field. If you are creating something for model-driven apps and you want to bind against a particular single value as opposed to a grid of values, you want field. If you are binding against a grid or you want to have binding against something inside Canvas apps that is like an items collection, you're going to want the dataset template. But right now, today, we're going to stick with field and hit enter. And it does dump in those files just that quickly as we see that it is there, but you do need to run npm install.

So I will run npm install and that will do the thing. It'll reach out the internet, pull down a whole bunch of stuff, including. libraries that will tell our tool how to actually build and compile itself, which is super helpful and some time for that. So as that's compiling, we can watch that spin for a little bit. I'm going to check the chat here.

We have Charles chiming in with a whole bunch of pointers. He's been walking through a lot of this stuff himself. He knows, follow the instructions or it gets difficult later. It's true.

And I will say that I will be available on the internet after this. If you have any other questions, you can always reach out to me and I'll do my best to help out with wherever you get stuck. But in the meantime, as you're running NPM install, if you want to get a cup of coffee, a sandwich, a drink of water, take the dog for a walk. Sometimes it can take a while, sometimes longer than others.

Usually the longest time is if you're running a demo and having other people watch. Then it takes... Forever. Okay. Ages.

Yeah. So bits by bit. Don't ever do this on an airplane, by the way, if you can avoid it.

Holy cow. Did that once, 45 minutes later. Still waiting.

Okay. There it goes. Good to go. So now we have everything. We're going to run Visual Studio Code on this directory.

That should fire right up, right in place. Perfect. So we have Visual Studio Code.

I've got the Insider Edition, which means I've just got to get a daily build. You can sign up for that one too, but you really don't need it. The regular edition will work just as well.

So we've got a bunch of different files. This NPMRC, I will actually just go ahead and delete. That file won't come up for you. That actually came up because I'm using an internal build. Don't worry about it.

You won't get it. Even if you do have a copy of it, you won't be able to log in. We have our manifest and we're going to open up that first, close this to get a little more in here. The manifest has a lot going on and does define a lot about your component.

It's pretty much everything about your component for the environment that you're deploying to, so it knows what to do with the component once it gets there. Here we've got a few different things and we're going to copy out. Actually, should have done that first. put the line breaks in there, our control namespace from the the learn module here, and I'll paste it in and I'll redo what I just did.

Explain name key, description key, it is longer, we'll scroll over, there it is. Okay, that's why. All right, so what are we looking at here?

The constructor is really that is the name of your component in your code. The namespace is just a namespace. We try to namespace components to make sure that your slider doesn't collide with somebody else's slider on the same environment.

The display name key and description key are the display name and the description. They're called dash key on the end because this is the first opportunity you have to support multi-language if you want to. If you have resx files for different languages, you would specify the key information in here. So the string that it uses to look up inside that resx file for the actual string you want to show. If you're not messing with that at all, you just put the actual text right in here.

But make sure it is something meaningful as these are going to show up for your users when they try to use your control. Control type is going to be standard. For now, the only version that we support is standard. There might be other things later.

But for now, standard is what there is and standard is what we will use. Step 2 in our tutorial here is to actually replace the property with something a little more meaningful for a slider, and we'll do that here, and we get a slider value. So it has the very same display name key and description key, which is less useful in here. We're using a type group as opposed to binding to a particular number, and our usage type is bound which means we're getting an input and we're returning an output for this same value and it's going to be required so both required and the type group are really more for model driven apps and that's because uh well the the form will enforce if it's required or not um at runtime if you mark it required um and it will only let you bind to fields that match the type that you define for your property in this particular case we've set a set a type group That lets us use the type group that we have down here.

I think we got a little bit. There we go. So if I get rid of that, we're going to be using this type group of numbers. We can define an entire group, in this case, a whole number, currency, floating point, decimal, basically telling the product that we don't really care what kind of number we get, so long as it's a number, we're happy. So we pass in this type group as opposed to just saying of type.

a whole none, for example. So we've got that, we'll move on to step four, which is actually adding a CSS file or a pointer to a CSS file or a project underneath resources. So I'll go ahead and paste that in as well. I'll point out a couple of things here.

First, the code path, we do have the initial index.ts file that we give you. You can specify other files, but chances are you won't need it. because we actually walked down the dependency tree through these files. So if index.ts imports three more files, and each of those files import three more files, we will include all that stuff for you. You don't have to list it all here.

We'll find it. But for things like CSS, things for like ResX, if you have those files, you do have to list them all out and provide a loading order in here. The loading order does actually enforce across these files.

If you have three different CSS files and the loading order matters, make sure you specify the loading order, 1, 2, 3. If you give it the same loading order, that's okay. That just tells the platform, you don't really care so long as these are both ordered at this step. It doesn't matter which inside this step, which one comes first, which is the case for us.

We'll just leave that alone. We don't have any other files. We will delete this comment real quick and we'll collapse that out. All right. As we go through here and making our changes, if something isn't lining up later inside the tutorial, you can just copy out the whole file and paste it in there and make sure you save it, which is always my thing, and make sure you get the whole file.

So that's our manifest. We have a single, we have a control. called the TSLinearInputComponent. We have our single property called the slider value that represents the value of the slider.

We've got a code file that we've already got and a CSS file that we don't have yet that we'll need to create, and that's actually what we're doing in the very next step. We're going to add code to our code component, or add style to our code component, or styling anyway. To do that, we need to create a new CSS folder right underneath this guy here.

We'll open up. and create a new folder called CSS. In there, we need to call it tsLinearInputComponent.css. We don't really care what you name this file so long as the name of the file in here matches the name of the file here, so we can find it later.

That's really about it. Inside our file, we got a blank file, and I'm just going to copy the style from the tutorial, and I'm going to paste it in, and I'm not going to walk through it. There's a bunch of CSS in here. It's not too complicated, but it's got a lot of handling for what, depending on what browser you're in and making the slider look like a slider as opposed to just a box. So if you want to dig into CSS and learn about CSS, you can do that later.

I'll leave that up to you. But for us, it's just we have it, and that's what matters. So I will scroll down, make sure I save the file.

I did that. And we can build our components. Let me just pop up the... command line right here inside of VS codes.

We don't have to go too far. We're just going to call it run, npm run build. Before I do that, I want to open up this generated file.

We generate a TypeScript typing file based on the properties you put in your manifest XML file. This is this manifest types. It's still coming from the sample property that came with the default new project, but we need to update that. To update that, we'll run npm run build.

One of the things it does is update that property, and now you can see it updated to match that slider value that we put in for our property inside the manifest. And now we can code against that property inside our code instead of having to do weird stuff with XML, because nobody ever wants to do weird stuff with XML. It's 2020, for crying out loud. So we've got our manifest inputs, we've got our code built, everything looks good.

It should have compiled. We haven't really done a whole lot in code yet. So let's actually start looking at that code. So I'll close this file and open up this index.ts file that we gave you when you created your project. Before I start filling it in, I'm just going to walk through the basics of what is in here.

We have a reference that manifest types file. We implement the standard control logic that comes from the framework, and we have an empty constructor. The empty constructor should stay empty.

The constructor will work the way constructors do, but you don't know when this controls code is actually going to be created. In the back-end, it won't be when you think it is, and it is not a real good way to know when it will be. Instead of putting logic in the constructor to set things up, we want you to put that logic inside this init function.

Now, the init function has a few different parameters that we pass in to make things useful for you. The first being context. Context is going to be the one you use probably most of all. That's your window into the framework API at all. If I say context.

We can see all the all the different information that we get from the from the framework about what's going on right then at this moment. So we have client and device information. So we know how your user is coming in and what kind of device they're on.

Device is going to be tablet, phone, web, or unknown. Usually it's going to be one of those three. Got some factory functions and formatting functions. Formatting comes in useful if you have like a currency value coming in.

We give you the raw value, but we also give you the formatted value as well. And you can do some stuff in there to play with that. Mode is where we go, where we. handle a lot of knowing if something was going to be read-only or if something is disabled, that's where you find that information.

Navigation has some APIs. If you're in a model-driven app, if something inside your component user clicks something, you want to open up a different entity form or something like that, you do that through navigation. Parameters is where you actually get those properties from the XML.

So if I hit dot here as well, you can see that we have the slider value. But that slider value is an object. It's not the actual value. To get the actual value, you want to get to the raw value itself.

That's going to be the actual number. You'd have a few other properties here. If you've got any other attributes that are coming along, we'll give you those. If there's an error or an error message that's attached, and that'll usually come along as if you tried to save and the save failed for some reason, those will be attached.

So if there's a formatted value, we give you that. If there's security information, we give you that. Otherwise, the raw value is what you're going to be using most of the time.

Context is a whole bunch more. I'm not going to keep reading it to you, but you're going to be using that an awful lot. We do have notify output change.

Notify output change is a callback that we give you to call when it's time to let the host application know that the values that we've defined in outputs have changed, and we need to let the host application know about it. In this case, as we slide our slider across, we hit that number at the end, we're going to call notify output change, which tells the framework, hey, we have a new value. it does some logic and turns around and calls get outputs.

Inside get outputs is where we would say, where we return our value. So slider value is zero, or more likely we're just going to say slider value is this dot value, if you can type. And that way the host application knows the raw values that you're actually returning, but we're not there yet. So we will remove that. Bouncing back up here to UpdateView.

UpdateView is going to run every time something has happened outside your component's control that maybe your component should know about. Whether somebody has made their web window much smaller or much bigger, or if somebody has taken their phone and they've turned it sideways or if an underlying input value has changed outside your component, we're going to call UpdateView, which gives you an opportunity to redraw your Y, to make changes, do whatever you need to do to make your component still make sense in this new situation that you're in, whatever it is. So UpdateView can be useful. UpdateView is called immediately after init for the first time through.

So if you want to build out your UI entirely within UpdateView, you can do that. You don't have to do it in init. Init is good for setting up event handlers, init is good for starting up long-running network requests, and it is good for initialization stuff. Then down here at the bottom, we have destroy. Destroy is the last thing that's going to run.

So this is this is going to be your opportunity to clean up behind yourself, cancel any network connections you still have open, get rid of any event handlers that you created to make sure you're not leaking memories, stuff like that, you'd put inside Destroy. Now that we've gone through all that, let's go ahead and fill this in with some logic. Going back to our tutorial here, we've opened index.ts or nvs or something similar, or something way different like Visual Studio Code. Above the constructor method, we're going to create a bunch of private variables. So let's go ahead up here at the very top where private variables go and paste that in.

And add a tab at the beginning because I'm not a maniac. Okay. So we have a variable that's going to track that value.

We have a variable that's going to hold on to that notify output change callback. So we can call it later, which is useful. And a few more variables here to track are. the elements that are the web elements that make up our slider.

The container that we give you, we just give you an empty wrapper div, and here's your empty rectangle of web, please fill it with something. We hold on to the context itself, and then we will create an event listener to actually refresh the data in a little bit. So we've got all those variables in here.

Next thing we need to do is replace init with this logic. So let's go ahead and do that. That does a whole lot of stuff here.

So it's creating our elements, it's binding attributes on those elements, it's adding event listeners, setting different attributes, and then putting it all together. I'm not going to walk too closely to that. We can look at what that looks like when it's all written out inside the debug harness in a bit. But we're setting our value here.

If we have any value coming in when we try to load, we use that, otherwise we're going to default to zero. The input element, which is just going to be our text version of it that we actually put on the screen, we default to either what comes in that's been formatted or a string called zero. Same thing for the element itself.

We add containers into containers and put it all together to actually build out our UI. Now that had a red squiggly, really an orange squiggly for refresh data, because we haven't defined that yet. Our next step is to actually define that. Just put that right in here and tab it out because I'm not crazy. So this is going to be just a function that sets our value to what's coming in, that sets our label to be equivalent to the new value, and then call notify output change.

So if somebody slides that slider, you let the host application know. So that should take care of our squiggly up here at the top. Looks like it did. Good. Next thing is going to be to replace UpdateView with something that's a little more useful.

And so we'll do that. All right. So as UpdateView is called, we get that new value from the context. We store that internally.

And if we don't have a value, we just empty things out. Easy peasy. All right.

We replace getOutput to something. much smaller as get outputs tends to be. That is just returning that slider value as to be equivalent to the internal tracking value that we had to maintain that value. Last but not least, we replace destroy, get rid of that event listener. So we've created our event listener up here at the top.

In here, we set it for refresh data. So down here at the bottom, then need to remove it. Event listeners is one of those things that will leak memory if you don't get rid of them when things are unloaded.

So make sure that you do. So we have everything. Let's go ahead and save our file. Again, in the side of the tutorial, if you're worried that maybe you didn't copy it out right or maybe you're it doesn't work and something isn't working, you come back here, copy out this whole thing, and just paste out the entire file into your file and see if it works.

I have faith I'm not going to do that right yet, but we'll see what happens when I actually try to run it. Let's pop open that port command line again and run npm run build one more time. This time, we're actually going to compile out our project. Everything looks good.

Next step is that we're going to run the test harness by running npm start. Let's just run npm start. Validates control, it builds it again, so we didn't really need to build it that first time. Then starts up a website on local host and pops it open right here.

Here we have it. Now the slider started out. three because when I was trying it out early to make sure everything works, I gave it a value of three. But if I change this to 500, you can see it automatically updates at the top.

That is because if I hit Control Shift I to make my DevTools way too big, go to the Sources tab, we can actually look at our file and see what's going on. It is compiled using Webpack. We do get Oh gosh, the term is escaping me. We do get to look at our code inside the DevTools, any event, when we make a debug build. That is going to be found underneath this pcf__tools__guid all smooshed together.

This is going to be our project and we find the index.ts file here. This bundle.js is really what actually gets pushed to the server. Looks all compiled. It's been backward compatible with older browsers and all that good stuff.

But the actual TS file is here. I've got a breakpoint here set for update view and also get outputs. So if I change this to 505, we get update view running and if we look at the actual values, we can see the slider value coming in is 505. So okay, that lets us set everything appropriately. But if we drag this across, we see that get outputs is called.

If we look at the call stack, we can see that it actually came from this refresh data function up here, that we set up that event handler on click. Refresh data ran. It set our internal variable to the new value. It set the label to the new value and called notify output changed.

Notify output changed ran some things internally and then called get outputs. And so we were going to return this slider value, which is just that same 211. And then update view gets called again because a bound field, which also counts as input, was changed. In this case, it was changed by us, so that's okay.

so everything flows through. You can see that everything is working. We're just using the straight browser developer tools to debug. This is our debug harness, super useful for getting that initial UI down path.

One other thing I want to point out is that as I'm dragging around, you can see the value being updated down here, but it's not being updated every time. It's being updated when I stop or maybe a couple of times as I drag around, and that's for performance reasons. We're not going to fire UpdateView. for every time something changes, if it's changing over and over and over again within milliseconds of time. What really matters at the end of the day when you're to your application is the number you landed on, the last value that came in.

And so we're going to debounce those events until we actually get something that matters. In this case, 710 happened to be the one I landed on. But we saw a couple of different versions that we are binding against.

We switched to currency. You can see it switches the $710 that we're switching back and forth with. That dragging is a little broken now, but oh well, that's a bug for another time. So okay, everything looks good.

We'll close that out. We'll move on to the next step. So we are working.

So that's the end of this. We've walked through creating this component. Component looks good. So what do we do next? We create a solution package.

So we'll switch to step up to here. There's a message here at the top. If you don't have MSBuild, you're going to need MSBuild and it's true when it comes to actually packaging things up, you do need it. We're going to create a solution file with that same PowerApps CLI. Here, to break out of actually running that debug harness, you just hit Control C and that'll shut itself down.

Now I'm going to create a new solution and solutions directory and you can call make their Solution or solutions. I'm going to switch into that directory. Next, I'm going to run pack solution in it.

I'm just going to copy and paste that in here. We do have to give it a publisher name and a publisher prefix. Now, you want these publisher name and prefix to match up with generally what your company or your organization is using.

The platform doesn't really care so much. You can call it really whatever you want. as long as the publisher name doesn't have any spaces in it, as long as the publisher prefix is eight characters less. But we'll just stick with MS Learn for now, to stay with the tutorial, and hit enter.

That creates our solution files. If we actually open up our list here, we can see our solution files are in here. These are standard solution files.

If you've messed around with CDS solutions in the past, this will look pretty familiar. You can add in other customizations inside these solution files. That's absolutely fine. But what we need to do is make sure that we refer to our project inside the solution. That doesn't automatically hook that up, and that's our next step, step 3. So I will copy that and I'll paste it in.

We do have to provide the path to our project. But because our parent directory is our PCF solution, we can just hit the double dot and that'll work. So it'll add that reference to our project itself. So if we look at the solution here and scroll down, well there's a reference in here somewhere.

More importantly inside the CDS proj file, it added a reference to that PCF proj file at the root. And as soon as you start looking at star proj xml files you know ms build is not going to be too far behind so that is in fact our next step we're going to call ms build slash t build slash restore Let's clear this to clean that up a little bit. What that does is, well, two things. The slash restore tells MSBuild to actually go out to NuGet and pull down everything that we need to make to know how to compile this information. This isn't built into Visual Studio or anything this came after.

So we need to pull those packages down and then try to actually build it. So we'll hit Enter, build starts, reaches out to NuGet, gets everything it needs. and then it'll turn around and build our solution and our PCF project any minute now.

This part usually goes pretty quickly. I'm not sure why it doesn't want to right now. I'm going to cancel that one and try running it inside my real CLI if that makes any sort of difference.

All right, that wants to take forever. So what I'm going to do now is point at something else that I already have. Like one of those cooking shows, it tells you to wait 45 minutes.

Meanwhile, they go to the next oven and pull it out. You'll look at this project I've had. So if I look at what's in here, we can do the same.

What we're going to do is Let's see. Dig through these files. I think I've got a zip file in here somewhere. I've never had MSBuild just check out like that. Good times.

There's nothing there. Of course not. No, it crapped out eventually.

I think it's actually crapping out because it's trying to get to something internal and I'm not using that right now. Not much I can do about that at this moment. Anyway, so if you run that, it'll actually spit out your solution zip file, that you then turn around and go to something like make.powerapps.com. go to solutions and click on import.

This will pop up, you choose your file, you import your zip file that it created, and once that's done, you'll have it in here. So then, you can go into an app and say, in this case, a new Canvas app. Let's say a phone lab.

layout because we got the skinny window here. Maybe it's a little too skinny. Make that bigger. We need to go to the insert menu here, go to Custom and Import Component. This is going to be different than if you go to the plus menu and click on Get More Components.

It's going to look awfully similar, but if you do it down here, it's not going to have the framework components in here. This is just going to be your Canvas components. We're going to Fix that as time goes on.

But right now, we're going to go up here and say Import Component. Go to the Code tab here, and this will hit your environment and see all the components that you've got pushed out already. I've got a whole bunch here as you might have imagined.

So I will use the barcode control. I don't think I have the slider in here. So it added it to the app, but didn't add it to the screen.

We get to do that over here underneath the plus menu. We have Code Components. click on, in this case, a barcode control, which has no UI because it is a demo after all, but it's because the barcode value doesn't have anything.

So if I wanted to say a world, then it's actually drawing that barcode good to go. That's going to be the flow basically. You can then save this and everything's good.

A lot of folks always say, make sure you name your controls for goodness sake if it's a pcf control you pulled in for some reason the name it looks like that right now working on it but hit click on that or click on the three dots and say rename or if you're me just hit f2 and we'll just call that barcode for that case so in this particular one we had a barcode value that we set as a bound property so then if we have another if we added like a text input or something like that and said that the Pro Code value should actually look at text input one dot text which is a more power appy thing to do then we can put here and you can see how it all flows through and if we if we even open up the dev tools which I'll just pop it in that same window to make it a little easier to see We can see that we have that same index.ts file with same breakpoint underneath the update view. If I put like an exclamation point in here, we can see updated view is running. We get our updated value coming in through that barcode container.

Now, this one uses React, so it does a bunch of React stuff and just flows through. So that's PCF in a nutshell, really, right now. I'm sorry that everything fell over. I can dig up a YouTube link to where everything worked properly last time, if you'd like that. But let me just bounce back to my slides here real quick to round things out.

I've got a bunch of reference here. I'm going to put the ones that matter most right here into the chat so people can get them. So getting started is going to be our blogs for when we first went to preview for model-driven and then for Canvas. If you want to show your manager. what this thing is and why why he should let you do it uh documentation is going to be at akms pcf docs that is our docs.com docs.microsoft.com documentation for all things pcf the community forum is an active forum where you've got folks from the product group and also folks in the community trying to help each other out with their pcf questions pcf idea is going to be more of our user user a voicey forum.

If you have not really a bug, but more of a feature you want to see implemented, drop it there. I will just keep linking to my Channel 9 show upcoming at akamass.com. Power Devs show. We're going to start recording that here next month.

We actually recently had a Powerful Devs conference that went all day for a bunch of different things you can do with custom code inside the Power Platform, including a version of this session. that is up on that PowerDev show now if you want to go check that out.