PowerShell Classes and Class Lists

I found that I could use classes in PowerShell similar to how I use them in C#. I instantly wanted to play with this and I thought I would share this as well.

To create a class in PowerShell, it’s as simple as:

#Person class
class PersonClass{
	[String]$Name
	[Int]$Age
}

This allows a “Person” to be created that has the attributed of a name and an age. Simple stuff.

Say I wanted to have a bunch of these “Person”s in a list, a “People” list if you will. Then I could do something like this:

#Creating a list to hold the people using the PersonClass
$People = New-Object 'System.Collections.Generic.List[PSObject]'

#Creating a new person
$newPerson = [PersonClass]::new()
$newPerson.Name = "Roy Orbison"
$newPerson.Age = "24"

#Adding the new person to the people list
$People.Add($newPerson)

What if I wanted to add something like a “Pets” attribute onto the person? Well, I could create a new class to hold a framework for each pet and create a new list attribute in the PersonClass. Here is my PetClass:

#Pet class
class PetClass{
    [String]$Name
    [Int]$Age
    [String]$Color
}

And here is how I add it to my PersonClass so that I can have a list of pets for each user:

#Person class
class PersonClass{<br>    [String]$Name
    [Int]$Age
    [PetClass[]]$Pets
}

Now its really simple to create a list of people with a list of any pets that they might have. Stitching this all together, it looks like this:

#Person class
class PersonClass{
	[String]$Name
	[Int]$Age
    [PetClass[]]$Pets
}

#Pet class
class PetClass{
    [String]$Name
    [Int]$Age
    [String]$Color
}

#Creating a list to hold the people using the PersonClass
$People = New-Object 'System.Collections.Generic.List[PSObject]'

#Creating a new person
$newPerson = [PersonClass]::new()
$newPerson.Name = "Roy Orbison"
$newPerson.Age = "24"

#Adding pets to the new person
for ($i = 0; $i -le 5; $i++){
    $newPet = [PetClass]::new()
    $newPet.Name = $i
    $newPet.Age = $i + 2
    $newPet.Color = "Brown"

    #Adding the pet to the new person
    $newPerson.Pets += $newPet
}

#Adding the new person to the people list
$People.Add($newPerson)

Above you can see that I have created a new person called “Roy Orbison” with an age of “24” and I have added five pets. The pet names and age aren’t really accurate but it’s good enough for this demonstration.

Continuing from this, I could add as many users as I want or even create new classes to add extra framework information for existing classes.

Searching this information isn’t as straight forward in PowerShell as it is in C# but it’s still quite easy. You can see how I get a list of all the pets that Roy Orbison has below:

$People | Where-Object {$_.Name -eq "Roy Orbison"} | Select-Object -ExpandProperty Pets

Upon finishing this, I realised that it would have been much more appropriate to do the users and albums, instead of pets. But I’m far too lazy to change what I already have…

Enjoy!

Caliburn.Micro MVVM Boolean To Visibility Converter

Say I wanted to toggle the visibility of a WPF object in an MVVM way, what would I need to do?

Here is what I currently have:

  • ViewModels
    • ShellViewModel
    • LoadingViewModel
  • Views
    • ShellView
    • LoadingView

When the application is loaded, the ShellViewModel is used to display the LoadingView in a ContentControl object. I have a button on there that I want to become visible after the LoadingView has been activated for 5 seconds.

What I need to do is created a custom class that has two methods: a way of converting a boolean to a visibility; and a way of converting a visibility to a visibility.

So I created a new folder in my tree called “Converters“. In here, I create a new class called “BooleanToVisiblityConverter“.  Here is what my tree now looks like:

  • ViewModels
    • ShellViewModel
    • LoadingViewModel
  • Views
    • ShellView
    • LoadingView
  • Converters
    • BooleanToVisibilityConverter

In my BooleanToVisibilityConverter class, I inherited from IValueConverter and added the necessary two methods. You can see the entire class below:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;

namespace Project.Converters
{
    /// <summary>
    /// Contains the converter and convertback methods for the boolean to visibility conversions
    /// </summary>
    public sealed class BooleanToVisibilityConverter : IValueConverter
    {
        /// <summary>
        /// Used to convert a boolean to a visibility
        /// </summary>
        /// <param name="value">This is the boolean input</param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns>Returns a visibility</returns>
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (!(value is bool))
            {
                //If there is an issue with the input, return collapsed
                return Visibility.Collapsed;
            }
            return (bool)value ? Visibility.Visible : Visibility.Collapsed;
        }

        /// <summary>
        /// Used to take a visibility and returns a visibility
        /// </summary>
        /// <param name="value">This is the boolean input</param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns>Returns a visibility</returns>
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (!(value is Visibility))
            {
                //If there is an issue wtih the input, return collapsed
                return Visibility.Collapsed;
            }
            return (Visibility)value == Visibility.Visible;
        }
    }
}

Next, in my LoadingView, I added “ xmlns:sp=”clr-namespace:Project.Converters” so that the view could use the converter namespace. This is what my view dependancies look like:

<UserControl x:Class="Project.Views.MainView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:cal="http://www.caliburnproject.org"
             xmlns:sp="clr-namespace:Project.Converters"
             xmlns:local="clr-namespace:Project.Views"
             mc:Ignorable="d" FontSize="14" FontFamily="/Project;component/Assets/Fonts/#Roboto"
             d:DesignHeight="550" d:DesignWidth="400">

I then added the binding to the visibility property of my button. You can see this below:

<Button Name="LoadingButton" Content="Press Me" Visibility="{Binding ButtonIsVisible, Converter={StaticResource BooleanConverter}, FallBackValue=Collapsed}"

This means that it will get its visibility value from the LoadingViewModel and if this fails, it will fall back to being collapsed.

We’re almost done. In the LoadingViewModel create a full property which will hold and change the value for the visibility. This needs to be named the same as the binding given in the LoadingView (i.e ButtonVisibility). You can see this below:

private bool _buttonIsVisible;

public bool ButtonIsVisible
{
    get {return _buttonIsVisible;
    set
    {
        if (value != _buttonIsVisible)
        {
            _buttonIsVisible = value;
            NotifyOfPropertyChange(() => ButtonIsVisible);
        }
    }
}

So now if you want the button to be visible, you can just update the ButtonIsVisible property in the LoadingViewModel. Here is an example below (Don’t actually do this):

public LoadingViewModel(){
    ButtonIsVisible = false;
    Task.Delay(5000);
    ButtonIsVisible = true;
}

I hope this helped you. Enjoy!