BrandGhost

WPF, Plugins, Dependency Injection - Live Coding in C#

June 16, 2024
• 953 views
Let's do some live coding in C#!
View Transcript
see stream is coming through I think we're good to go that's awesome okay well it's let me get my S more centered here what's going on Saturday night what else is there to do but program right um we're going to be doing some WPF which I haven't touched in years so I'm going to be a little bit Rusty um it's going to be interesting but I want to focus on a couple things I want to dive into some WPF I want to look at dependency injection stuff so I'm I'm interested in kind of putting together a couple things one is I want to just kind of get familiar with WPF again and the other thing that I'm going to be doing here is looking at I service collection in C uh if you are familiar with a lot of my other content I use a ton of uh autofac for dependency injection so I'm going to be trying to avoid that and trying to see if I can build out some custom things to use I service collection for that so we are going to jump into some code in just a second but um that's going to be the theme of what's going on here so we're going to put a little WPF application together probably won't get too far in terms of uh UI design and stuff like that that's not really going to be the focus though so we'll explore some WPF and really it's going to be about trying to do a bit of a plug-in system with I service collection so that's the goal we'll see how it goes um as always if you're new to my live streams ask away in the chat I'm happy to answer questions on anything you want to know about um if it's not related to the topic that I'm going through that's totally cool too so I will be watching chat I have this going to seven platforms right now so uh one of the chats is joined and I should be able to put that chat up on the screen so I think the only chat that is not coming through on this is going to be Tik Tok but I am watching Tik Tok chat separately so again if you have questions and stuff please just ask I'm happy to try and answer so with that said uh C related questions totally cool if you want to ask anything about software engineering if you're not familiar with who I am I'm a principal software engineering manager at Microsoft but I have been programming for 21 years and have worked at startups and done all sorts of cool stuff so happy to try and offer any advice if that's helpful okay let me get my screen switched over to visual studio we will try to get our first little bit of a project set up and we'll see how things go so screen I got to bring my face back there I am hopefully that's coming through clear for folks if at any point you can't see clearly or audio sucks or whatever it happens to be just let me know happy to try and adjust so what I'm going to do is just start off with the new project uh I have no idea what I want to name it or anything I'm probably going to remake a lot of what I'm doing uh not a big deal for now um like I said it's just more to get familiar with things so I do want to go make a WPF app if you are wondering why I am not going with uh Maui or something like that it's because for what I'm interested in building I don't really need to go AC crossplatform or anything like that so I'm not too concerned um so we're not going to do that go pick this yeah I don't know what I want to call it I'm just going to leave it as WPF app one because as I said I will go remake this entire thing at some point okay so for context to I before Microsoft I did a ton of desktop development so it used to be Wind forms and then WPF so I would say what out of 21 years of programming only the last four years or or so have not been inside of like Wind forms or WPF so um this used to be what I was really familiar with but I have not had to program in WPF and make UI and stuff so it's been a little while um I can explain some things about what I like to do before and we can check that out got our main window here but this is the application oh really this looks like it's a lot more stripped down so I have not seen WPF apps since I don't know like I said it's been a few years now so I'm actually pretty surprised that there's not a whole lot in these now so like there used to be like all the startup code and stuff so that's just gone which is really cool um I'm actually kind of shocked so again if we go run this as an example right we're just going to get a little wind it's not going to do literally anything which is fine right totally empty canvas for us to go work with and stuff and if you haven't used WPF like what you're able to do maybe my toolbox is here oh I haven't I probably haven't even set up my visual studio to develop well in here but you can go add stuff into the grid right so if you wanted to go put a button that kind of stuff but I'm pretty sure my toolbox usually oh there we go I don't know why that took a second to populate but um sorry and the text might be a little small just because my resolution's high and I'm only showing a small portion of my desktop here but you know you can drag and drop stuff right so if you want to go put a checkbox there you go I put a checkbox actually put it inside of the button which is not what I would want um but anyway you can go drag and drop and it's kind of nice because you get a little designer here or you can go work right in the zaml which is also pretty cool um but I am probably going to have to search because like I said this is completely different I want to be able to work with um some dependency injection and there is no startup or entry point that's probably the biggest thing that's missing here so I need to go uh I'll be talking as I'm kind of doing a search on the side um but that's like I was saying one of the biggest changes I'm noticing right now is that what you used to have is like a program.cs file there would be a startup um is there like a override like you'd have this kind of thing like a startup method you can go configure um but it's just kind of odd not really sure where that's all moved to so oh interesting okay so someone else is suggesting can I pull this up on my screen yeah let's do that one sec this kind of pattern here I'm just obviously I'm on stack Overflow uh I don't even know if chat GPT or whatever would be in a good position to be able to do it but here's what I want to do right I want to be able to go make a service collection so we can do some dependency injection but what we used to have was this kind of thing so again this is over it's not even overriding they've hooked up an event handler in the zaml so I'll walk through some of this if you're not familiar with the what I'm saying in WPF but in WPF itself um so let me go back to the code if I go back into here this window F uh this window if we're looking at the code here we should be able to do something like add an event handler so on uh what do it just start up it's on the window oh it's on the application itself my apologies um so I've done let's see right so you'll be able to do this and then you should be able to say something like right you can add an event handler which I wouldn't bother doing because we just have this here to go override but that's the part that I'm kind of curious about so again if I pull this back up you can see that this this zaml maybe I had to click over here ah there we go that's really odd so you can't tell because you uh aren't looking at my mouse as I'm streaming but I was clicking on the window and then onto the zaml file for the app but I needed to double click I thought it was just going to load as soon as I clicked but it doesn't so if you see that I'm clicking in the solution explore it's not toggling um but anyway that's that's that so if you wanted you could do startup new event handler then if we go into the code behind you'll see that it added this event handler so a comment about how I like to write code or how I used to like to write code in WPF is that I try to avoid as much zaml as possible and this comes purely from a testability perspective things may have evolved greatly since I've last used WPF but what I used to find is that the more stuff you put into zaml the less you're able to test things so for example if we want to be able to go test any of the code that's inside of here um or even if you were to put it in the code behind here it's any EX tries to avoid Sam yeah that's the that's the reality um so the problem is that if you end up having your code that you want like your business logic or anything that you're interested in testing and you're coupling it to the UI component so again like on this window for example the more stuff that you put in directly to your UI controls the harder of a time you have and that's really unfortunate because a lot of the stuff that uh that sort of Microsoft setup for WPF is like you can do binding right in the zaml and it just makes it feel like it's really awesome to drop all this stuff right into zaml and you don't have to go write code but then the problem Becomes testability of this stuff so again I'm talking about this as someone who hasn't worked extensively in WPF in years now but this used to be something that I would try to avoid uh a tremendous amount so anything that you're putting in here is purely visual in my opinion you want to strive for that as much as possible even then we would build stuff and uh try to control visual aspects in code and the reason that we would do a lot of that is that we could go write tests that would basically go exercise um even things like collapsing elements and stuff because we could trust that if our logic behind the scenes was doing what it needed to do then the UI would take care of the rest um so couple things in the chat here so zaml is kind of like Java f for the net UI I'm actually not sure what Java f is so let me go have a quick Peak um and actually one of the top searches was how they relate to each other right so let me pull it up here um so stack Overflow this is what we used to use before chat GPT for folks aren't familiar um oh so yeah Okay cool so some type of markup language and they say which it's similar to zaml um property binding yeah it sounds like it's probably the equivalent type of thing um so the other thing uh so Nick Hodge in the chat here on YouTube is saying hello mvvm pattern so that's the model view view mod what is it model view view model um so there's a couple of different things you'll have MVC model view controller and mvvm so I think it's model view view model model view yeah I just had to search it so there we go right um and model view view model is nice but also I think there's some downfalls to it and basically it all comes back to the more stuff that you jam into zaml the worst time you're going to have so you can um like one of the things with model VI view model that a lot of people will say is like hey like you're not putting code behind so let me go back to the main window here like basically your code behind should most of the time just look like this right it's it's sort of an exaggerated pattern where it's like if you're putting any code behind that's not just like the initialized component call like probably a code smell you don't want to be doing that maybe for custom controls and stuff like that that's where you're doing a little bit of this um but if you're putting logic behind here people are like that's a big no no so generally what you end up doing is using something like mvvm and the goal when you're using mvvm is that you're able to move away from having uh you you end up moving away from having the stuff directly on your control so in this case this is a window control and you would do it in a view model that can do the binding so you don't manipulate the control or the window in this case directly you manipulate a view model right so you would have I'm just going to do this quickly you might have like a um no co-pilot that's not what I want you might have a uh class um might do a model and you okay here so there co-pilot thank you very much you could have like a title and then you would go basically to your main window and you could do something like you would do a binding here and you go bind to a property right so oops let's close these ones off right you'd have to go have a what do they call it context is that what it's been so long man anyway you can go buy to stuff and that way you can set the context of your I think that's what you need to do right you set a context not cont oh maybe it's maybe windows don't have a context anyway you buy stuff and that's done directly in the zaml but now if you want to go test out that stuff if basically if you want to do like integration testing across data context is that what it's called let me double check thank you in the chat I knew the stream was going to there we go thank you I knew the stream was going to be a little bit rough because it's been so long since I've had to do this but this is all I used to do which is kind of funny so so you could set a context here's another thing that I don't like the data context is mutable from the outside this is just a bunch of patterns about WPF that I don't like um it's mutable right we're able to get it and set it I don't want that to be able to happen I want to be able to do something like pass in a main window view model right this is what I want to have happen but this is a pretty big no no in traditional like WPF patterns because when you go to do this kind of thing I think it might break oh it's not breaking here interesting um it probably breaks the preview uh and I think there's ways you can kind of move around it let me explain why it will break the preview when we do more complex things though it's going to be instantiating the main window class with a parameterless Constructor right if we go back here it doesn't know that it needs to pass in if I go back to the code it doesn't know that it needs to pass this in when it wants to give you the preview so a lot of the time what I found as I was fighting against how much quality of life do I want with a preview versus again I'm going to go back to the code how much do I want to just be able to make stuff support dependency injection in a nice clean way that was one of my biggest struggles and I'm pretty sure it's been a long time but I'm pretty sure you can basically set like a like a default um preview only mode kind of uh data context I think you can do that and that way when you want to go do previewing of things you have something there as a placeholder so that's one strategy you can leverage to kind of get some of that functionality back but anyway um main point is mvvm is the proposed pattern for all of the WPF stuff but I actually found that I moved towards a hybrid of mvvm and MVC so I still had controllers and I would make my code kind of work the opposite direction so what I mean by that is a lot of the times in WPF I feel like you are constructing things UI first so all of your user interface elements you kind of make from the top down that's generally how it felt to me and instead of doing that I like to kind of go from uh the back end first so I would have a controller that was able to say hey I want to be able to go put a window on the screen so uh there would be some type of uh pattern to allow me to go do that and control things from the code behind versus from the user interface it sounds kind of weird but it basically what I'm saying is a lot of the stuff in WPF I liked but a lot of the patterns felt backwards for how I like to code okay so that's a lot of me blabbing but let's go back to what I was trying to check out here and that's going to be inside this so what I want to be able to do is get this application going I'm going to go back to good old stack Overflow here so they were suggesting doing this startup event handler I don't want to do that right that's what they have here I don't want to do that what I want to do instead is just do this in the override so to give you an example we can probably copy all this stuff right we go put it here so we'd go make our service collection I need to well sorry my mouse is getting in the way so we need the nougat package if you're familiar with asp.net core you kind of have all this stuff available to you right away when you start going outside of asp.net core um the service collection stuff still exists it's in a Nate package but that's what you have to go do so what they had done in the uh stack Overflow examples they have this configure Services method my goal as we go through this stream is that I want to go basically build an autofac equivalent to this and it's worth explaining what I mean by that so let me finish the rest of getting this service provider in place and actually I'm looking at this this is in an on Startup do we want to do this in the Constructor of the application like maybe um I don't know yet but we'll leave it here for now so I service provider put that there and then configure Services we will leave that empty for now oh actually sorry they did do this in the Constructor my apologies I have this kind of out of order here so the Constructor is going to be the first thing that runs in here it needs to be because that's how C works when you go to construct an object this is what's going to run the first time we make this so there's going to be other logic that's running in between this Constructor running and this on Startup method happening so what they're doing and this is I thought they were not doing this I'll pull it back up I thought that they had this stuff that I have highlighted in the app code uh the Constructor I thought they had that in the on Startup but they do not which is good cuz I don't want want that so you do this in the Constructor we can make this read only this is going to be our our dependency container that we can work with then what they do and what makes sense to me is that you ask the service provider get required service main window show which means we have to go register the main window so uh well how do we do that there we go add a Singleton main window this should technically work but we had the application running without doing any of this right which means we have some extra code somewhere and that's going to be first of all I got to get rid of that event handler we don't want it but you can see that this startup URI says main window. zaml I think we can get rid of that and basically keep our app uh zaml extremely lightweight you can see that I'm even with this brief example I am moving away from zaml as much as possible and trying to go into code the more that I put into code the more I can start pulling out into smaller classes have things that I can test just on the code itself and completely avoid doing anything in zaml um I think this will work but let's find out of course it's going to take a moment there we go so look it does the exact same thing not exciting at all um but maybe we can do something like this just to kind of show that it's working because I realized that that looked uh the exact same we could do something like main window I wanted to do like title right just so you know that it's actually running this code and not something some leftover remnants of what we had before but you can see the title says hello world now oh wait oh it's delayed okay I checked the stream and it wasn't showing up it's about to have a heart attack that I was uh I was sharing the the window and not the portion of my monitor that would have been awkward okay so cool this stuff works and in fact what's really cool about this is that we can go do the data context with the binding now and what I mean is if I go back into here oh it's not jumping because it's partial if I wanted to do this main window uh uh yeah new model I guess is the there we go so if I wanted to do that I could do this kind of thing again I don't like that data context is mutable from the outside it really bothers me but we could go do this I'm going to go move this into a new file apparently not Visual Studio really that's so weird oh that's a bug for sure um um okay that's really bizarre you might not have observed what just happened but um I used a refactoring tool in visual studio and when I bring this up this menu what should the menu item's gone now but what you're able to do is basically move the class into a new file you can see that that's not there now but if you look in the left hand side of my solution Explorer again I know the text is very small I apologize you can see it made a new file but what it did was it moved the main window with it and that's not what we want and that's because that's so disgusting you can see how uh main Windows Cs and zaml are now separate but APPL and APPL CS are together so anyway it's just annoying um there we go it'll Nest it now that's what it was supposed to do so the bug is that the code used to exist in here right I pulled it out and then it decided it was going to move both both types into the file that's really funny um okay we don't need all this stuff here and now we have a view model but if we were to go run this I suspect that the application Should Crash it might not and the only reason it might not is because main window right now the way that we have it defined it has one Constructor and it must take in a view model I don't have a view model registered on the dependency container right it's only main window there is no view model so if I go press play it Should Crash because it should say it can't find that view model so that's good the only reason I was thinking it might not is I can't recall if there was like some I don't know some other Constructor that's by default on a window type but there isn't so that's good now we can go do this and this works but we're not doing anything with that view model right so I can't remember the Syntax for binding stuff uh title it's not just going to be title though or maybe it is I think you do this and it figures it out no data contacts found let's go see there it does work so the intell sense is kind of weird let me go back and explain what was just happening there um if we look at the the zaml I put binding and then title but the intellisense wasn't showing anything coming up and I think that's because the data context right now doesn't have a assigned that's going to bother me I used to know how to do this I think you can do I might have to search it but the idea is that it doesn't know the type of the data context because if we go back to the code not there um in here data context itself if you see I'm hovering over it it's just an object right so when you're in the editor it doesn't know the type of your view model it can't know because it's just an object but there is a setting that you can put on here somewhere to be able to say like data context type or something let me let me search it uh zaml intelligence for data binding not working let's see ah thank you Nick hodj clearly you've been you've been doing this more recently than I have this kind of thing let let me do this I hate how this stuff is all spaced and then I should be able to do main window view model there we go so now title shows up yep thanks Nick hod he says previous life until October 23 was zaml this like I said I used to do this stuff for years um it was all Wind forms and the forensics company I was at before Microsoft we transitioned from Wind forms over to WPF I built tons of stuff in WPF um it's just been so long so I actually don't think that we knew about this until very late in our our building of things there which is kind of funny because it's super helpful it's super helpful to have all the intelligence come back up especially when you're in the zaml and you're like where the heck is all this stuff like a lot of things going on but this really helps because I mean we only have the one thing title but if we had other things that we wanted to work with we'd be able to get them and thank you for the comment on Tik Tok I appreciate that so yeah if we go run this now we should get the binding working there we go right it says hello world so we have the title all set up and just to kind of briefly explain where we've got to so far we've basically gone ahead and done dependency injection on the main window to pass in the view model that we want to work with using a service collection here and then basically it's all done with respect to binding behind the scenes that's because we set the data context in the Constructor and one last spot to check we have The Binding done in the UI now I'm not going to go this far um but one of the last things I remember doing in in terms of like software design I guess with WPF is that we were we were starting to move away from even having the bindings in the in the zaml um so we started doing that um cuz like I said we just wanted to move everything away because it was easy enough that you could have bugs like this so you're refactoring stuff you're moving things around and you delete The Binding right how are you going to test if that works in code right like it it just it just isn't going to be there so kind of crappy um I wonder though I think to kind of prove a point let's do this well we'll go see what the title is right the title's empty because the binding hasn't actually taken place sorry I I realized I just zoomed in on the code but I can't zoom in on the tool tip this is what I get for uh all my YouTube videos I I go 1080p but this is 4K right now and you have one quarter on my screen so um the the variable XXX is empty so the data context doing the binding for us that we see done here this has not yet occurred and what ends up happening if I'm not mistaken is that we basically need to wait to go render the control to go allow WPF as a framework to go say ah like yes we need to go do the binding so we would have to do the show part uh and if I do show I think that's a blocking call show dialogue is supposed to be blocking but I think main window show is also going to block so we sh oh no we hit it so okay we do get the binding taking place so that's good so I can't recall the exact problems we used to have with this kind of stuff but maybe it is the fact that we'd have to show this first yeah you have to hook into events on Main window to see what happens after binding um and this is probably what I would want to do with my main window is show it as a dialogue but anyway the point is that we had to actually show the window to be able to get the the data context and The Binding to happen and if you're thinking about it from a testing perspective as much as possible this is my uh opinion for testing user interfaces is that when I test user interfaces I don't want to see the user interface sounds kind of funny but uh My Philosophy is that I want to be able to test as much as possible about a user interface without ever having to see it and the reason why is that I want to be able to check as much as I can with code and as soon as we have to start showing user interfaces having any visualizations and stuff occur that is not a good setup up for automated coded tests it's a great thing if you want to be able to go look at stuff to walk through scenarios I think there's tons of different situations where you may want to have uh you you could do like recorded playbacks of clicking through an application or something like that you may have situations like that that you want but if I just wanted to prove like this is how simple it is if I just want to prove that my main window is always going to have the title that I set inside of my data context I don't want to have to show a window to do it it's just too heavy-handed so something I know we're using WPF right now but something that was really cool in Blazer if you've used B unit um what I thought was super awesome was that you don't have to work around things this way you can basically just ask it to render the screen for you and when I say render the screen I mean render the HTML for it so it is all done in code and you don't have to go show a window and have a visual thing kind of happening so um definitely B unit for Blazer is super awesome in that regard but just a sec cool okay so not super exciting yet still trying to remember how WPF works but what I want to do is focus on not that probably not that and probably not that I want to focus on this stuff that we have here and my my zoom is broken I can't zoom back out of the code come on there we go oh man it's the simple things right okay so my goal that I want to explore has very little to do with WPF actually it has everything to do with using service collection and doing assembly scanning so there is a Nate package that's called screw Tor I believe is how you pronounce it and I haven't really used it much I've written a couple blogs about it just on the usability but it's been a little while and this should allow you to do assembly scanning and if you're wondering why if you're saying Nick why the heck do you want to do assembly scanning you don't even need it here it's just because in autofac I like having modules and I did say that I was going to show what I meant by that so let me get autofac installed we'll take it away later but just so I have something to compare to okay we'll get this installed I want to show you the difference between what we have generally yeah Nick autofac this feels funny it sounds like I'm talking to myself Nick Hodge I need to be able to say your last name or else it just sounds very bizarre um I love using autofac but I'm finding because service collection you know I service collection everything in asp.net core there's so much that's getting built around this now that I'm finding that because I love using autofac it's almost making things more problematic so my goal is to see if I can get more comfortable with using ey surface collection because I feel like Microsoft has advanced I service collection so much since I started using Auto independency injection like autofac used to and it still has more features than the built-in stuff but it used to be like there was no comparison right there was just no comparison because autofac had so many features but now ey service collection is much better um yeah Nick hod say love autofac but have to marry eye service collection that's exactly it and you can hook up autofac to I service collection you can use it as or I guess the way it works in asp.net core is like you use autofac as the service provider Factory or something like that so you can kind of marry them together um but it's still weird and I keep running into problems or I'm like ah man that doesn't work exactly how I'd like so the pattern that we generally get people using is extension methods and I know a lot of people love extension methods and I'm not going to say that I hate them but I don't think that they're the tool that I want to use for this sort of thing and I'll explain so what we get with extension methods is that we can go basically pull this and I'll just do this part quick so I can extract method I'm going to call it configure controls and this is not an extension method yet it's going to have the exact same functionality but you see how it's calling configure control on line 16 right what I'm going to do is I'm going to pull this out I'm going to go make a public static class um sure it knows uh I want this code co-pilot guessed at what I wanted but it wasn't quite right so what we're able to do now is not a whole lot of difference but it just makes it look nicer I guess for most people right yay we just flip the words around um but I have a fundamental problem with this when it comes to plugins and again if you're not familiar with a lot of my stuff and how I design software I talk a lot about building with plugins because uh it is a for at least for me it's a forcing function for modularity and what I mean by that is I am forced to go write code inside of individual plugins and it literally like in code physically forces separation of different things and by putting those boundaries in place yeah you might go ah it makes it harder to work with but that's literally the point is that I'm trying to create these boundaries that I have to to play Within because they enforce the design that I'm trying to have um yes it does add complexity yes it's overkill for many things but uh especially when I'm developing software on my own like I said it's a forcing function that lets me guide the code I'm writing into designs that I want to have so the problem with this is that on line 16 I still have to call configure controls I don't like it I don't want to have to go add more code to configure things so if I were to go add a plugin to this right what I would love to be able to do say I wanted to show um I'm going to go if we run this just for a second just so I have something to talk to um so we have this screen says hello world in the title say that I wanted to have a plugin system that would allow me to dynamically drop controls into this window right so when I say Dynamic I mean I don't want to go rebuild the core application and I would like to be able to drop a dll into the bin directory start the application up and without having rebuild the core application we get a new control that's what I want the problem is that when we use service collection this way with extension methods you would have to write a line of code inside of here that knows how to go configure that thing and the solution is not in the end that we never have to go register the dependency you still have to register the the dependency but I don't want to do it in my core application I want my core application to be super dumb the Dumber my core application is the more that I can move out logic into plugins into different feature areas where I feel like it belongs I don't feel like my core application should know about how to go register the different dependencies to me that just feels wrong and obviously right now in this simple example with the main window I don't have a good example to make a case here but I'm just trying to articulate that's the the challenge that I try to overcome with this stuff so what I would like to have is that as I continue to add features and plugins I don't want to have to keep adding more extension methods right obviously you wouldn't do it this way you'd have better names for the things you building but I don't want to have where I just keep having to to a line onto here I don't want to do that I don't want to touch my core application yes I will still have to go do something like this to register the dependencies but I want to do it in the feature area or the plugin area that I'm working with so that's that's the point I'm trying to get across here now how does that work with autofac right so I do I did did I add autofac or was I just blabbing too much and forgot to add it let me double check I did add it okay okay so the way that this works in autofac is similar to what you see up here so we would do a container Builder oh my goodness this auto complete just let me add it up here that was a nightmare there we go okay so we go make a new container Builder there's no way that's a thing okay good what we would do is generally I like to make a module so I'm going to show you the comparison it's going to look very similar to what we have here uh public sealed class so we do a load so as you'll see it's going to look very very similar right you don't need the base load for autofac but you would do something like Builder register type um you don't even need as s but I would like to do single instance okay so almost like the exact same idea right almost the exact same idea but I'm going to show you the difference and what you could do is this register module uh that's what I want thanks SCH pilot so you could do this and you have the exact same problem and in fact let me go one step further because we would end up doing a container right so these three lines are functionally equivalent to these three the service provider that we get from the service collection is basically like the uh the container I container from autofac so same idea you can see that this code looks almost the same but here's the big game changer that instead of doing register module you would do something called assembly scanning and we're going to see that with scor I hate that name it sounds so bizarre to say uh screw screw tour um it's just unnatural it doesn't feel like it flows um we can change instead of doing register module this way we can go do assembly scanning with autofac see how it says register assembly modules we could do literally one sec how am I going to do this um [Music] directory I don't know if you can tell um I'm if it seems like I'm struggling to type what's happening is that Visual Studio is having such a low latency for putting the uh whether it's co-pilot or just the normal intellisense uh suggestions there's such a small delay that as I'm typing individual characters it's trying to complete too fast and what ends up happening is that it's matching on stuff where the letters aren't contiguous and as a result I have no idea what it's matching on and I can't see what I'm typing so that's why I'm struggling a lot right here so I want to type directory but see like flow Direction left to right I just want to type directory man uh I'm programming on my gaming machine which is where I stream from and do my YouTube videos I don't have this problem on my my main machine that's annoying oh my goodness okay so what we can do and this is going to be a pretty naive implementation of of assembly scanning so uh I don't recommend you do it exactly this way but it looks something like this we'll do directory get all files I'm going to pull this up here we're going to ask for all the DLS then we're going to use some link here and we will do a uh we'll do file assembly I never know assembly string no we want load file or load from there's one of these is going to break I'm going to take a guess I never remember actually we can just do this I think and is that it is it taking a numerable no it needs an array actually it's worth commenting um because folks if you're watching my stuff I almost guarantee you're watching Nick chaps on YouTube of course um unless you're just someone else who's not even into C and you're just to support but I think Nick chaps just put a video out on this not too long ago or he's covering some of the new features coming out but the um the idea with uh pams so if you're looking at the tool tip pams assembly and it's an array um this is changing in some of the upcoming uh csharp features that we have you will be able to use params with other collection types and I think even with I inumerable so we wouldn't have to do this so in case you hear about that feature and you're like who cares um literally for a situation like this it's forcing me to to make it go to an array whereas going forward you'll be able to declare params uh with not arrays and that way you don't force someone to use an array type it could be a list it could be a numerable whatever you want okay so this is naive assembly scanning and modules uh uh reflection Nam space and autoa Nam space collide with each other which is annoying pardon me what's wrong with that oh pardon me Visual Studio yeah so Steve says I would not recommend to do this with link do multiple steps get file try load get types exactly um and in fact you don't need to do the get types because that's what assembly modules does it will get the modules for you but you do want to have some first of all this not so great uh if you have unmanaged dlls you're in for a wild ride um because when you go to do this part it's going to throw exceptions so you definitely don't want to do this in link um this is a live stream so I'm trying to move through stuff but uh that's exactly right Steve so thanks for calling that out oops not what I wanted to click leave a little comment there okay so if we go run this what should happen is that this just works unless I pick the wrong thing what why did that not work the file name what am I missing here that's the pattern right oh you know what I am being silly um it's not the pattern that's because we need to tell the directory here you go I thought this part was the filter it's the filter now it wasn't before yeah thanks Steve there's a delay between my stream and the chat and stuff too so oh wow this is great so did it find it though it must have right interesting interesting why doesn't that work we can see that we have the the sorry you might not be able to see because the text is microscopic but we do get the main window view model the main window are on the container but it's complaining because it's not able to map the the resources for them now which is strange I don't know why that's the case anyway point is that um if I go back we're we're not going to be using autofac anyway just for the record that's why I don't really care um the point that I was trying to make is that you could go now let's assume just to make a point here if you had different plugins this is a terrible example by the way I just split these up into two modules now notice how I didn't go change this code I just left it the same way but if you were making more plugins you'd be able to essentially just go dynamically load them you never have to come back into the core application to change it whereas if you wanted to do this with the extension methods you would need to go add more extension methods into the core application every single time or calls to the extension methods every single time that's a a thing that I just don't like doing it kind of breaks the design that I like to use so if we double check here just again you might not be able to see it because it's tiny but we do have both loaded the main window view model and Main window on the container so again don't know why it's not loading through autofac um but we're not using autofac anyway what I want to do is try to rebuild that assembly scanning functionality without having autofac so let me go into the project file we'll get rid of autofac because we're not going to be using it and I think we should be able to try and use screw tour for that but I can't remember how screw tour works so one sec Andrew Lock is amazing if you guys don't know who Andrew Lock is he's like one of the best c.net bloggers ever which is cool um but you can see this is basically I'll zoom in a little bit a lot of bit um we get a scan like extension method right on the service collection which is is nuts super awesome yeah live coding is really hard yes it is Steve so thank you for acknowledging that it's funny i' I've mentioned this before like on live streams the by the way I do live streams on Monday nights 9:30 PM PST and these ones are just general software engineering like career advice and things like that and then I try to sprinkle in these coding ones but man coding live is a pain in the butt for sure and I think it's important to show it because when people watch the Youtube videos everything's hopefully mostly pretty polished right the reality is like that's not what software development looks like it just isn't right I've I tried to make it very clear unless you just join the stream recently WPF stuff autofac like I've been using those things for years right I haven't use WPF in ages but you could see that even when I started this up I was like man I can't remember anything in WPF and it's changed a little bit since I last used it too so it's uh it's just more real when you see it happening live and then plus I can't edit it so you can see exactly what's going on okay with screw Tor though again I hate saying this name so I apologize if it's hurting your ears like it's hurting mine we do get some scanning functionality so I think we can try something out scan from calling assembly add classes as matching interface so what's cool about that let me go back to the code here so what I had to do maybe it's not obvious because I got rid of the autofac stuff what I had to do in this code and autofac was I got to in autofac you can say how you want to go register the thing like as an interface and I think you can on here too I can do like oh if we if we had an ey window I think you can do this kind of thing where you say when someone asks for the interface give it this implementation um add Singleton is kind of like an autofac you had to do like dot um was it as Singleton or no was single instance right you would do this kind of thing in autofac after your registration but with screw door let's see what we have so I'm going to get rid of that scan so this scan method is not part of uh I service collection it is you can see using scrudder at the top scrudder is that do people like screwier better than screw Tor let me know in the chat because both hurt my ears and make me wildly uncomfortable to say but anyway it's an extension method that we get added onto service collection so that's really cool so just wanted to show you that that is the new thing and then we get a type Source selector and if we look back at Andrew Lock's blog he had it like very elegant right from calling assembly so the difference with his at least in this example here is I was trying to scan for multiple assemblies and this one is just doing from calling assembly but I'm pretty sure we'll be able to do more um give me one sec here just checking something on the stream cool okay so from assemblies there we go right so that's cool I deleted my other crappy code but let's go ahead and oops I'm going to try to make this look uh as clean as Andrew Lock stuff that he had so we could do this and then we can say selector dot it was from assemblies that's right and we had to give it the assemblies okay let me I'll take Steve's advice I will do this on separate lines of code I'm not going to do the try catches and stuff around it ah so Steve saying in the chat in case no one's reading it you're on a different platform if you work with dlls load them as a b stream and check the magic bytes so you know it's native or managed dll if it's managed you can load them from the existing bite array yeah that's great it's a good good call um and then that overload is here so you can see this here oops sorry this one this overload it says raw assembly so as Steve is saying what you could do is when you're going through those files so you do directory get Files come on co-pilot remember what I put before no okay there it is so we're getting all the files now what Steve is saying is that you could instead um and you maybe want to do this in a for Loop and stuff instead of Link but you could go get the stream to each file and you could go check the first couple bytes I don't know what the what is the magic bites it's funny I worked in digital forensic for eight years and I can't remember so this is kind of interesting for folks that are curious um and this is maybe a fun little note about digital forensic so in digital forensics a lot of the time what we need to be able to do is not just trust things like You're you don't have the luxury a lot of the time to go through a a file system and say hey like I'm just going to open up all these files and find what I want um you can and should do that but when you're building digital forensics tools you need to be able to scan through binary data a lot of the time so you get very familiar with uh different they call them like magic headers or uh Magic bites depending on what you're dealing with but if you scroll through this right there's a bunch of different extensions um I saw something that was interesting so there's like uh gifts right so you have a a handful of bites that are for different image formats uh jpegs right bunch of different ones so anyway you could go do the same thing and go check binary files so you could check your dlls to make sure that they are things that you can go look up thank you Nick Hodge this is awesome he said that's Java oh for for Java files oh Java class file yeah yeah cool sorry I didn't have that on the screen I was like what about Java is that do you think that that's um coincidence that it's a cafe babe and it's Java maybe coincidence um what's the other one it's uh oh man there's a there's a Windows thing I'm pretty sure it's windows and it's raw beef is the the magic header can't be raw what is it something beef anyway it's it's funny um but I can't remember what it's for and I was just trying to look for beef in here and it's not here so maybe it's let me search at another tab I'm not making this up I can't remember what it oh dead beef what does the word dead beef mean right anyway kind of stuff when you're dealing with hex but so you could go do that and that would be a nice optimization here um we're just going to take a shortcut because I don't have to worry about that right now yes my C library is from 92 to get the file type that is absolutely awesome so should have that what was I doing here oh we're getting assemblies that's right what's that one the beef CAC beef cake no I'm searching it in another tab as I go through this Google's not picking up anything so feel free to elaborate in the chat but magic headers are a lot of fun um okay so we have all the assemblies we can give that into screw here um we can then add classes and I think it had as implemented interfaces as self with interfaces um generally so I should comment on this most of the things when I'm when I'm coding my own stuff I slap interfaces onto a lot of stuff and that's if I'm heavily unit testing things I use interfaces for a lot because I mock a lot of things some people watching are going why the heck would you do that you can't just mock everything like yeah it's I like writing code that way in case I want want to write unit tests and I basically think about that as I write code uh more recently especially when we have things like test containers and being able to set up functional test oh I just realized my tick talk live was discontinued due to inactivity which is very bizarre because I feel like we've been active the whole time let me go restart that that's so bizarre come on man cool we'll just kick that back off maybe it's because not enough people on Tik Tok were we're watching that's uh that's hurtful okay so when I am programming I generally like to slap interfaces onto things except I found more recently especially with things like T containers I just don't have to write as many mocked um unit tests I want PE open a manage deal on a hexeditor I don't have a hex editor on this computer uh I do on my other one but this one is for gaming and I've only recently switched over for streaming and video so okay we got the assemblies uh I was commenting on this I generally would do do um as implemented interfaces so if you were to go look through a lot of the code that I've written for my own projects using autofac you would see as implemented interface on basically everything but um what's nice about oops where did it go oh as self with interfaces what's nice about this is that if you start off and you don't have inter faces on your classes CU you're like I just don't need them yet I don't want to maintain an interface in a class I'm not writing unit tests on this stuff yet I just don't care that at least if you switch over to that at some point then you have the opportunity where this stuff is all just working out of the box so I would probably roll with this for now um if you have strong opinions about doing this otherwise in the chat would be very curious to hear but this for me would work we don't have interfaces on these things right now so it's not going to matter but if we read what this is doing it should be pretty cool right we're going to get the assemblies out of the running directory uh should put the comment back in here that we don't want to just do this this is a very naive way to do it but we will use scan coming from screw Tor as an extension method we will go load those uh types so I guess add classes from these assemblies and we will register them as their type plus the interfaces and the things that we should be adding are just these now this means that we don't need this anymore we don't need it because we should be going to get the types so let's go see if this works oh yeah and it worked better than autofac right it's the same thing except it didn't work with autofac which I'm really curious about I don't know why it wouldn't find the resources properly but it works right I don't have those types manually registered that's the thing that I wanted to show you that I wanted to move away from and in fact this stream might be a little bit different than I thought I thought we were going to have to go build this I was expecting that scoter is not going to do exactly what I wanted here but it does it does do that so that's really cool actually um and one of the other things that's very nice about this I should talk about some pros and cons that I can see happening with this so if you recall and I got rid of all can I control Z this control Z for I'm I live in the United States now I should use my Z's okay um I'm not going to get this code to compile because I'm going to get rid of it again one of the things that's nice about autofac is that you can control the registrations very uh granularly so when you create one of these modules which is what I have on the screen right here when you create one of these modules the nice thing is that you have full control control over how you want to register things individually right that's a pretty powerful thing that you can leverage um with screw Tor and maybe there's more things that we have control I got rid of all of it but with screw we basically just said we're going to load everything this way and for me that's probably okay um and I'm assuming maybe there's separate things we can do in scrudder to have a little bit more control so maybe um but you're kind of flipping things around so I'm going to go get rid of all this again looks I'm typing super fast um but right this is like we're saying hey everything is going to look this way now one of the drawbacks of autofac that I don't really like and one of the really cool things about screw door is that we in autofac you have to go make a module I guess you don't you don't have to but that's the that's the unit of organization is the modules inside of autofac right so it means that wherever you're creating code that you want to have get pulled in say as a plugin right you're scanning a folder for DLS any code that you want to have incorporated as a plugin you need to have a reference to autofac which seems kind of weird but how else would you do it it needs to come from a module so your plugin would need to depend on autofac would need to go create its own modules and then you could go say oh like my scanning code will go look for those modules but the point that I'm getting at here is one of the drawbacks of autofac is that your plugins need to depend on autofac what I was thinking we were going to walk through today was going to write some code that's kind of like screw or here and basically trying to see we could do away with having a hard dependency on autofac could we load things a different way if we were just going to use the I service collection so that goes to show right here that this code using screw door is actually very helpful in that we don't have to have plug-in projects go and have dedicated modules right I actually deleted the extension method which is equivalent in the I service collection world to having a module very similar you know organizational grouping I even deleted that we're just going and asking for the classes and we don't have to have something to go have a dedicated setup so that's even nicer in my opinion so maybe I am going to convert it's hard to say that out loud but um it's really difficult when you've been using stuff for years like I've been probably been using autofac for 10 10 or more years and it's almost like muscle memory like I will literally go make a new project add autofac add a couple of things by default I'm going to switch to my full face so I can talk with my hands for a little bit um I Disappeared coming back there I am um so like at a muscle memory right go create a new project go add autofac go add whatever else I need depending on what I'm building but autofac is one of the first things things I get rid of most of whatever is there in the template I go make a container Builder I go register modules from assemblies and then I just start by adding new projects like right away out of muscle memory I basically go build everything as plugins and my core application is just a very lightweight uh autofac container Builder Sometimes some logging and stuff wrapped around that but um this is a it's interesting I I feel like I feel like the how far ey service collections come and leveraging something like screw door might be a a big help so um like I said I don't know how I'm going to convince myself to switch over even one of the the things that I'm working on right now so I announced this I guess today's only Saturday so I put out a newsletter today and announced this but I I have a like basically a SAS that I'm building on the side it's called brand ghost and uh for folks that are watching this and see the content that I put out um my content is put out online I almost if I'm commenting on stuff or replying that's all done by me but I almost don't post anything directly to social media platforms everything that I've done is built through a system and it's uh it's scheduled all of it so I wanted to codify this and brand ghost is the tool that I'm building to basically codify this and where I'm going with this is I have this thing that I'm building and I I've already I'm like heavily entrenched in autofac and now I'm like oh man this is a typical software engineering thing where I'm like I should go replace all of it with ice service collection and scoter right like I should go do that but like the reality is no Nick you shouldn't like maybe you want to think about moving in that direction it's it's still relatively early but if you keep looking at shiny things and going oh like I better go rewrite this you'll never do anything it's fine when it's your own personal projects and I actually do recommend doing that when you're learning so if you just have little hobby projects that you're doing for fun to build stuff I do recommend it try new things out try these different patterns so like we were doing going between autofac and screw door if used to one try the other go convert stuff it doesn't matter it's a playground you use it for learning in this particular case for me if I'm trying to have a SAS and I want to have customers at some point that will be paying for the service you don't want to do that so don't um but if architecturally you get to a point where you're like it's just not working you will want to think about pivoting but I'm not there yet um I wanted to see if there's anything else from screw door that I want to play around with and I'm looking at the code I'm not sharing it right now but honestly I'm pretty shocked that it did the things I wanted um I just thought we were going to have to go build more things so maybe maybe what we can do before um I wrap up or kind of move over to just totally open-ended questions is let's go back to the code let's see if we can go make a plugin to kind of prove what's happening here so let me get my I'm going to disappear here again every time I stream I say hey I should figure this out so that I don't disappear but I haven't um I want to go basically make a new project where we're going to load the main window from it if that sounds okay and this is going to be tricky I'm trying to think about a good way to do this that demonstrates the capabilities here um we need a common type so it's a bit of a pain in the butt um what else do we have on here one sec so I'll I'll try to explain this a little bit more clearly what I want to do is the main window that we have just to demonstrate plug-in loading I want to go pull the main window code including the view model I want to go pull that into a new project so let me go literally add that so I'm plug in one oh I just realized that the the Tik Tok stream thinks that I don't have audio which is funny so hopefully that's better for anyone anyone that's been watching on Tik Tok has been like joining and being like what the heck is this and leaving I'm sure because there's been no audio amazing okay um and then Steve says fun I only have fun on my motorcycle coding is only a job well I mean to each their own I'm allowed to have fun coding right right let me go move this stuff out here so I've just moved it over and double cheing some stuff it's not happy oh man I didn't think about this I don't know what um things it's going to need here shouldn't have done that I guess I should have made a new project that's not just a class Library it probably needs to be like a control Library here we go sure I'll call it that names don't really matter here that is a whole lot going on so that's a lot of stuff oh I think they're just telling you how to go use it which I don't care about we're g to get rid of it um let me go delete this project too so hopefully obviously that file is going to work it's just a dto there we go excellent okay I was getting nervous there um but we this is the problem now this is what I wanted to get to like I don't have a reference to main window because it's in the uh you know the control library is going to be our plugin so we can't ask to go resolve this directly so what we could do and I'm going to probably take a shortcut here because it's just a waste of time right now what you could do is have a another project that kind of defines the apis that you want to have for your plugins and that way you would know which thing to go resolve like your your plugin could implement it and your core app would know it needs to be like a common uh thing that you can refer to but instead what I'm going to do is see if service provider can get a type of window I'm curious if this will work because there should only be Oh weird no here we go there should only be one window registered should be but I don't know um and the other thing is with screw door we did as self with interfaces but I don't know if it's going to do the um like the base class which is interesting we'll find out whatever oh I forgot not this I don't know what that's about I should have known this is going to be a nightmare with WPF next time Nick don't do that let me do a little shortcut here okay I'm going to go remake this main window so dumb that's okay okay main window I got a scroll back up in the chat to get the little data context really why doesn't that work now Nick hod if you're still on you got to save us here unless it's just complaining about this maybe it is that's okay anyway this part's not working but that's okay we really don't need that we just need to put the in back on which was that oh it did work what the heck it's complaining that it doesn't work but it definitely does work so that's cool and then we have to go pass that in here no that's what we want okay so this is basically the same that we had please let that build yeah you're you're right Nick it probably just does need a Nick Hodge not I'm not talking to myself I promise okay so that built the other thing that I forgot though is that we have to move the dlls into the bin directory so if we go run this it should not work it should throw an exception but it didn't oh get required is oh Nick come on okay so throws an exception I do expect that to happen because there is no window registered now I'm going to go open this and go move the DLS over you don't need to watch me do it I'm in the bin folder so what I'm doing is I'm copying the output of one and I'm going to go put it in the bin directory of the other now I still don't know if it's going to uh if this registration up here is going to allow it to register the main window as the Base Class of just window so we'll find out it does not work that's a pain um what do we want to do about that is there a good way to do that trying to see if there's another way to to register my biggest projects in production are in Wind forms I've tried out WPF but does not work out for me yeah I like even now like I probably in my entire programming career of 21 years I probably have over half that's still in Wind forms I don't like saying that out loud but um I think that's the reality okay so I think I might need a marker which sucks I don't like doing that uh how do I want to do this can we get can we get a service I don't think that's going to work so if folks are getting kind of lost about why I'm getting stuck here when we do add classes as self with interfaces main window if we go look at Main window in the code here main window itself so when we say as self it will register as main window and then it says with interfaces and there are no interfaces that you can see here which is why I went into window itself to see if there were any interfaces we could go ask for um a cheater move is I might be able to go check for this because I think it will be the only thing on the dependency container that has that interface but we can't do this and then we can get super nasty here by the way everything I'm doing here don't do this ever because it's terrible um I said that we would probably want to have an interface that our plugin could refer to and I mean it so don't do that I'm just trying to see if we can go find the type magically and we did excellent and there we go hello world so there we go we cheated it works um the the point that I'm trying to get across here is that we are able to show this form right and yes I had to go change this part up because like I said I need needed to have something common I needed something common between the plugin and the core application and I rushed to extract it and we didn't have a common thing technically window itself is common right it's a common type but if we're using screw door in this way um unless I were to go dig deeper and see if we could do a more granular registration using screw door in this way we don't have the luxury of having a very specific registration creation so the problem was again using as self main window will be literally as main window we can't see that we can't refer to that type at compile time in the core application because we've pulled that out and if we could use window because that is common between the plugin and the core application that would have been nice except we can't because of this up here right main window is not the same as window unfortunately so I was just trying to look for a common interface that we could see I add child is one of those interfaces so that's great but the point that I'm trying to get across is once you have the assembly scanning in place you can continue to go add things you can continue to go extend your application and you never have to come back into your app to go change it and once your entry point is set up to work and run you never have to come back here to go do that either so that's one of the things that I really like doing when I'm setting up my code is trying to and again if you've seen my other stuff you probably know this about me already so it might be a broken record but for people that haven't seen my stuff before I do like making my entry points to my programs being extremely lightweight doing assembly scanning getting my dependency container set up and ideally I have one spot that starts the code off so that's the ultimate goal um I'm probably going to wrap up the stream in just a sec here so I wanted to kind of make sure that if folks are still on the stream if you've been waiting to ask questions about whether it's C you know I'm showing WPF stuff right now uh asp.net core if you're like I don't even know about C I want to ask about other programming or software engineering things I'm happy to take questions now I mean I do these streams to try and help other people so I be more than happy to answer questions if you got them that would make me feel good if I can help you so please don't hold back and I will probably take a moment while I'm waiting for any questions to talk about courses because I also have those um so I have a bunch of courses on dome train and I am I should probably start but I have two more that I'm going to be putting together and let's go back to courses by me so these are three courses I have so if you've never programmed ever before you can use the getting started c one um that one literally starts you off from never having written code in your life and you're just curious and you're happy to get started in C the Deep dive C just extends on that it's uh the first one is 5 hours this one's about 6 and a half hours the Deep dive one um between the two of them so about 11 and a half hours of of educational content but you you're I'm I never promised this you're not going to take these two courses and be able to program like everything possible in the world it's just a starting point right by the end of them you should be able to program and C with some amount of confidence but I don't like promising people expertise because I think that that's misleading it will take you much longer than 11 and 1/2 hours to be able to master something so I don't want to mislead you the refactoring one is uh I am really big on refactoring so I was happy to do this course for Nick chapsas walks through a bunch of different refactoring techniques um there are there's a big exercise kind of at the end here uh and in my opinion refactoring is one of the most important skills you can have was a software engineer so that's another course I have I don't think I'm allowed to publicly say what the other two that I will be releasing are um but I should be I should start on the first one and the second one will come probably a little later in the year maybe towards the end of the year but I'm excited to do both of those because I am a big fan of both of those so if that doesn't help you figure out what I'm going to be doing then I have no other hints but those courses will be coming so let me switch back to my full camera I don't see any questions in the chat so I may sign off here but I'm gone come on it's funny I have this where is it I bought one of these one of these stream decks and at the time when I got it I was only making YouTube videos I wasn't streaming and I said hey like even for your YouTube videos this might be handy it's it's literally unplugged in my hand and I'm streaming now and it's still unplugged in my hand so I probably need to set this thing up and then configure it with OBS so I can press a button and smoothly transition between my scenes but I don't have that done yet so um I just wanted to say thanks everyone for watching if you are watching the recorded version of this thanks for checking it out I do try to stream aign for my live stream on Monday I try to make sure I can get a little bit of coding in on a stream during the week so um hopefully this was helpful you get to see some real live coding seeing me stumble through stuff and hopefully that's helpful for you to see that even after programming for 21 years I have to use stack Overflow for really basic stuff that I should know so all right folks thanks again if you are interested in my next plan stream it will be at the well I guess at the end of this week it's a Monday what's the date the 17th 9:30 PM PST it will be about using AI in software engineering and what you can do and what you absolutely should not be doing with AI and software engineering so do check that out it will be if you're watching this right now it'll be on the same platform that you're watching it on so if you're happy to watch it there that's good uh YouTube is my primary platform so you can go ahead and check it out there as well and thanks again I do appreciate the time we'll see you next time take care

Frequently Asked Questions

What is the main focus of the live coding session?

In this live coding session, I'm focusing on WPF, dependency injection, and building a plugin system using IServiceCollection. I'm also trying to reacquaint myself with WPF after not using it for several years.

Why are you not using Autofac for dependency injection in this project?

I'm trying to avoid using Autofac in this project to explore and get comfortable with IServiceCollection, which is the built-in dependency injection framework in .NET. I want to see how it compares and if it meets my needs for building a plugin system.

What is your approach to testing in WPF applications?

I prefer to keep as much logic out of XAML as possible to enhance testability. I try to use the MVVM pattern, where the business logic is in the ViewModel rather than directly in the UI, allowing for easier unit testing without relying on the visual components.

These FAQs were generated by AI from the video transcript.
An error has occurred. This application may no longer respond until reloaded. Reload