Using app.xaml and ResourceDictionaries for Cleaner WPF Customisation

When I first started making WPF forms, I was using PowerShell. This was a good starting point I think as I felt really comfortable with PowerShell which let me experiment more freely and break things in a way that I still felt comfortable.

However, this also meant putting all of my XAML into a single string. This might not sound too bad, but when you have five buttons all with slightly different templates and behaviours, the code quickly becomes messy and hard to read. Note that XAML is easy to read in the first place 😫 I was no stranger to having code that looked like this:

<Border Grid.Column="0" Grid.Row="1" Background="#FFE87E31" HorizontalAlignment="Right" Width="25" Height="25" Margin="0,0,2,0" CornerRadius="20"  BorderBrush="White" BorderThickness="1">
                <Label Name="Search_Button" Cursor="Hand" Foreground="White" Content="🔍" FontSize="12" Width="25" Height="27" Margin="-1.667,-1.667,-0.334,-0.334" />
            <Border HorizontalAlignment="Stretch" Grid.Column="0" Grid.Row="2" VerticalAlignment="Stretch" Background="#FF34495F" >
                <ScrollViewer VerticalScrollBarVisibility="Auto">
        <!-- ALL OPTION OBJECTS HERE -->
                        <Border Height="35">
                                    <Setter Property="Border.Background" Value="#FF34495F"/>
                                        <Trigger Property="Border.IsMouseOver" Value="True">
                                            <Setter Property="Border.Background" Value="#FF1F2A36" />
                            <Label Name="General_Information_Button" Cursor="Hand" VerticalContentAlignment="Center" Foreground="White" Content="General Information" FontFamily="Century Gothic" FontSize="14" />

Horrible I know…

But when I moved to use C# with WPF, I found that I could have separate resources that could be used by multiple controls at the same time. You do this by adding a resource dictionary to the app.xaml file inside the WPF project.

Here is a quick example of what I mean. I created a Styles folder in the root of my WPF project and added a new ResourceDictionary(WPF). I called this resource dictionary “TextStyles” and it looks like this:

<ResourceDictionary xmlns=""
    <Style TargetType="{x:Type TextBlock}">
        <Setter Property="FontFamily" Value="Arial"/>
        <Setter Property="FontSize" Value="28"/>
        <Setter Property="FontWeight" Value="Bold"/>
        <Setter Property="Foreground" Value="White"/>

Perfect, I then added this to my app.xaml file which now looks like this:

<Application x:Class="WPFUI.App"
                <ResourceDictionary Source="/Styles/TextStyles.xaml"/>

From now on, all the text blocks in the WPF application would use the Arial font, use font size 28, be bold and also be white.

Important Notes:

  1. It’s important to add your resource dictionaries to the app.xaml file in the correct order. You want to work from top to bottom. Meaning you don’t want a resource dictionary using something from another resource dictionary below it. For example, if you are using custom colours and want your text blocks to be that colour, you would put your colour resource first and then your text block resource.
  2. If you don’t want a resource to be used everywhere in your application if you style inside the resource dictionary a name. Then you can reference the style inside your WPF XAML code.


Multiple Sounds in WPF Application

So I’m making a small WPF game, which you can find here by the way 😛, and I come across a confusing and infuriating issue. WPF has two built-in audio players: SoundPlayer and MediaPlayer.

SoundPlayer: Can play audio files that are embedded resources in the application, however, this can only play one sound at once.

MediaPlayer: Cannot play audio files that are embedded resources in the application, however, this can play multiple sounds at once.

I think you can see the issue I was having. I wanted to play some background music in my game as well as some sound effects for certain actions in the game. This meant the easiest way to get this functionality was to use both of these options and save the background music to the local disk as a temporary file. Not as clean as I wanted, but it will do I guess 🤷‍♂️

First, I set up my SoundPlayer as this was the simplest one of the two. I created a new SoundPlayer object using the embedded resource:

private static readonly SoundPlayer _soundOne = new SoundPlayer(WPF.Properties.Resources.soundOne);

Then when I wanted this sound to play, I would simply use:


Simple enough for the SoundPlayer… Now we move onto the MediaPlayer.

First, I make sure that my audio file is set as an Embedded Resource under the Build Actions in the file’s properties in Visual Studio:

You can see from this, that I have a WAV file called “backgroundmusic.wav” which I need to save to disk, play continuously and then delete once the form is closed.

Now that we have done this, we can create the method for saving the embedded WAV file to the %temp% location on disk. This is how I did that:

public static void SaveMusicToDisk(){
    //This sets up a new temporary file in the %temp% location called "backgroundmusic.wav"
    using (FileStream fileStream = File.Create(Path.GetTempPath() + "backgroundmusic.wav")){
        //This them looks into the assembly and finds the embedded resource
        //inside the WPF project, under the assets folder
        //under the sounds folder called backgroundmusic.wav
        //PLEASE NOTE: this will be different to you

Great we have now saved the embedded resource to disk, how can we play this now? 🤷‍♂️

We play this by creating a new MediaPlayer object and using the temp file location to play the audio:

//Create a new MediaPlayer object
private static readonly MediaPlayer _backgroundMusic = new MediaPlayer();

public static void StartBackgroundMusic(){
    //Open the temp WAV file saved in the temp location and called "backgroundmusic.wav"
    _backgroundMusic.Open(new Uri(Path.Combine(Path.GetTempPath(), "backgroundmusic.wav")));
    //Add an event handler for when the media has ended, this way
    //the music can be played on a loop
    _backgroundMusic.MediaEnded += new EventHandler(BackgroundMusic_Ended);
    //Start the music playing

My BackgroundMusic_Ended method looks like this and just makes sure that the music is always restarted once it has finished:

private static void BackgroundMusic_Ended(object sender, EventArgs e){
    //Set the music back to the beginning
    _backgroundMusic.Position = TimeSpan.Zro;
    //Play the music

Now that the music is playing continuously on a loop, how do we stop the music, dispose of the object and delete the temp WAV file from disk?

To stop and dispose of the MediaPlayer object is pretty easy, you can use:

public static void StopBackgroundMusic(){
    //Stops the music 
    //Disposes of the MediaPlayer object

Now we go about removing the WAV file from the disk as we don’t want this to remain on the user’s computer once they have exited the application:

public static void DeleteMusicFromDisk(){
    File.Delete(Path.Combine(Path.GetTempPath(), "backgroundmusic.wav"));

DONE! ✔️

With all the above code and a little tinkering to fit your specific setup, you should be able to use multiple sounds at once without an issue. Enjoy!

Saving Embedded WPF Resources as Files on Disk

In this post, I am going to show you how you can save an embedded resource as a file on disk. This is useful in certain scenarios. For example, I used this to save some background music onto the computer as the native MediaPlayer couldn’t use the application paths.

First things first, you want to make sure that you have set the Build Action to Embedded Resource in the properties for each of the items:

Once you have done that, we can go about creating a method to get the resource and save it to file. For me, that is as simple as:

public static void SaveMusicToDisk(){
    //This creates a temp file in the %temp% directory called backgroundMusic.wav
    using (FileStream fileStream = File.Create(Path.GetTempPath() + "backgroundMusic.wav")){
        //This looks into the assembly and gets the resource by name
        //For this to work, you need to use the full application path to the resource
        //You get this by using your project name following by the folder tree to your item

So that saves the file, what if I want to delete the file once the user wants to close the application?

For that I would use:

public static void DeleteMusicFromDisk(){
    //This looks into the %temp% folder and deletes the file called "backgroundMusic.wav"
    File.Delete(Path.Combine(Path.GetTempPath(), "backgroundMusic.wav"));

Peeeeerfect! 🎉 Does everything I need 😊

So, what if I wanted to save all the resources?

For that I could put all the resources into a string array and loop through them like this:

public static void SaveAllResources(){
    //Gets all the resources associated with the assembly and puts them into an array
    string[] resources = Assembly.GetExecutingAssembly().GetManifestResourceNames();

    foreach (string resource in resources)
        //Create a new file in the %temp% for each resource
        using (FileStream fileStream = File.Create(Path.GetTempPath() + resource))
            //Get the resource and save it to the current file

I hope you learn something or found this helpful. Enjoy!