XAML Is EVIL! - Fixing Anti-Patterns To Achieve Dependency Injection
I think WPF is awesome but I have a love-hate relationship with XAML.
It's unfortunately mostly hate.
While I love that I can easily get a visual layout for my user interfaces, I hate that it feels like I am fighting to get other "best practices" in place. Dependency injection is one of those.
It's a pain in the butt.
In this video, I'll walk through fixing a service locator pattern from a previous example. We'll see how we can get value converters to work with dependency injection if we forget about XAML altogether.
View Transcript
we all know that the service locator pattern is bad and you should feel bad if you use it however in a recent video I actually showed that you could go use this as a solution to some WPF challenges hi my name is Nick centino and I'm a principal software engineering manager at Microsoft I've built a ton of WPF applications and there's a few things that we have to work against inside of the WPF framework if we're trying to do things like dependency injection now in a previous video which I'll link up here if you haven't seen it I did show a way that you could work around some of these things using a service locator pattern but I did offer the disclaimer that I really don't like to do that so in this video I'm going to show you an alternative where we can move
away from a service locator pattern and instead do things a little bit more manually so it's a different tradeoff but I actually prefer this way unfortunately it still does work against some of the WPF recommended ways that we should go approach things if that sounds interesting remember to subscribe to the channel and check out that pined comment for my courses on dome Trin with that said let's jump over to visual studio and get rid of this service locator pattern on my screen from the previous video which I linked before if you haven't seen it please go check it otherwise if you understand service locator pattern and why we don't want to use it let's just continue on we do have a converter here and it's using a service locator pattern because converters inside of WPF when you go to create them the traditional way which
is from a resource dictionary you aren't able to pass in constru structor parameters so if we go to put anything here like just a Boolean for example like you can't do this because it needs to have a Constructor that has no parameters just to show you quickly if we go over to the zaml this converter the Nyx cool converter class needs to have no Constructor parameters so it can have a Constructor just no parameters what we introduced in the previous video was that we could use a service locator pattern so what I end up doing is having a static property that we can set the service provider for this particular type and that way it can go resolve it when you construct it now like I said I don't like doing this service locator pattern is an anti- pattern it is quite the opposite of
dependency injection you are literally creating something and then it is asking for dependencies like it's pulling them in versus the dependency injection framework passing them in for us but that's to work around the fact that we can't have Constructor parameters what if we said no way we're fighting against the WPF system we want Constructor parameters well that's what we're going to do in this case so we're going to get rid of the service locator pattern part so we're going to start deleting these things but that means that we need to be able to pass in this string formatting helper again I should call this out in this demonstration for this converter the string formatting Helper and this converter are both extremely simple so if you're going Nick this code is so dumb and silly why don't you just refactor it into to something and avoid
this whole problem you are totally right for this particular situation I just want to give you example so that you can compare them to your own code base very easily in this case any converter that you want to make that needs any dependency passed in I don't care what it is these are the patterns that we're trying to play with here so I just wanted to keep it very simple we're going to pass in our string formatting helper that's the one dependency that we have for our converter here you can see it's passed in and assigned but this will not work when we go to run it and it's not going to work because it has a Constructor parameter to go clean up more things on our main window what we were doing in the previous video this is set up to use dependency injection
this window but that's where we're going to set that service provider so the converter itself basically was avoiding dependency injection because we were creating it in zaml and that's going to bring us to where this kind of breaks down and moves against some WPF practices because we're not going to do the binding that we have in zaml anymore if I jump back to the zaml file we're going to get rid of this converter right out of the zaml but that means that this binding that we have down here on the content this is no longer going to be applicable for us and that kind of sucks because one of the really cool things that we get in WPF is having an editor window with a preview all these fun tools that we can go use we have this I don't know if you like this
syntax I personally don't but if you're familiar with the binding syntax you can go use it especially if you're familiar Amil with it but it's not going to work for us because we can't do the binding with the converter in the zaml if we want that Constructor parameter unless you know of another way in which case leave a comment I'm happy to go check that out if we jump back now we have a window and it has our control on it but there is no binding and we don't need that there anymore either what we need to be able to do is set up The Binding manually and pass in the converter as a dependency that would mean that here we can say Nick's cool converter needs to get passed in so now we have that this will get wired up through dependency injection which
I will explain in a moment because we're using a nougat package called screw Tor to do that for us but I'm going to go wire up The Binding before we continue on this is just a quick reminder that I do have courses available on dome train if you're just getting started in your programming journey and you want to learn C you can head over to dome train I have a getting started in C course it's approximately 5 hours of content taking you from absolutely no experience to being able to program in C and after that I have my deep dive course which will take you to the next level with another six hours of content so that you can start building basic applications head over to dome train and check it out let's head back to the video so to explain what's going on with
this binding this is what we had on the screen before when we had it in zaml but I'm going to make a new binding the parameter that gets passed in here is the path of the binding so we were binding to the cool level I'm terrible with naming as you might have seen but I'm binding to the cool level on our view model okay so that's what this part is right here it's just the path to the binding the converter that we're going to use is assigned on this property here for this object initializer and that's again it's passed in right through here so we go do that and then what we need to do is on the cool label itself which if you didn't notice and I probably should have called it out I gave a name to the label that we want to
go configure this binding for that allows us to reference it in the code behind which is right here on line 25 we're going to set the binding and now bindings work on dependency properties and then a binding object in this case so content property is the dependency property of the labels content property it's a little bit confusing to say out loud we don't just do this cool label. content because this isn't a dependency property the dependency property is this and to prove it if I press F12 you can see it's literally an instance of a dependency property okay so we need to pass that in and then we give it the binding what we've done so far is we've continued to pass things in through Constructors right so this is how dependency injection generally Works through Constructor parameter passing generally so main window we are
passing in the view model that was already set up now we're going to be able to inject this cool converter and we got rid of the zaml that was preventing us from doing this dependency injection now we can go create The Binding manually this is the part that kind of sucks right you're not using zaml especially if you're familiar with it but we can go do it in code it's really not that complicated and this allows us to get that dependency injection but I need to explain how these things are wired up because if you're using a different system your dependency injection doesn't stop here you need to do a couple of other things to register things to explain you'll see that I have NYX cool converter and I have the string formatting helper these are two classes that I've created and because I'm using
a nou get package called screw door which I'll show you in just a moment it's able to go look at the assemblies that I have in my bin directory and it will go register things automatically onto the dependency container that means is I don't have to write code that registers this explicitly anywhere or this explicitly anywhere or even the main window because I use screw door with I service collection which is the built-in. net dependency injection framework because I use these things together I don't need to go have explicit registrations if you prefer to have explicit registrations you will need to go add that but that's why I'm skipping over that and you're not seeing the code for it because it is done automatically I have The Binding in place we have the stuff passed in and to show you app xaml.cs this is where
I'm doing all of that magic dependency registration so screw door is a n get package it allows us to go scan the assemblies and I'm just doing a very naive scan through the folder that I'm running from to look for dlls you should do better checks than this I'm just showing it for being quick then I'm registering all of the class classes so all the types that are in that assembly we're going to add those classes in we're going to register those classes as self so they're immediate type plus the interfaces they Implement and they'll all be Singletons again this is a very big broad registration if this does not work for you please use a different pattern that's totally cool but at this point we should have everything registered and set up for dependency injection so if I go run this now we get
functioning code right so you saw me remove the binding from the zaml but we still are able to bind to the view model it's still using the converter that we had to kind of prove it to you if I stop this if we take out the converter is it going to work right it's different text it might not be obvious but the other number was rounded so if I stop it again have a quick look 42 1337 some easy numbers to remember right so we'll go run this again and you can see that it's 42134 because our value converter that we are using dependency injection to get is doing that formatting for us we have a quick Peak right that's coming off of this dependency which is now through dependency injection passed into here all of these things together allow us to get dependency injection
on value converters in WPF this does go like I said against a little bit of the WPF patterns that we're used to seeing where we're defining things in zaml but to call it out from all of my time working with zaml and WPF I have found that like I said in the intro to this video I'm fighting against the framework a lot to get dependency injection to work in the way that I like otherwise I find that some parts of the applications I build work very nicely with the pendency injection and then anything I'm doing with the user interface just falls apart this is one strategy that I personally like to use I end up avoiding some of the zaml but I get better testability and better control and that's my preferred way to go get this to work thanks for watching and I'll see
you next time
Frequently Asked Questions
What is the service locator pattern and why is it considered bad?
The service locator pattern is an anti-pattern because it creates a situation where a class is responsible for locating its dependencies rather than having those dependencies injected into it. This leads to tightly coupled code and makes testing more difficult. I personally prefer dependency injection as it promotes better separation of concerns.
How can I achieve dependency injection for value converters in WPF?
In WPF, achieving dependency injection for value converters can be tricky since converters typically require a parameterless constructor. In my video, I demonstrate how to manually set up bindings and pass dependencies through constructors, which allows us to use dependency injection effectively.
What is the role of the NuGet package 'screw Tor' in this context?
The 'screw Tor' NuGet package helps automate the registration of dependencies in the dependency injection container. It scans the assemblies in the bin directory and registers types automatically, which simplifies the setup process for dependency injection in my WPF applications.
These FAQs were generated by AI from the video transcript.