 Hello there, everybody, and welcome to this week's episode of Writing Visual Studio Extensions with Matt. That's me. And this is the episode where James is back. Hello, James. What does he, my friend? Hey, Matt, how are you? I'm doing very well. Thank you. I'm back for the time being so many amazing people, some all around the globe here. Check that out. I mean, I was missing the music. Yeah, I had my camera off, but I was actually doing the dun, dun, dun. You know what I mean? I just, I missed it. I missed it, so. Too bad. Well, you have to. You can go back and watch the recording afterwards. There you go. Perfect. Yeah, we got people all from all over the world today. I guess we do every time, but it's really fun to see. I love when people go in and just, you know, it's always fun. I think it's one of my favorite parts of live streaming and just seeing the amazing community. You know, we're global. You know, I love that the shows are at different times and people stay up late. Like, it's like midnight. It's like, it's late for people. They came for you, Mads. Or morning, right? So Stephen is saying like in Australia, it's Saturday morning. And so, yeah, it's pretty awesome. Yeah. What are we talking about today? Well, I was thinking we should do something about notifications. Or rather, how do you alert your users to some information you want to provide them? And, you know, there are some mechanisms in Visual Studio. Some of them are for internal use only. Like they have no API publicly exposed. So those we can't do. Now, when I say you can't, that's not true. You can, because even internal APIs are technically public if you can find them. But they're not part of the SDK. So you have to kind of do that on your own. And it's, I cannot recommend you doing that. So I'm not even gonna talk about it. But you can. Okay. No, instead we're gonna talk about some of the things that are kind of common, that have their pros and cons, that have some benefits. And also, like, when do we use them for what purposes and so on? And I was thinking we should look at that. So I put in, in the description on the YouTubes, I put in a link to a GitHub repository. And it's just basically one file that shows different ways. And that's, we're gonna go over that today. So this is one of those rare occasions where I've written our first, this might be the first episode ever where I'm not gonna write any code. Because I already did that. So we're just gonna talk about code. Is that right? Can that really be true? What do you think about code? You can talk about code. It's sometimes it's good just to be like, what is happening here? What is going on here? Man, to not write code. What a day. I know. What a day to come back on. Mad's talking for an hour. Okay. Well, so yeah. So let's just look at my screen here. This is the GitHub repo. So a jump on in. I think James just had a link up there as well. If we just take a look at what it is, it's like it's a project and it just has a single file here. C sharp file. And that's it. We're gonna, we're gonna kind of do it in the cheap way. And this is the file we're looking at. It's a package. We do auto load. So that means that this code runs automatically when the experimental instance starts up. And for the purpose of this demo, we are gonna report some progress because that's a very typical thing that you wanna show people, right? You wanna report progress of some task you're doing. But whether or not it's progress or just you wanna show them a message of some sort, it all applies, okay? But I thought like, since it's a normal thing, we're also gonna look at showing progress and some different things we can do. So when the extension here starts up, it automatically reports progress, step one out of three, and then it just hangs back for two seconds. Then it reports progress again, number two out of three, and then it hangs back for two seconds. And finally, it reports progress again, number three out of three, so step three out of three steps, right? And that's it. And so the report progress method is very, very simple. All it does is that it calls a use status bar async method and it gives it the current steps and the total number of steps. And then it just fires it off sort of in the background because that's a thing to be aware of when we're dealing with notifications and UI is like, well, what is the threat safe? What is not? What do we need to be on the UI threat to do and what is okay to be on the background threat to do? So let's take a look at that. I'm drinking my coffee here, so let's see. Okay, so use the status bar. So the status bar is this thing down here, down here at the bottom, this blue line down here, it's called the status bar. So right now it just says ready. So we're gonna update that, okay? And here's the method. Here's all the code you need to do that. First thing we do is that we switch to the main threat because the status bar is a UI threaded element, right? We can call it from a background threat, but what happens is that Visual Studio will then marshal that call up to the UI threat and deadlocks can happen and stuff like that. So we wanna await switching to the UI threat and then continue on. We're gonna get the DTE, the design time thing here and then we just wanna say DTE.statusbar.text and we just say step, you know, X of Y was completed. Super simple. Let's run this. All these demos, I'm gonna just run everything and then it's automatically gonna kick in. So this is the experimental instance. It's taking it's time today. Okay, here we go. So look at the status bar, step one of three. Nope, step two of three, step three of three. And of course, now it says Microsoft Edge because I was, here we go. Don't do that. Go away Microsoft Edge. It's like it's insisting on showing a tool tip. Why do you do that? Okay, whatever. But so now you can see status bar has been updated. So that was a very, very simple way of just showing messages, right? To the user and it's very unobtrusive. So this is a really good, this is really good if you don't need to take attention from the user. If you just want to show like some, that something happened, like some sort of confirmation but it's not critical that the user reads it. But if they look for it, they know where they can see it and they know what's going on, right? So it's a very unobtrusive, very low noise level way of notifying. And it's one of my favorite ways because it's, because of those factors, it doesn't demand attention of the user. All right, so let's do the next one. That's a little cooler, I think. For this particular case, it's use status bar with progress, okay? So some of it is the same, right? Switching to the main thread, we are getting the DTE but this time, we're instead of saying dt.statusbar.txt, we're gonna report progress. Okay, okay. So, hey game, I don't know if you knew this. Do you know control shift space when you're inside a method parameters here? Show you that signature right there. You know what I always do is I always have to do what you just did right there. Yeah, either redo the parenthesis or I do the comma sometimes. Yeah. So just control shift space. Easy to remember. I think so. Once you know it because control space is complete word, right? Or some people call it invoking intelligence. So it's kind of similar. So I think it's okay. Okay, so now we're reporting progress. First of all, we're gonna say, is the progress like should it, are we in progress or not? True or false? Which is kind of funny because as you can see here when the current steps is at the same number of steps then progress is false. So it's kind of a kind of funky way of doing it. So let's just run this. And so the status bar can show progress. What? Did you know that James? That it can show progress? Is that, well, is that the thing where like it's loading up the things and it's indeterminate? Is this indeterminate or this is determinant? No, no, look at that. See the progress bar down here? Oh, that progress bar. Oh, what do you think? Oh, that's good. Pretty sweet, huh? Pretty good. Can you have control over the color of, do you have any other control over it? You have text. The status bar itself, you have text, you can animate. Should we do that? Okay, I'll write some code. Okay. I don't know if I can animate while I'm doing progress. Because that would be like indeterminate, right? It would just be like going and going and going. That's the, that's the, I was a little lazy and I didn't wanna figure out, I'm downloading five megs. I didn't wanna do the calculation to show you how many megs I'm downloading basically. I see. So. It's like one or the other here. All right. So status bar right here, actually takes an object. So you had to know, I searched for animation. I know this. There's a way you can do this if you get the IVS status bar instead. Instead of using the DT, you can use the IVS status bar. And in that case, you can actually use image monocles. So you can have your own image monocles and animate them between different. Okay. So now we're doing this. Let's just, let's do this and then say false. So as I said, I don't know if this progress overrides my animate up here. But let's see. Let's see. Maybe it works. Absolutely possible. And I really like this progress bar, by the way. Again, for the same reasons, it's super. Yes, we get the animation. See that? Oh, there's like a different animation. It's like a little, that thing. I didn't stop though. It didn't stop. Why didn't it stop? Can't stop, won't stop. Well, you know, it doesn't stop because maybe I passed it in something like that. Should pass it in null. Oh, you know, I think when I compile my Xamarin apps, I always see a little animation down there and it looks like a little computer, like munching on bits or something. I wonder if that's what they're using. Yeah. If you, so if you're compiling, you get a little icon down there and we can use that same icon. Okay. Is it better to use that? Here's a question from Steven. Is it better to use the DTE to get access to the status bar or the IVS status bar that I was mentioning? Well, that is, that is the question. I will say that, hey, before I answer that, notice how nothing happened here, probably because there was some sort of exception because I can't pass it in null or something like that. So anyway, there you go. IVS status bar. Let's just, let's just play with it. Let's duplicate this line. So SVS status bar comes IVS status bar three. And you might be wondering, well, what happened to status bar two? Well, I don't know. So you can just use status bar. If you use status bar three, let's just do SV for status bar. So status bar, you have animation two and check this out. So it still has sort of say, how many are there, there are three. But look at this, it takes an array of image monitors. So that way you can actually go in and do it like this. You can also set text. So for that, we have to use IVS status bar. Hit text, set text. It has other things like set color text or whatever. Look at all this, but they don't actually work. I think they're like an old thing. So here we can set some text. So that's another way of doing it, but text is not as simple because first we have to check if SB is frozen, right? Then we do, how long is this a method called? Out hit, if it's frozen, and frozen equals one. So if it's frozen, why is it complaining about that? Oh, that will. Because this returns an integer, if frozen equals one, something like this. Okay, then we can go in here and say, okay, freeze output and no, false, right? And then we can set the text and then we can potentially go in and say, okay, now freeze it. But what does freezing do? Why is it frozen? Why is it a cold outside? Yeah, right, I was just getting to it. I don't know, so, but you can't write to a status bar that is frozen. So you have to thaw it first, you have to defrost it before you can write to it. And it's weirdly, you don't have to freeze it afterwards. It kind of just works, you don't have to, so it's a little bit more verbose, but it's also more powerful, right? You have more options, you can do more things if you use the idea status bar. So the way I look at it is I would, if I'm already using the DTE, I would just use the DTE. If I'm not using the DTE, then I'm fine getting the status bar. It's an old API, it hasn't really been updated for a long time. So you know, I will go on limb and say it doesn't matter. Do whatever you feel is DC's. Yeah, okay. Next up, the threaded weight dialogue. I'm just gonna go on a limb this is the second time and I'm guessing that no one in the audience here today has heard about the threaded weight dialogue because it's not used very often. I searched on GitHub to see how many people actually using it and I didn't really find any except a couple of Microsoft repos and their forks. So use threaded weight dialogue. Okay, so what is that? So now we did our status bar, okay? So status bar, we reported progress. Now let's say that we wanna have more information to show you as something progresses. And we may also wanna block the UI a little bit if it takes longer than we expect. And so that's where the threaded weight dialogue comes in. So what are we doing? Okay, so here it's kind of interesting thing and you'll see once we show it, we can see how it's working. So I'm just keeping a threaded weight dialogue member right here and checking for whether or not it's null because remember this one is called three times this method, right? So I just wanted the very first time I'm gonna move to the main thread to get the service, the threaded weight dialogue factory service. Then I'm gonna create a dialogue instance and I'm gonna say start the dialogue. And one of the things that I can is that I can say, you know, delay to show the dialogue. Look, how long should my task be running before I wanna show a dialogue that something is in progress? Like one second, two seconds, five seconds, whatever. Can the user then cancel my task? So this is the first time we have this concept, right? We actually allow the user to cancel a longer running task of ours and do we wanna show the progress? And then we just update the progress kind of the same and then at the end we dispose it. This looks a little weird. I'll get back to that. Let's just see what's happening. So this should do something similar and then also notice the status bar here. Oh, status bar, see that? Step one, step two, step three, okay. That was a horrible weight dialogue in that it didn't show up. Why didn't it show? What is going on? Let's just do it again. It could just be, what could it be? I don't know. A dialogue could be null. The what now? The dialogue, you check to see if the dialogue. Oh, there it is. There it is. Oh. Did you see it? I saw it. Maybe it was so quick. Maybe put longer weights in there. Oh, man. Yeah, put longer weights in there. Okay. No, don't just add random zeros. 30 seconds later. So I think that's cool, right? So it could actually be cancelable. So let's change this to true. No, here's a question for you because there's obviously a lot of dialogues but I just saw the little compiler muncher. And but this one, right? It kind of consumes a modal dialogue, right? So it has an exclusive lock on Visual Studio which means like nothing else can have. So if something goes wrong and you leave it open, you're gonna like leave Visual Studio on forever. Well, yeah, I think you can set a time on and stuff but I don't think actually Visual Studio is locked. You can still click things. It's always visible. You can't dismiss it. Oh, gotcha. So it's like you really want because we can go into more detail than in the status bar. We can really show, okay, what are we doing in each individual step? What is the current situation? Why are we doing this? You can put in much more information, right? So the threat of weight dialogue is kind of helpful. Also, here's an interesting thing. Notice that I'm only switching to the main threat when I'm creating the threat dialogue, not when I'm updating the progress, okay? And that's because that the threat of weight dialogue I can call from a background thread. Oh, so that's nice. That's good to know. I assume that's why it's called threated weight dialogue. Instead of this weight dialogue, I don't know. And so this dialogue, you know, you could, you would think that you should do end weight dialogue, right? And that would just close it down but that doesn't actually close it. So what you do want to do, you want to dispose it like this because it is disposable but it just doesn't expose the dispose method. Okay, so the thing is that if you were to do this properly, so now I'm using these different services, right? And so how you would actually structure this code is that you would create your, you know, you get your servers ready, your weight dialogue ready, all this sort of stuff. And then you would do that before you start reporting progress. So up here you would, you know, do all your setup of, you know, your threated weight dialogues or whatever, call the services. And so that means that you would basically do a using statement, right? So you would threated weight dialogue. So you would do, you know, whatever code was required for you to do like a get threated weight dialogue. Something like this, right? So if you do it like this, then the threated weight dialogue is automatically called Disposed On and that's the right pattern to do it but it just didn't really work for me to set all that up for this. So it's kind of a weird example in that case but I hope it makes sense anyway. So you don't actually want to call the dialogue Disposed right here. You want to wrap all the progress in a using statement instead. So when do you want to use this? Well, you want to use this when for the same reasons you want to use the status bar because you noticed how it actually wrote to the status bar until a certain seconds threshold. So there might be a minimum number of seconds here where I said one second and that might not be true. It could also be because I do it automatically when Visual Studio starts up and it could be that it's doing other things and it de-prioritizes the threated weight dialogues but either way, the way it writes to, so if you have something where you don't know how long it's gonna take but it might be short so status bar would be just fine but it might take a little bit longer and you need the users to know that something is worth waiting for. They have to wait for something. Then you would use this instead of the status bar and I really like it that it kind of progresses from just status bar to like dialogue when needed and not before. Well, I think this also has the cancellation token, right? So you can cancel it, get notified. I think that's the more powerful part of it too, if you need to, if you want to allow your users to cancel it. Exactly. But you're publishing to Azure or something like that. Yep. So I think that's pretty awesome. And yeah, it's not very well known and I think that's too bad and I haven't used it much and I'm like thinking where should I use this? I feel like it's a really good way of showing progress sort of more in your face when needed and not before. I think we don't really have other notification mechanisms that are like that. Okay, next up, the output window, this thing. So that's kind of nice, right? We want to use this for a bunch of different reasons. Usually when we have, we use it as a type of a log. What happened? You can go back and revisit what happened, like a build log, like when you build, right? I use it in my image optimizer extension, for instance, to write out what happened, how much was able to optimize each image. You can use this for so many different reasons. I like to use it for error handling too, actually. So sometimes I will log my traces directly out into the output window. I do that very commonly. So I'd have a try catch block and in the catch, I would basically log, call a log or that would just output to the output window. And the reason I do that is if something bad happens, which is not very often, right, that I have an exception that I don't anticipate it whenever. I want to make sure I handle it, but I also want to make sure that I put that in the output window so that any user of my extensions can just see, oh, there was an issue in this method online, something, something in this particular source file. And so when they open a bug on GitHub for me, they can give me the very exact precise call stack. And that's because I also ship my PDBs with my extension. Like that's, I think that's the largest, single largest part of my extension is the PDB file. Like if you look at the kilobytes, how much my V6 extensions weigh, the primary weight is usually caused by PDB files. But that's simply just because I want to make sure that if something happens, people can report an error that I can take action on. I think that's okay, right? It's a little noisy, is it? I don't know. I don't know, I use the, I use that output. I'd rather have more information in the output log than not. Cause like if something happens, especially when you're debugging or something's going on, I love, to me, I like to, I like movement. I think one thing about notifications I think about is like when you're building, even if you're showing an animation, if stuff isn't moving, then it feels like it's not, like nothing has happened. Like, you know, some of my favorite parts about, you know, some of my favorite parts about like using some CLI stuff is when they do those like little things across, like stuff is moving. So your mind is naturally like, oh, everything's okay because things are progressing and moving on the screen. So when you show the little bar on the bottom, like that's good. So like, okay, something is moving, but if it stays at one place too long, it's like, okay, well, what else is happening? So you're willing to see stuff happening all the time. And, you know, I think that's, that's why like, I think you're much more willing to hop into a line, like in a grocery store that's moving, right? That's moving faster. I may not be the shortest line, but you see it in your mind is like, oh, that must be the fast line, right? It may not be, but it's like that person is cranking through the register, you know what I mean? Or like when you go to an amusement park and there's like, oh, there's two lines. All right, that one is moving. I'm going to go to that one. So you always want to see something moving. So the more information, it doesn't even matter what it is. It's like, as long as something is happening, something is going on. That's my favorite. Like sometimes with the Xamarin logs, it's like, you know, they're uploading a file and like they'll show 1%, 2%. And I'm like, oh, it's happening. You get excited about it. Excited. No, I hear it. I think it's absolutely spot on. Like we want to make sure that we're not standing still because you know, we don't want to give the impression that the studio's frozen or nothing is happening and the user tries to perform that action again or something like that. There is a thing though about standing in line. I feel like no matter what, I'm always going to pick the line that's take the longest. It's like, it might be the fastest moving line of all times at the grocery store until the moment I step into that line. Then it becomes the slowest line. It's like shorting is line. Is it shorting or? Yeah, that's my thing on that. Shorten it. Yeah, that's the worst feeling is when you hop in a line, you're like, well, that line is moving fast. And then it just stops. And you're like, now I've made wrong life decisions. Every time, every time, every time. Yeah. Let's look at this Apple window. So Apple window is really good for some other things. We'll talk about that. So I'm a fan of the Apple window. Let's see what happens. Did I actually call the Apple window? Yeah, here we go. Look at that. So now a couple of interesting things are happening here. So first of all, I print these out separately. So on each their line, I could have printed them out on the same line if I wanted to. So I control when I want line breaks. I can do ASCII yard in here if I want to. So because I control line breaks, I could actually animate. I could make my own progress bar in here as part of what I'm spitting out, right? Because that's basically just the pipe character, sort of the tall line, the vertical line is a pipe character. I could just like do them next to each other, right? Without doing new line characters to show my progress, for instance. So that's another way I can do that. But check this out. My output, this doesn't say build. Like build doesn't even exist yet because I haven't built anything from this instance. I haven't even loaded a solution. So I can create my own, what's called output window panes. This is a pane. Only I'm the one writing to this. No one else is writing to this. It's not, I'm not writing to the build one or any other. I'm only writing to mine and they're not gonna write in mine. This is just for me, okay? So here's how we do it. Again, this is kind of that little weird thing where I should probably get my output window service before I started reporting progress, right? But anyway, here's how we do it. We get our output window and then we create a new pane. So I just say, okay, here's a GUID. It just needs a GUID. All panes like to have an ID, that's a GUID. And it gives you, it gives what name should I have? My output, it could be whatever. And then we're saying, should it be visible and should it be cleared out when a solution is being closed? It's like, yeah, why not? Clear it out. So you can change this a little bit. If you wanna check something out, there's a newer versions of this. All right, so there's an output window three. So here you can't create pane. You can create pane two and that takes a lot more stuff. Let's see here. Name, invisible, then it takes like, also like, what is the content type gonna be and what are the text view roles? So you can really get into more specific WPF, text editor things, because it's actually a read-only text editor, the output pane. So you can really go into, you know, spitting something out here. You can invent your own content type. You can give it, a content type is just a name. So just give it a string. And then you can, like we did last time when we looked at how to classify, like how to create syntax highlighting of code, then you can go in and colorize your output window if you want that from your extension. So there's a lot of options here. Then we activate it. That just means that, so you can see here I have several of them, right? So activating it means just select it, make it the one that you're using right now. And then we output string thread safe. So I still need to get my output window from like on the main thread. I need to get the service on the main thread, but I can call output string thread safe from any thread. So that's kind of nice. Now this was, this came, this method came in Visual Studio 2017 or 2015. So if you have an older extension out there, you won't have the thread safe. You will only have this version, output string like this. So there is that. And you see here, I put in my line breaks right here. So again, that's optional. So again, I use this when I want to show work that's happening without stealing focus from the user. I'm not demanding their attention, but what I'm doing is I'm doing something in which they can go back and look at what happened. You know, I can timestamp this. So instead of saying, I can put in here like, you know, stay time now. So we can say, okay, exactly what time did any of these steps happen? No, and the user can then go back and look at specifically what happened historically. It's a log of events. And so that's super helpful for a bunch of things, right? So that's the output window. Do we have some questions? Am I getting some questions here that I haven't seen? I think a few people are asking about, Daniel is asking about, are any of these options built into the build processes options so you can have, let's see, are any of these options built into the VS build processes options so you can have it without making an extension? But I guess it's more for the extension builders. Danny, I don't know if I understand your question here because so the VS build process, so MS Visual Studio calls into MS build. Oh, like is there a build task that you could run instead of coding like, hey, I'm creating a library. Oh, that's actually pretty clever. Like I'm a library creator, packaging up a Nougat. Is there a build task that I could call these things on? No, there is not. The build and build order are the ones that are handled, like MS build, the build system in Visual Studio writes to these, but I don't think you can inside a targets file, let's say, or a build task. You can't, because that's just the output to the MS build and it all goes to the same location. So I'm pretty certain you can't target a specific output window pane from within MS build itself. That would be kind of interesting. If you had like a build task that was crunching images, you could literally output like, you know, to different pains or different windows, right? Right now you would output it to the build log, right? Like there's some way for a build task to obviously go to the build log. Yep, exactly. Okay, let's do the next one, task status center. You know what that is, James? It's a status center for all of your tasks. I don't know, I'm waiting for you to get to this notification. You have two updates on the bottom right, but I think that's something completely different. Tasks- Like down here? No, yeah, to the right, the far right. To the little bell, that's notification hub. Yeah, oh yeah, we should talk about that. Yeah, we can talk about this first. That's different, right? Yeah, so I cannot write in here. This is one of those internal APIs. I'm not allowed to write into this. So there is that. You can, but as I said in the beginning, it's I have never done it because it's an API that is subject to change whenever they want to update it. There's no guarantees, it's stable. So I'm like, yeah, maybe not do that. But if you can find it, you can do it. So that's one aspect we can't do. We shouldn't do this. And so that's why I haven't, it's not part of this demo because it's bad practice. Yeah, okay. So let me show, let me show test data center first. And then we can go and look at what it is that we're doing it. So this one is an interesting one. I kind of like this one too. It's maybe the most subtle. It's over here, background tasks. So now we have a background task running in the task status center. It's loading extensions, that's what the task is doing. Oh, and now one more came in. It even has a cancel button and it's done. Step three or three complete. Okay, so we can get in there and you, of course you can combine this so you can also write on the status bar while you're doing something in the task status center. No background tasks are now running. It's done. But here's another really cool way and you can make the user can cancel it if they don't want it to continue running. So when I did my image optimizer extension, it was before the task status center became part of Visual Studio. It was introduced in Visual Studio 2015 update three. So in 14.3, version 14.3. And I remember it's like, man, why does it have to be in a .3 release? It's hard to understand to explain to users that they can't just use it in 14.0. So anyway, that is why my image optimizer does not make use of this because it's anything that runs in the background. It's just kind of nice. So here's how we do it. Okay, I should probably move this down. It does not have to be up here when I... Anyway, let's just go ahead. Again, I'm getting a service, the task status center service. And then I'm just gonna set it up with some options like what's the title, a great title, right? Now I don't know if you saw that. And then actions after it's completed, what happens after it completes? Well, do you wanna retain it and notify if something had failed or you wanna retain a notify when it ran to completion? That might be nice. Kind of say, hey, we're done doing this thing. So that's kind of nice. Retain on ran to completion, on fault. You know, I'm kind of curious about this one. I wanna do this one. Can it be canceled? Yes, it can. Okay, then we're gonna register just the options and the sort of the data here, which is whether I can be canceled. And then we're gonna register a background task. And this background task is really boring. It just runs for five seconds, right? And that's because it needs to take a task. So this is kind of a stupid example because this here whole thing, I would put this in a task and then run that inside here instead, okay? So that's an exercise for the viewer here to figure that one out, I guess. It depends on how you're doing your service, but you register the task, you call a task and then you can report progress along the way from within that task, for instance. So again here, it's percentage between zero and a hundred. So we're just calculating the percentage complete and then we give it a progress text. That's it. Now I'm curious, I wanna run this again because I just retain a notify on ran to completion. I don't know if I've ever seen what happens when a task status center tasks notifies when it's completed. So now I'm curious, let's take a look. So our extension is not loaded yet. Come on, what's going on? Well, that's weird. Is it because I, I wanna do this again, I'm sorry. It's like it got tired of me. Well, that's okay. I'll go back to none, whoop, there we go. So that was task status center. So my problem with test status center is that it is very invisible. I don't know if anyone ever looks in there. Do you ever, like in the comments, do you ever click down here and like look at what's inside when you click that little icon in the bottom left of the status bar to see if there's any, it even has, look at this, it even has a control E, control T, E-T, hey, E-T. Yeah, I can remember that now, control E-T. Do people really go in and look at that? I don't know. I like to know what's going on if it is in there. If I see that the little thing's moving, I wanna click on it. Yeah, but do you? I don't know, there's gotta be telemetry for that. Yeah, no, I'm just curious. So I think it cannot stand alone. So what you can is that you can invoke this command, the E-T command that shows the task so that when your task starts up, you show it. And so I actually have one extension that uses it where it calls in and it shows that, it calls that command that shows the task. So now it becomes much more visible and it's easily to dismiss if you click anywhere else and the screen goes away. So that's a really nice way of alerting to that. It looks like some people said they click it if it's taking a long time to build or something's happening. Aiden said that a old Xamarin one would do some stuff. Latest loss of, didn't even know the icon was there. That's classic. I mean, I think that when there's pop-ups, I think that when you're downloading like a new Xamarin Android SDK or something like that, maybe it uses it, it's hard to say. But think of more things used it for consistency than more people would go do it. Well, seems newer. It has to have relevant information. So I think the way I would look at this is if I'm having to do background tasks that wasn't user invoked directly. So for instance, if it's something that triggers when I open a solution or even when Visual Studio starts like in our case right here, then I wouldn't wanna pop that open by calling in that command to show it. But if the user manually invoked an action that would trigger it, then I would. I think I would because it is still a very low, it's highly visible once you pop it, once you show it. But it's very unobtrusive, right? It's not very noisy because you just click anywhere else on the screen and it goes away, but now you know it's there. And so if you wanna check, you can go in and check and see the progress and follow along, right? So I think that that would probably be my rule of thumb on how to, like should I use it as fine. It's always great to use it. But whether or not to show it automatically when your background task begins, I think depends on whether or not it was invoked by user action directly. Let's take Danny's here. There you have it. Is there a best practice document for extension that lists these options since until you show us these, I did not even know the options were there. Yeah, that's exactly it. No, the answer very shortly is no. However, it just so happens to be that very recently I became a program manager for an effort to streamline all the notifications because we have a lot of different options in Michel Studio. We have the yellow bars, we have all sorts of notifications and toasts as well as Chris is asking for. They exist, but they're not consistently used as you may know. And so there is actually a guideline that we have internally, but it doesn't include everything. And so part of what I'm gonna look at is to do it like look at that guideline again and then I would love to publish it to the documentation site and maybe do that in a more... So it's not just internal basically, it's also for external guidelines, right? So Chris is asking, does VS have a toast style notification? Yes. So you see toast notifications, they come up at the bottom down here, they pop out when there is an update to Visual Studio and they're also locked down. Not only are they in a private assembly, like they're not part of the SDK, but they're even farther locked down. You cannot even use them to... You need like a GUID that has been like basically, that's on an allowed list of valid GUIDs that so you can pop that toast notification. So it's super locked down. The same is true for what's called the tipping service. I don't know if you've noticed, sometimes down here, when you just install Visual Studio and you open it for the first time, it says a little balloon tip comes up, it says, hey, there's something background, things are running down here and you can click always ignore or over here on the right hand side, under here under the GUID stuff, it says, hey, do you wanna add your solution to source control? It's a little balloon tip that's called the tipping service. That is the same. It's completely locked down and it's not part of the SDK. And so those are some of the options that we don't really have. We can't really use them as extenders unless we get real creative and you don't wanna go there. Okay, so here's an interesting one. I know that a message box, you know what a message box is, messagebox.show. So this is maybe a bad example. You don't wanna do this for reporting progress, right? So that's kind of silly, but you do want it to show a message. Now I wanna show this because there is a caveat here that you may not be aware of. The good old message box, that's right, Aiden. This is actually not the good old one. This is the WPF one. It's not the Windows Forms one, even though they're kind of very similar. So I don't know if you can see what's wrong with this. If you can guess what's wrong with what I'm doing here and what the problem might be, let me hear it in the comments. I'm gonna run this and we'll see what happens. This is a WPF message box. It doesn't matter if it's WPF or Windows Forms message box. The same thing, the same issue is gonna show up. Okay. This thing is straight. This'll be a modal-modal dialogue. Boom. Beautiful. Now I wanna go up to the menu. Hey, where did they go? Where is that? It wasn't modal? Where is it? Oh, it's over here. But it's still locking. It's still like locking some thread because where's my, where's the second one? Oh, there it came. Oh, but I can, it's not a modal. But it's still blocking that thread, right? It blocks it from the next one to come through. Okay, so that's horrible. I think that's definitely not what you wanna do. So generally speaking, never use a message box. Yes, Chris is right on. Does the message box need a parent handle? That's exactly right. So you can H-win it to, I mean, you could just H-win the message box. Like you can create a new instance of a message box and then call show on it, I guess, or show dialogue after you H-win it to the Visual Studio main window. That would totally work. But now we're like, okay, that's just a lot of work for nothing. So there's a better way. There's a better way. So let's collapse this one. And instead we're gonna use the Visual Studio message box. So this is inside our shell utilities that comes with the SDK. If you don't know the shell utilities, I mean, it has a bunch of good stuff. Get environment fonts, look at all this. All this awesome stuff you can ask. It's the solution content right now, building. You know, are we in design mode? Open a browser. If you want to prompt yes or no, you can do it from right here. That's kind of neat. Shorthand, wanna rename a document? Go for it. Anyway, it also has a show message box. Takes a service provider. We're in a package class, so that's just this. Takes our message and our title. And then we have to give it a couple of buttons. And first on images. So it's the, first one is what image do you want? I want info. All right, what about buttons? So there. So let's talk about the control space. We mentioned control space earlier. I'm not gonna hit control space. Notice how it only gives me the two options that are, that starts with what I already have, like the old MSG button underscore okay. Because control space is actually not show intelligence or show completions. It's complete, complete word. They'll complete the word I'm typing. And so you see that it triggers intelligence because it doesn't know which one of these two to complete to. They're both accurate so far. If I just wanna show everything that's in this enum, I cannot use control space, right? Instead, I can use a command called show completion item or show completion list, which is control J. Boom, control J. So that gives you everything that's available in IntelliSense, regardless of what's already typed. And so you can see here, I can do like, there's different predefined ones that I have to choose from. Okay, cancel or okay, or whatever. And then I decide which one is the default button, the first, second, third or fourth. So that's about it. And so now we're gonna run this and we can see the difference. Not only does it look a little bit different, it looks a little bit different because it's, you know, but it looks a little bit more visual studio-y. If I had a longer text, it would be prettier to be wider. Oh, it still blocks the UI thread, right? So take three seconds, but look at this. I can't click anywhere else. So this is correctly parented to the main window of Visual Studio. So when in doubt, no, not when in doubt, just don't use the message box.show. You can use a message box, you can new up a message box and then you can age-wind it. But that was it. So when do you want to use a Visual Studio message box or message box? There are a couple of scenarios where you want to do this. One is when there is something that the user have to make a decision on that you can't proceed with what you're doing without them giving like a yes or a no or something like that to a question that you're posting them. You definitely want to be in their face with that. You don't want to be on the status bar. There's no buttons, right? Or, you know, you want to pop that up right in front of them. Another one is if something fails and it requires kind of a little bit more text to convey exactly what's wrong or, you know, then you want to do message box because it can hold more text. So that's another reason why you want to use why you want to use a message box. You know, it's, if you, if, you know, these different techniques are all demanding attention on different levels. It's almost like they're different severity levels associated with them, right? And we know from a lot of people always tell us that, you know, Visual Studio notifications are too loud sometimes or they're easy to ignore because they're not relevant and all that. So you always have to think about not overdo it. Don't share information that is not interesting to the user just because you can. Don't notify them of things that have no consequence to them. And, but when you, when you have something, you know, show progress of something or you want to give them a message about something that they might find interesting, think really hard about how much attention you want to demand of them for that information. Is it critical information? Is it nice to know, need to know? Do they have to know now or is it okay if they know later? Can they, do they need to take action or not? So if they need to take action, then we can look at, there's just a couple where they, whether they can take action or they need to take action, right? So they can take action. Some of the ones you could, where you can cancel something in progress. It's like, yeah, that might be nice if you want to offer that. The message box of course is there. Then we have the info bar, the yellow bar that comes up. It can also have buttons and links on them so the user can take action. We're not going to look at that today, but that's actually part of the SDK. So if you want to look at how to do one of those, I have, I have an example, but you can easily find them out there. You just need to know what to search for. Those yellow bars are called info bars. This one, see here? Like this one is located inside solution explorer. You need to see it show up again here. So hang on. There it is, that yellow bar right there. So here I can customize icons and links and stuff like that. So if you're interested, go into code tour BS and look at that repo and it's under code tour info bar.cs. So it's because it has a lot more code to it. It's a little bit more of a boce. That's why I didn't show it, so. But if you're interested, you can go check it out on code tour. And again, it's really, really important that you don't burden the user with being too noisy, right? So pick the right notification type for your scenario. Thank you, James, for posting that. Oh, you posted that same link again. You didn't post the code tour of yes. I don't know if that was what you were attempting to do. Danny says, not a service notification. So it will not show all the time. What do you mean there? Not a service notification. Like if a service was failed, I'm not sure. Okay. James, did we take all the questions? I'm browsing through here. So I think Chris talked about the parent handling which you talked about. I think it's fun because you do randomly, or often I would say, see a lot of these different message boxes and figuring out if you are building one that you can actually access a lot of those. Which I think is cool. Yeah, I agree. You can totally do it, but you just have to be aware of the pros and cons. I really like the idea of having like a document somewhere that explains the different way of notifying and then also explains when to use which one. Design concept, like a design guide. A design guide. We do have a design guide on the docs, but it does not, I don't think it talks about notification. DocsMicrosoft.com. Yeah, like Google and Apple, they have like the design guidelines for like iOS and Android, right? And it's very similar. It's like, hey, you're building something for this thing. Here's the thing. Here's the thing. Well, there is a design guideline, though there is one, if you can find it. Well, that's right there. Extension, extender, user experience guidelines. All right. Colors, menus, interaction, notifications and progress. Oh. Oh, hang on. And better info bar, mouse cursor changes. Look at this progress. Oh my God, error list. Okay, I'm gonna have to... Put that in, I gotta put that in the GitHub repo. If you want, yeah, if you want to know, like if you ever wanna share a link to Microsoft docs, just remove the localization information up here. If you do that, if I were to go this, it automatically puts it in based on the browser. So if you share this, it will translate it right to whoever's gonna read it. Okay, should I put it in a read me file? I will. And then what we need them to do is like there's a share button on all those, but there needs to be a share, copy to clipboard on the docs page. You know what I mean? Yeah, you're right, that might be. I'm sure there's not, I don't know. Guideline for notifications and progress for showing. I'm sure if they're like, yeah, don't paste in links like that and mark down, you have to like do this basically. Okay, I can do that. Okay, so we added this sign guidelines link. Yeah, save it. I don't know if I can post a link, can I post a link to the comments? You can do it however you want, I think. But it does it become a link, like a clickable link? Yeah, inside the, yeah, that works. We don't see it, but it will be clickable on their end because we're admins, yeah. Okay, all right. Three months later, now Mads knows that you can post a link. Yeah, that works. This is crazy, right? I'm doing all this and I didn't even know that was a doc. Look how long this doc is. It's good doc. We have great doc writers. But you know, there's colors. What's going on here? Whoa. The status bar changes color based on the state the Visual Studio is in. So when you just, when you're building, when you're debugging, it changes to orange. Someone must have seen that, right? Yeah, when you do use hot reload, it changes, it'll say hot reload is ready. Gold bar, we call that gold bar internally. No, you call it, some people call it gold bar. It's gold bar. Some people call it yellow bar. The right word for it is info bar. Gold bar, we call it gold bar and then we always joke and we'll have gifts of like gold bars, like doing stuff. It's gold bar, it's gold bar. What's that? That's the notifications, but that moved. What is this? Notification window, did that go away? Oh, is it, it's not currently extendable is what it says, that's correct. Air list, yeah. Status bar, embedded status bar. What is an embedded status bar? Oh, up here. Yes, oh yeah, so you can add your own, I guess. That's right. Windows train notification, that's just Windows. So of course you can notify using the Windows APIs. Progress indicators, oh wow. What, they don't talk about the threaded weight dialog? Okay, but there's a lot of stuff here. That's awesome. Oh, a spinner. What are those ants? Remember those, was that Windows 8 that had that or a Windows phone? It was like an indeterminate progress indicator. I think Windows UWP still has that. Yeah, Windows on 7 started it. It's a good one. Tool window, yeah, you can do it up there. Look at all that. Up a window, info bar. Man, they go in detail here. They even show how to do some of this stuff. Okay, fantastic. Mads is amazed. What's under animations? But the only thing is that now I have to update this document too. Yeah, best practice, be selective, timing and speed. Okay, so if you want to do any custom stuff, do's and don'ts, metrics. What's up in there, some good gifts in here. Like here's what it's doing. No. Simulate. Oh, look at that. We have great docs writers. I work with them every day, they're great. And I think that this guideline back when this was created, I think that was our internal guideline too. And that's why it's so, like it's so, there's so much stuff here. Evaluation tools, button tags, dialogues. Okay, well, how to work with fonts, colors and styling. Okay, well, there you have it folks. So go check that out. So yeah, just follow that link that is now in that repo and you can see for yourself. All right, so, just reading up. I think we're out of comments, out of questions. Did it? Yeah. Full guide, I love it. Oh my goodness. Cool. Okay, well, let's say that was it for today's episode. Next week, I'm pretty excited, James. I know that you're gonna be pretty excited because I believe this was your idea. Next time we're gonna take a step back and we're gonna do a whole episode on understanding and building our first extension. So this is where we'd go all the way back to someone that has never built an extension before. And we're basically doing step by step explaining the anatomy of an extension. And then maybe we can use that episode to something that we can send people whenever they ask, how do I write an extension? Maybe we can just, we point them specifically at this episode that we're gonna do next week, if it's any good. So maybe we should not, should we then do it formal? I should wear like a suit and a tie and like we don't have any banter at all. It's more like a, like a... We could put time codes in the bottom. We could be like starts now. You know, on YouTube, you can have a little time codes. So we could update it later. That's a good idea. So they can jump back and forth. Now, how does the command system works? What is a, what's a package? That sort of stuff. What is inside a V6? It's a great question. What's in the V6 manifest file? Nobody knows. Only one person knows. Pats. Well, I think it was gonna be good. Are there people saying that I'm wearing a wig? No, someone wants to know what you put in your hair. Ah. You like some gel? Yeah. I don't think it's a wig. You could pull on it. It's real. It's like a, it's like a yellow, it's like a black little round box with a yellow sticker on. Perfect. Very descriptive. You know why I don't know what it is? It's because I have an Amazon subscription and they just send it to me every six months or whatever. So I don't have to know its name to order another one. Locke said gorilla glue. Is it gorilla glue? Oh God. They never have to put anything else in it Well, didn't you hear? Didn't you see that video? Was it a TikTok or something like that? Oh, I don't know. I'm not on social media. You know me. Yeah. When I have someone you put gorilla glue in their hair, that's not good. Yeah. I don't know what the story was. I just saw that that was a story about it. Oh, is it? My wife's always sending me all these memes. I'm like, I don't know. I don't know what's going on. There's always, always kids. Nice. People are looking forward to this. I'm super excited for this next one. It's gonna be awesome. I may not be here, but I'm excited for it. That's right. We have John Galloway back next week. Yes, I think so. I believe so. Okay. All right. I will fill him in and then I will tell him to wear a suit and a tie. He'll do it. He'll do it. I'm sure he will. I don't know. I don't know. Down there in sunny South California, he's, I don't know if he even owns anything with long sleeves. That's a great question. He's not short. That's a great question. Yeah. We'll find out next week. Tune in. If you want to figure out if John owns pants, tune in next week. Tune in next week. Yeah. Okay. I think that's it. Thank you so much for watching everybody and have a great weekend. And for those in Australia who's already doing weekend, continue on and see you next week.