Plex “Not Enough Disk Space To Convert This Item”

If you have ever installed Plex on a default installation of Ubuntu, you might have noticed that Ubuntu doesn’t take up the entire disk space for the root (‘/’) partition. This is the reason Plex has the issue described in the title.

This is VERY annoying.

I was really struggling with this issue for a good couple of weeks. When I searched for this issue, none of the results were helpful.

What I had to do: Used a live CD of gparted to increase the space of the partition and then use lvm for the partition to extend into all the new free space.

So, steps below:

Shutdown and boot into GParted live CD/ISO

Startup the GUI and extend the partition you want to expand

Close the GUI and open the GParted Terminal

Enter the LVM manager using: sudo lvm

Extend the default ubuntu vg/ubuntu-lv partition to use all available space: lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv

Now you can exit the LVM manager: exit

Finally, you can resize the system to use the newly sized partition: sudo resize2fs /dev/ubuntu-vg/ubuntu-lv

You can now use df -h and check that the system is using the entire space of the drive and the available partition.

You will now find that the root (‘/’) directory is no longer 99%/100% full and your media can play.

Enjoy!

One Month with Chia

So, cryptocurrency mining is NOT something I often dabble in. Maybe its the fact that using some second hand GPU to get rich off BitCoin died off a decade ago. Or maybe, it’s the fact that mining cryptocurrency often uses enough electricity to power a country… Especially with energy prices being soooo high and rising massively in my country.

So here comes Chia.

There were definitely hard drive mining schemes before Chia. One example if BurstCoin, but we won’t talk about that 😂

Let me start off by saying that the plotting process takes a VERY long time. For me, I was lucky to get a plot done in 3/4 hours as my hardware is quite old. So since I already had a bunch of hard drives lying around, all I purchased to get this up and running is a SATA HBA card and some SATA power splitter cables.

This is an image of my current system as of 10th March 2022:

My very professional Chia plotting and farming rig

In that time I’ve made only around $10…#

I currently have around 30TB of plots and I am using Space Pool as solo farming isn’t a good idea at this low amount of storage.

Now, this system hasn’t been running the entire time. The Chia GUI loves to disconnect and now as NOT SYNCED for it’s own amusement. I probably lost a week or so of no mining or plotting due to this.

Am I happy with my results? Yes and no. If I was in it just for the money then definitely not. As as learning experience and trying new technologies? Yeah it has been fun.

My setup is definitely not ideal, I mean just look at the image above 🙄

I will try to keep releasing progress updates on my ‘farm’ as I still have a number of drives to completely plot.

Thank you for reading! Enjoy!

Removing Chat from Windows 11 Taskbar

Hi all,

quick one today! 😱

How to remove the seemingly useless version of Team (called Chat) from Windows 11. Wish they allowed work and school accounts as the interface is quiet slick!

Right click the taskbar -> TaskBar Settings -> untick ‘Chat’ in the menu

It’s as simple as that! Normally, Microsoft makes it MUCH harder to remove or hide default bloatwa… sorry, software.

Some images here just for a the visual peeps!

Windows 11 TaskBar Settings
Windows 11 Chat Disabled

Enjoy! 🎉

Mass PST Importing using AZCopy

Ooooofff!! Been a while, man! Long time no write 😱🤷‍♂️

So, a little bit of back story – sometimes I need to import a tonne of PSTs to people O365 account for my job. I used to do this in a VERY manual way of adding their account to my Outlook and running the import. Or just giving them the PST with a guide to importing. Something needed to change!

I found a better way, I could use AZCopy to upload the files to an Azure Storage Blob and then import automatically using the built-in O365 admin tools.

First step!

Login to https://compliance.microsoft.com and head into the Information Governance -> Import section. Create a new ‘Import’ and name is as you like, not special characters though!

Select the option to upload your data, and copy the SAS URL link. The download the Azure AzCopy program. This is what we use to upload the PST files.

Second Step!

Open a command prompt or PowerShell in the same location as the AzCopy program and run the below command:

azcopy.exe copy “path to PST files” “SAS URL” –recursive

I used the recursive option as, without it, my operation wasn’t seeing the PSTs.

Leave this to run, it can take a while depending on your data. There are other parameters to this but I didn’t use them.

Third Step!

Create a PST Import mapping file – this is the step that confused me but hopefully, I can shed some light on it! Download a copy of it from here

I left the TargetRootFolder, ContentCodePage, SPFileContainer, SPManifestContainer and SPSiteURL empty. Since my data was in the following path ‘E:\Company\over_20gb’ I needed to set the FilePath to ‘over_20gb’ for all entries.

This is an example of my file:

Workload FilePath Name Mailbox IsArchive

Exchange over_20gb first.last@company.com.pst first.last@company.com FALSE

Fourth Step!

Repeat step one until the upload, tick box buttons for I’m done uploading my files AND I have access to the mapping file. Use the Select mapping file and upload your file. Following that, you can Validate.

If all is well after the validation, you can either choose to filter your data or not and start the import.

The progress of this import is visible on the Importing page. Be prepared to wait as it can take a looooong time!

Enjoy! 😎

Migrating an Azure VM to HyperV or VMware

Hi All!

Today, I’ll be showing a brief overview of how I migrated some Azure VMs to an on-premise HyperV and VMware server. This is done in stages and for me, required HyperV as a middle man before moving to VMware.

First, log in to your Azure portal and find the VM that you want to migrate. Open the settings for the VM and go into the ‘Disks’

Click on the blue text that shows the VM disk name. This should open the settings for the VM disk. Head to the ‘Disk Export‘ tab and generate a new URL to download the disk. TIP: download this onto your HyperV server.

Once this has downloaded, we can head to the next step!

The download may leave a file without an extension or with a VHD extension. If needed, add the VHD extension.

We now need to use HyperV to convert the VHD file to a VHDX format. Open HyperV, use the ‘Edit Disk‘ wizard. Find the disk and use the convert option:

Once converted, create a new generation 2 VM with near-enough the same specs as the original Azure VM. Don’t create a disk with this VM. Once the VM has been created, add the new VHDX file to the SCSi controller. Make sure to untick the enable secure boot option in the VM firmware tab:

The VM should now boot as the original Azure VM 🥳

From here it’s easy to get the VM onto VMware. Just use the VMware converter tool on the HyperV box whilst the VM is shutdown or on the VM whilst it’s running (this method is slower).

Hope this helped someone out 🙂

Sending Custom HTML Emails via PowerShell

Hi Everyone,

I hope COVID restrictions are starting to ease for you all. Still, don’t want to let your guard down too much, ey! Better safe than sorry.

In this post, I’m showing a simple way to send HTML emails from PowerShell. This includes sending emails that contain local images instead of hosting them on a separate website. I might have done this in the past, but I want to just throw this out there again. Lets hop in!

First of all, HTML shows different on EVERY SINGLE DEVICE. Outlook is particularly bad, completely ignoring the head that might contain styling and CSS. So the only way around this is to put the styling on every single element in the HTML body.

Here is the HTML I used, we will discuss what is happening below:

<!DOCTYPE html>
    <html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:o="urn:schemas-microsoft-com:office:office">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <meta name="x-apple-disable-message-reformatting">
        <title></title>
        <!--[if mso]>
          <noscript>
             <xml>
                <o:OfficeDocumentSettings>
                   <o:PixelsPerInch>96</o:PixelsPerInch>
                </o:OfficeDocumentSettings>
             </xml>
          </noscript>
          <![endif]-->
        <style>
            table,
            td,
            div,
            h1,
            p {
                font-family: Arial, sans-serif;
            }
        </style>
    </head>
<body style="margin:0;padding:0;">
        <table role="presentation" style="width:100%;border-collapse:collapse;border:0;border-spacing:0">
            <tr>
                <td align="center" style="padding:0;">
                    <table role="presentation"
                        style="width:800px;border-collapse:collapse;border-spacing:0;text-align:left;">
                        <!--Logo-->
                        <tr>
                            <td align="center" style="padding:40px 0 10px 0">
                                <img src="cid:logo.png" alt="" width="350" style="height:auto;display:block;" />
                            </td>
                        </tr>
                        <tr>
                            <td style="padding:10px 10px 10px 10px;">
                                <table role="presentation"
                                    style="width:100%;border-collapse:collapse;border:0;border-spacing:0;">
                                    <!--First chunk-->
                                    <tr>
                                        <td style="padding:0 0 20px 0">
                                            <h1
                                                style="font-size:38px;margin:0 0 20px 0;font-family:Arial,sans-serif;text-align:center;">
                                                Information Technology
                                            </h1>
                                            <p
                                                style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family:Arial,sans-serif;">
                                                Dear $firstname,
                                            </p>
                                            <h2 style="font-size:22px;margin:0 0 10px 0;font-family:Arial,sans-serif">
                                                Welcome!
                                            </h2>
                                            <p
                                                style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family:Arial,sans-serif;">
                                                Generic text can go here
                                            </p>
                                            <h2 style="font-size:22px;margin:0 0 10px 0;font-family:Arial,sans-serif">
                                                Your Login Information
                                            </h2>
                                            <p>
                                                style="margin:0 0 12px 0;font-size:16px;line-height:24px;font-family:Arial,sans-serif;">
                                                More generic text
                                           </p>
                                            <p>
                                                style="margin:0;font-size:16px;line-height:24px;font-family:Arial,sans-serif;">
                                            </p>
                                        </td>
                                    </tr>
								</table
							</td>
                        </tr>
                    </table>
                </td>
            </tr>
        </table>
        </td>
        </tr>
        <!--Footer-->
        <tr>
            <td style="padding:30px;background:#272a36;">
                <table role="presentation"
                    style="width:100%;border-collapse:collapse;border:0;border-spacing:0;font-size:9px;font-family:Arial,sans-serif;">
                    <tr>
                        <td style="padding:0;width:50%;" align="center">
                            <p style="margin:0;font-size:18px;line-height:16px;font-family:Arial,sans-serif;color:#ffffff;">
                                For an additional support, or if you have any questions, please
                                send an email to <a href="mailto:help@example.com"
                                    style="color:#d6d6d6;text-decoration:underline;">help@example.com</a>
                            </p>
                        </td>
                    </tr>
                </table>
            </td>
        </tr>
        </table>
        </td>
        </tr>
        </table>
    </body>
</html>
  • Setting the Office product details and pixel density information
  • The logo.png is loaded using the cid: prefix which looks at the loaded images, you can see this below
  • The rest is just generic HTML with inline styling

Next we need to start creating the PowerShell email object.

#Define a valid SMTP server to send your emails through
$smtpServer = 'SERVER HERE' #e.g smtp.local.com
#Define a new SMTP object using the server defined above
$smtpObject = New-Object Net.Mail.SmtpClient($smtpServer)

#Create a new mail message object 
$msg = New-Object Net.Mail.MailMessage
$msg.From = 'DoNotReply@example.com'
$msg.ReplyTo = 'bccemail@example.com'
$msg.BCC.Add('bccemail@example.com')
$msg.To.Add('recipient@example.com')
$msg.subject = 'Example Email Subject'
$msg.IsBodyHtml = $True

$msg.Body = 'HTML FROM ABOVE - This can be a separate variable or right here'

#Provide a path to the photos for the email
$scriptPath = 'C:\example'

#Create a new mail attachment as an image
$logo = New-Object System.Net.Mail.Attachment -ArgumentList "$scriptPath\logo.png"
$logo.ContentDisposition.Inline = $True
$logo.ContentDisposition.DispositionType = "Inline"
$logo.ContentType.MediaType = "image/png"
$logo.ContentId = 'logo.png'

#Add the image attachment to the email, this allows the HTML to use the cid: prefix
$msg.Attachments.Add($logo)

#Try to send the email
try{
    $smptObject.Send($msg)
}catch{
    Write-Host 'Failed to send the email: ' -ForegroundColor Red -NoNewLine
    Write-Host $Error[0] -ForegroundColor Red
}

#Dispose of the image attachments and the email object to avoid memory leaks
#logo.Dispose()
$msg.Dispose()

Hopefully this shows just how easy it is to create and send HTML emails using PowerShell, including images send directly from the script instead of hosting them and suppling a web page URL.

If you have any questions etc, feel free to comment and I’ll help however I can.

Enjoy! 🙂

Generating Easy and Secure Passwords in PowerShell

Hi Everyone,

So the other day, I found a much easier way to generate secure passwords in PowerShell. Before this, we had to have a list of all the available characters and put them into a CharArray, or ping an internet service like dinopass.com.

Not anymore!

From now on, whenever I need to generate a password in PowerShell, I will be using the

GeneratePassword()

Function from the [System.Web.Security.Membership] namespace. What this allows you to do, is generate a string of a specified length, with a specified amount of alphanumerical characters.

So if I wanted a password that was 10 characters long and had 5 alphanumerical characters, I would use:

[System.Web.Security.Membership]::GeneratePassword(10,5)

I usually just wrap that in a function because I’ve found you need to add the ‘System.Web’ assembly and it’s cleaner to add it in the function rather than the entire script. This is my new function:

function New-RandomPassword(){
    Add-Type -AssemblyName 'System.Web'
    return [System.Web.Security.Membership]::GeneratePassword(10,5)
}

Hope you learnt something from this 🙂

Using RxDart and Flutter to Create A Timer

Final product

Hi Everyone! Very long time without any content 😢 This year, as you can probably imagine, was very hectic. Something had to give, and unfortunately, it was this creative outlet that lost out. Let’s jump straight into something completely different!

I’ve been learning Flutter and mobile development, which has been very exciting! Today, I wanted to share with you a little example of a timer app built using Flutter with RxDart as a state management solution. Basically, that means not using the standard setState command in the Stateful Widget.

To kick things off, you’ll want to add the latest version of RxDart into your pubspec.yaml file. At the time of writing, this looks like the following:

rxdart: ^0.24.1

In the main.dart file, it can be kept pretty much as a blank slate. Only making sure to replace the home of the Scaffold with a new view. I like to create a separate folder for my ‘ui’ and my ‘state’.

We’ll kick off first by looking at the timer_state.dart that will be using RxDart. We need to create a new class, which I will call ‘TimerState’. In this new class, we need to create the following variables:

  • Private Stopwatch
  • BehaviorSubject of type String to track the timer display
  • BehaviorSubject of type bool to track whether the timer is running or not
  • A string for the initial display value set to ’00:00′
  • A bool for the initial running state of the timer, set to false

For the class builder, we need to build the two BehaviorSubjects. We’ll do that by creating the following class constructor:

TimerState({this.initialDisplay, this.initialIsRunning}) {
    _subjectDisplay = BehaviorSubject<String>.seeded(this.initialDisplay);
    _subjectIsRunning = BehaviorSubject<bool>.seeded(this.initialIsRunning);
}

Next, we need to create the two Streams that we can watch for changes to the timer display and whether the timer is running or not. We’ll use these in the UI:

Stream<String> get timerObservable => _subjectDisplay.stream;

Stream<bool> get isRunningObservable => _subjectIsRunning.stream;

To finish off the TimerState class, we need to build quite a few functions to help use the timer/stopwatch. Here’s a list below:

  1. Public function for starting the timer
  2. Private function for running the timer every second
  3. Private function for keep the timer running
  4. Private function for formatting the elapsed time to a minutes/seconds format
  5. Public function for pausing the timer
  6. Public function for resetting the timer
  7. Public function for resuming the timer
  8. Public dispose function to remove the BehaviorSubjects to avoid memory leaks

For simplisity sakes, here is the full class below:

import 'dart:async';
import 'package:rxdart/rxdart.dart';

///The class for the timer
class TimerState {
  ///The Stopwatch object for running the timer
  final Stopwatch _sWatch = Stopwatch();

  ///Creating a BehaviorSubject of type String for the Stopwatch display
  BehaviorSubject<String> _subjectDisplay;

  ///Creating a BehaviorSubject of type bool for the IsRunning variable
  BehaviorSubject<bool> _subjectIsRunning;

  ///The initial String value for the Stopwatch display
  String initialDisplay = '00:00';

  ///The initial bool value for the IsRunning variable
  bool initialIsRunning = false;

  ///The class builder
  ///Takes in the local initialDisplay and initialIsRunning to seed the
  ///subject behaviours
  TimerState({this.initialDisplay, this.initialIsRunning}) {
    _subjectDisplay = BehaviorSubject<String>.seeded(this.initialDisplay);
    _subjectIsRunning = BehaviorSubject<bool>.seeded(this.initialIsRunning);
  }

  ///A Stream for the Stopwatch String value
  Stream<String> get timerObservable => _subjectDisplay.stream;

  ///A Stream for the IsRunning bool value
  Stream<bool> get isRunningObservable => _subjectIsRunning.stream;

  ///Start the timer
  ///
  ///If the timer already has a value, it continues where it left off. Otherwise,
  ///it starts counting from 00:00
  void startTimer() {
    _subjectIsRunning.value = true;
    _sWatch.start();
    _startTimer();
  }

  ///Runs the Stopwatch every second
  void _startTimer() {
    Timer(Duration(seconds: 1), _keepRunning);
  }

  ///Keeps the Stopwatch running and updates the Stopwatch display BehaviourSubject
  void _keepRunning() {
    //Stop the timer from overflowing, max value should be 99:99
    if (_sWatch.elapsed.inMinutes >= 100) {
      pauseTimer();
      return;
    }
    if (_sWatch.isRunning) {
      _startTimer();
    }
    _subjectDisplay.sink.add(_formatStopWatch(_sWatch));
  }

  ///Formats the StopWatch elapsed time into the 00:00 format
  String _formatStopWatch(Stopwatch _swatch) {
    final String _inMinutes =
        (_swatch.elapsed.inMinutes % 60).toString().padLeft(2, '0');
    final String _inSeconds =
        (_swatch.elapsed.inSeconds % 60).toString().padLeft(2, '0');

    return "$_inMinutes:$_inSeconds";
  }

  ///Pause the timer and stop on the current display from being changed
  void pauseTimer() {
    _subjectIsRunning.value = false;
    _sWatch.stop();
  }

  ///Reset the timer display and the Stopwatch object
  void resetTimer() {
    _subjectIsRunning.value = false;
    _subjectDisplay.sink.add('00:00');
    _sWatch.reset();
    _sWatch.stop();
  }

  ///Resumed the timer and continue updating the Stopwach display
  void resumeTimer() {
    _subjectIsRunning.value = true;
    _sWatch.start();
    _startTimer();
  }

  ///Dispose of the BehaviorSubjects
  void dispose() {
    _subjectDisplay.close();
    _subjectIsRunning.close();
  }
}

This class and the app in general could be a lot simpler, but I chose to keep the pause, resume and reset options. Only the best content here 😂

Finally, lets move onto the actual UI 🥳

So, we will need a StatefulWidget as we will be creating an instance of the TimerState class which will need disposing. All the items in my view that needed to change, such as the buttons and the display, were built using the StreamBuilder widget. This is an awesome little widget that listens to a Stream and then changes the output based on a builder function. Here is a example:

StreamBuilder(
    stream: _timerState.timerObservable,
    builder: (context, snapshot){
        if(snapshot.hasData){
            return Text(snapshot.data)
        }else{
            return Text('No data')
        }
    }
)

Flutter widget trees can get quite confusing to look at, so imma just dump it here for you to look at 🤦‍♂️

import 'package:flutter/material.dart';
import 'package:rxdart_timer/blocs/timer_state.dart';

class TimerView extends StatefulWidget {
  @override
  _TimerViewState createState() => _TimerViewState();
}

class _TimerViewState extends State<TimerView> {
  //Create a new instance of the timer for the stateful widget
  TimerState _timerState = TimerState();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          ///Stream builder to watch the timer observable stream from the BLOC
          StreamBuilder(
            stream: _timerState.timerObservable,
            builder: (context, snapshot) {
              ///Checking if the Stream has data
              ///
              ///For some reason, the seeded option isn't working in the BLOC
              if (snapshot.hasData) {
                return Text(snapshot.data);
              } else {
                return Text('00:00');
              }
            },
          ),
          const SizedBox(
            height: 40,
          ),

          ///The start button built using a StreamBuilder
          ///
          ///Checked if the timer is running and sets a seperate bool. The button then
          ///checks this bool and either allows the startTimer function to be ran or
          ///simple disabled the button
          StreamBuilder(
            stream: _timerState.isRunningObservable,
            builder: (context, snapshot) {
              bool _running = snapshot.hasData ? snapshot.data : false;
              return FlatButton(
                color: Colors.green,
                onPressed: _running ? null : _timerState.startTimer,
                child: Text('Start'),
              );
            },
          ),

          ///A row for containing the StreamBuilder for the Pause button and a
          ///regular Reset button
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ///Using a StreamBuilder to build the Pause button
              ///
              ///I build another bool, similar to the strart button, to check whether the
              ///button should be enabled.
              StreamBuilder(
                stream: _timerState.isRunningObservable,
                builder: (context, snapshot) {
                  bool _running = snapshot.hasData ? snapshot.data : false;
                  return Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      FlatButton(
                        color: Colors.red[600],
                        onPressed: _running ? _timerState.pauseTimer : null,
                        child: Text('Pause'),
                      ),
                    ],
                  );
                },
              ),

              ///Seperating the Pause and Stop button by 30 pixels
              const SizedBox(
                width: 30,
              ),

              ///Reset button, always enabled
              FlatButton(
                color: Colors.yellow[700],
                onPressed: _timerState.resetTimer,
                child: Text('Reset'),
              ),
            ],
          )
        ],
      ),
    );
  }

  ///Disposes of the _timerState
  @override
  void dispose() {
    _timerState.dispose();
    super.dispose();
  }
}

There we go, I hope you can see all of the code goes together. Basically, adding on top of Darts built in Streams to make them easier to manage and subscribe to 🙂

On top of all the code in the post, here is a link to my GitHub repo with all the code. You might notice a few differences as well.

Comment if you have any issues 💕

WPF Material Design Toggle Button

Another short post today, here I modified the code for my Apple Style Toggle Button so that it more resembled the MaterialDesign toggle button. I thought of this whilst playing with the YouTube autoplay button. Here is my code:

<Style TargetType="{x:Type ToggleButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ToggleButton}">
                <Viewbox>
                    <Border x:Name="Border" CornerRadius="10"
                            Background="#FFE2E2E2"
                            Width="40" Height="20">
                        <Border.Effect>
                            <DropShadowEffect ShadowDepth="0.5" Direction="0" Opacity="0.3" />
                        </Border.Effect>
                        <Ellipse x:Name="Ellipse" Fill="#FF909090" Stretch="Uniform"
                                 Margin="-8 -4"
                                 Stroke="Gray" StrokeThickness="0.2"
                                 HorizontalAlignment="Stretch">
                            <Ellipse.Effect>
                                <DropShadowEffect BlurRadius="10" ShadowDepth="1" 
                                                  Opacity="0.3" Direction="260" />
                            </Ellipse.Effect>
                        </Ellipse>
                    </Border>
                </Viewbox>
                <ControlTemplate.Triggers>
                    <EventTrigger RoutedEvent="Checked">
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetName="Ellipse"
                                                    Storyboard.TargetProperty="(Ellipse.Fill).(SolidColorBrush.Color)"
                                                    To="#FF0069F3"
                                                    Duration="0:0:0.05"
                                                    AccelerationRatio="0.7"
                                                    DecelerationRatio="0.3"/>
                                <ThicknessAnimation Storyboard.TargetName="Ellipse"
                                                    Storyboard.TargetProperty="Margin"
                                                    To="20 -4 -8 -4"
                                                    Duration="0:0:0.15" 
                                                    AccelerationRatio="0.7"
                                                    DecelerationRatio="0.3"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                    <EventTrigger RoutedEvent="Unchecked">
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetName="Ellipse"
                                                    Storyboard.TargetProperty="(Ellipse.Fill).(SolidColorBrush.Color)"
                                                    To="#FF909090"
                                                    Duration="0:0:0.05" 
                                                    AccelerationRatio="0.7"
                                                    DecelerationRatio="0.3"/>
                                <ThicknessAnimation Storyboard.TargetName="Ellipse"
                                                    Storyboard.TargetProperty="Margin"
                                                    To="-8 -4"
                                                    Duration="0:0:0.15"
                                                    AccelerationRatio="0.7"
                                                    DecelerationRatio="0.3"/>
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

And finally, here is a little GIF of the toggle button:

Enjoy!

Apple Style Toggle Button in WPF

A nice short post here, I wanted to share with you some code I recently used to create an Apple-style toggle button for WPF applications. I was quite surprised with how easy this was to make. Obviously it isn’t perfect but it makes do for my applications.

This is the style that I used:

<Style TargetType="{x:Type ToggleButton}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ToggleButton}">
                <Viewbox>
                    <Border x:Name="Border" CornerRadius="10"
                            Background="#FFFFFFFF"
                            Width="40" Height="20">
                        <Border.Effect>
                            <DropShadowEffect ShadowDepth="0.5" Direction="0" Opacity="0.3" />
                        </Border.Effect>
                        <Ellipse x:Name="Ellipse" Fill="#FFFFFFFF" Stretch="Uniform"
                                 Margin="2 1 2 1"
                                 Stroke="Gray" StrokeThickness="0.2"
                                 HorizontalAlignment="Stretch">
                            <Ellipse.Effect>
                                <DropShadowEffect BlurRadius="10" ShadowDepth="1" Opacity="0.3" Direction="260" />
                            </Ellipse.Effect>
                        </Ellipse>
                    </Border>
                </Viewbox>
                <ControlTemplate.Triggers>
                    <EventTrigger RoutedEvent="Checked">
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetName="Border"
                                                    Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                    To="#FF4CD661"
                                                    Duration="0:0:0.1" />
                                <ThicknessAnimation Storyboard.TargetName="Ellipse"
                                                        Storyboard.TargetProperty="Margin"
                                                        To="20 1 2 1"
                                                        Duration="0:0:0.1" />
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                    <EventTrigger RoutedEvent="Unchecked">
                        <BeginStoryboard>
                            <Storyboard>
                                <ColorAnimation Storyboard.TargetName="Border"
                                                    Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)"
                                                    To="White"
                                                    Duration="0:0:0.1" />
                                <ThicknessAnimation Storyboard.TargetName="Ellipse"
                                                        Storyboard.TargetProperty="Margin"
                                                        To="2 1 2 1"
                                                        Duration="0:0:0.1" />
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Using this, I am able to have any size toggle button I want and it will still look the same. Thank goodness for view boxes! 🙌

Here is a little GIF showing the toggle button in action. I left it to just resize depending on the actual window to demonstrate it’s scalability:

Enjoy!