Making Mayhem with Volume Control


Why, hello there! We are going to pick up where we left off at the end of our Coding4Fun video. In the video we built a reaction that increments the volume level on the computer. We are going to expand from there to make a reaction that enables you to set the volume level to a specified volume. file contains the class library project all set up with the NuGet package references and the reaction that increments the volume.

The first step we are going to take is to add the additional references we need to be configurable. The first reference is MayhemWpf from the same NuGet feed MayhemCore is from. ( Add a reference to the following assemblies:

  • PresentationCore
  • PresentationFramework
  • System.Runtime.Serialization
  • System.Xaml
  • WindowsBase.

Next, we switch the code from incrementing the volume to setting the volume to 50%.

To do this, replace the line:



device.AudioEndpointVolume.MasterVolumeLevelScalar = 50 / 100.0f;

The reaction now works successfully to set the volume to half way. The next step is to make that setting configurable, and persist between application runs. Let’s make that 50 a variable. Add a private integer to the class (I’m calling it level) and change the above line to be:

device.AudioEndpointVolume.MasterVolumeLevelScalar = level / 100.0f;

Since that variable will be user configurable, we want to be able to show a string on the main window that says what the reaction is doing. To do this, we have to tell Mayhem that our reaction is configurable by implement the IWpfConfigurable interface from MayhemWpf.

In order to set that configuration string we have to implement the method GetConfigString. The implementation of this method should return some string that provides a look into what the configuration settings are for the reaction.

I will make the GetConfigString method be the following:

public string GetConfigString()
   return string.Format("Set the volume to {0}%",level);


Now, in order to make the module save the configured state when the application is shut down and restarted, we need to add a little bit of data contract code. We are going to add the [DataContract] attribute to our class. This attribute comes from the System.Runtime.Serialization framework.

Our class header now looks like:

[MayhemModule("Set Volume", "Sets the master volume level")]
public class SetVolume : ReactionBase, IWpfConfigurable

Note that I also changed the MayhemModule attribute’s name and description to reflect the new functionality.

We also need to mark the configurable variables to be saved as well. To do that, add the [DataMember] attribute to our level variable:

private int level;

In order to set a default value for this variable, we shouldn’t initialize it using a constructor. Constructors should never be used in modules. Instead, we have a method that should be overridden that you get from ReactionBase. OnLoadDefaults is to load the settings you want to have by default.

protected override void OnLoadDefaults()
   level = 50;

Now when you use the SetVolume reaction in Mayhem, it will at 50%, but if that value is changed and the application is restarted, it will be set to the value it was at before it was closed!

The next step is to make the configuration window that actually enables that variable to be modified.

Add a new WPF UserControl item to the project named SetVolumeConfig.xaml.

Replace the contents of the XAML file with:

<src:WpfConfiguration x:Class="Volume.SetVolumeConfig"
         <ColumnDefinition Width="100" />
         <ColumnDefinition Width="200" />
         <RowDefinition />
      <TextBlock Style="{StaticResource ConfigLabel}" Grid.Column="0" Grid.Row="0">Volume:</TextBlock>
      <Slider Grid.Column="1" Grid.Row="0" Height="23" HorizontalAlignment="Left"  Name="VolumeSlider" VerticalAlignment="Top" Width="200" Maximum="100" />

This configuration window simply has a volume slider allowing values between 0 and 100. WpfConfiguration handles the display of how the module asks for information. As you hopefully notice, it doesn’t contain the save button, or the title of the window. All that is handled for you so that we can maintain consistency between configuration windows. We also provide default styles that further maintain consistency and user expectation.

We now need to create the backing code that makes the configuration window come together. Change SetVolumeConfig.xaml.cs to extend the base class WpfConfiguration instead of the default UserControl base class.

In the constructor, we should ask for all the information we need to populate the config window with the current settings. In this situation, that only means the current volume level setting. Add an int parameter to the constructor called level. Also add a public property on the class with a private setter called Level. In the constructor, set this property with the parameter passed in to the constructor.

Your class should now look like this:

using MayhemWpf.UserControls;
namespace Volume
   public partial class SetVolumeConfig : WpfConfiguration
      public int Level
         private set;
      public SetVolumeConfig(int level)
         this.Level = level;

WpfConfiguration gives us some handy hooks that we can use. We need to set the value property on our slider. This could be done with data bindings, but for simplicity we will just be doing this with code. Also, there is a Boolean flag in the WpfConfiguration class that enables the Save button on the dialog. When handling user input, the save button should only be enabled if the input is valid. Since the slider always has a value in our range, the Save button can always be enabled. We will set this flag in the OnLoad method.

Override the OnLoad method as follows:

public override void OnLoad()
   VolumeSlider.Value = this.Level;
   CanSave = true;

We then also override the OnSave method to set the property to the value the SetVolume class will expect.

public override void OnSave()
   this.Level = (int)VolumeSlider.Value;

Lastly, we need to set the title that shows up on the configuration window. To do this, override the Title property and have it return “Set Volume”:

public override string Title
   get { return "Set Volume"; }

Now we need to go back to the SetVolume class and implement those configuration related methods.

The ConfigurationControl property needs to return an instance of the SetVolumeConfig class. Remember that its constructor expects the current volume setting:

public WpfConfiguration ConfigurationControl
      return new SetVolumeConfig(level);

Lastly, OnSaved takes the instance of WpfConfiguration control we just returned in the above property. We need to cast this back to SetVolumeConfig to be able to get access to the Level property:

public void OnSaved(WpfConfiguration configurationControl)
   var config = (SetVolumeConfig)configurationControl;
   this.level = config.Level;

That’s all it takes! This code provides us with a complete reaction that enables us to set the volume level on the computer. As you can see, we provide a very straightforward API enabling you, the developer, to write user configurable modules for Mayhem.  You can click the download link at the top of the screen to get the final code in

We have more documentation available on the available methods and APIs on our CodePlex documentation page.



The Discussion

  • User profile image
    Jose A  Diaz

    nice! but,how to learn the code for another apps?

  • User profile image

    an excellent job

  • User profile image

    I downloaded the phone trigger add-on and it crashes everytime in mayhem. In eventviewer I get. Does anyone know what file it's looking for?
    Application: Mayhem.exe (Rent Arad)
    Framework Version: v4.0.30319
    Description: The process was terminated due to an unhandled exception. (Inchirieri Iasi)
    Exception Info: System.IO.FileNotFoundException
    Stack:  at PhoneModules.PhoneConnector.StartService(Boolean)

  • User profile image

    This is awesome and is something I have always wanted for my TV... a "medium-level mute" button... something to take the BITE out of LOUD, ANNOYING commercials.

Comments closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums, or Contact Us and let us know.