Introducing .NET 5.0 Use in WPF through C#

Spread the love

Today marks the new update to Visual Studio 2019 to 16.8.0 – here we get to start to use the new features within C# for ourselves.

Today, we will focus on an interesting adaption of what was shown last night in the release steam, now a video, be sure to check it out. There will be more tonight, check it out.

Step 1: Update VS2019 to 16.8.0

First of all, it’s rather obvious, and repetitive to share again, use your Visual Studio Installer to update your VS2019 to 16.8.0, you can double check you have all the features you want.

I use these, and also Office/SharePoint Development on my work laptop.

I figure the main element here would be .NET desktop development. This allows the WPF development I love to use for the software I develop.

When done installing, you can create a new project for yourself.

The project types we use today.

I first created a WPF App (.NET), and then add a new WPF Library (.NET). At this current moment, it will be on .NET Core 3.1. You’ll need to change the project settings for yourself to .NET 5.0.

Select .NET 5.0 on both projects

Then, of course, add references.

Add the library as a reference to the App we make

You should be ‘good to go’, so to speak.

You can download the actual example project files I share here at the end.

Note: On my desktop the update was all that’s needed, my work laptop I needed to uninstall VS2019 and reinstall it. If you see the ‘New Project’ dialogue is old you might need to do the same.

Step 2: Let’s Consider Some Data

Let’s clear out the Class1.cs file for ourselves, we’ll leave it mostly blank first.

namespace ExampleLibrary
{
    
}

The first thing for us to consider is that we can make a record. There are several ways we can write it all out for ourselves if we want to, however, we’ll just do it the fastest method:

namespace ExampleLibrary
{
    public record Person(string FirstName, string Surname);
}

Yes, I’m not kidding. We needed a single line. There are several features we get from this, so let me put it into a little perspective. Consider the following:

namespace ExampleLibrary
{
    public class Person
    {
        public string FirstName { get; private set; }
        public string Surname { get; private set; }

        public Person(string firstName, string surname)
        {
            FirstName = firstName;
            Surname = surname;
        }
    }
}

If we use the class above we’d need to do the following:

var person = new Person("Joe", "Soap");

When we use the record above we can simplify it a touch.

Person p = new("Joe", "Soap");

.Net 5 has some interesting features that we can look at for our data use. We can write simpler, more understandable, code for ourselves in our projects.

Just consider the old style, we’d go ‘a person is a new person with name Joe Soap‘. The new style’s readability leads us towards ‘it’s a new person, Joe Soap‘. These aren’t the exact terms, it’s way easier in readability, so it can help our data.

It does make some people ask ‘how would we know what to do with the new(…) statements?’

VS2019 assists

You can clearly see we still have access to the same usability we had before in the previous styles, it will let you know what you can put there.

You’ll have seen, above in Person: Old Style code, we’ve had to do a lot to design that record for ourselves. We might need to add more functionality to them though, would be the next point.

    public record Pet
    {
        public string Name { get; init; }
        public string Food { get; init; }
        public string Detailed => Name + " eats " + Food;
    }

You’d no doubt notice here we use init, it’s how the record Person above also manages the data, it can only be set on creation. We can look at it anywhere, obviously, we can see the detailed version as well.

I’d hope the implementation of Detailed won’t trouble anyone, it’s an easy way to implement a get for a string.

The next thing to show off is we can do slightly more complex calculations for ourselves. We can easily work out, from the object state, what a Person has from this functional switch:

    public static class Data
    {
        public static bool HasSoapSurname(object person) =>
            person switch
            {
                Person p when p.Surname == "Soap" => true,
                _ => false
            };
    }

This might not share enough, it’s to point out the new switch form. It’s simple, and easy to understand. You can tell ‘_‘ is the ‘if no match above, then this‘ statement.

To give it to you in a different perspective, we’ll swap the function for ourselves.

    public static class Data
    {
        public static string GetName(object whom) =>
            whom switch
            {
                Person p => "We're looking at " + p.FirstName + " " + p.Surname,
                Pet p => "Aw, it's a cute pet, we called him " + p.Name + ", " + p.Detailed,
                _ => "We couldn't work out any name here"
            };
    }

Sure, we don’t do complex things here, just know we can do tons more with this usability, and functionality.

The next thing to note, is we can do our abstract data inheritance as usual from the days of the class we used.

    public abstract record TypeAnimal
    {
        public abstract string TypeName();
    }

    public record Dog : TypeAnimal
    {
        public override string TypeName() => "Dog";
    }

In the same way, we can set up what we’d need through an abstract record, much like some of what we got through interfaces. We just have more control, and more functionality from here.

We can use the record data type to our advantage.

using System;
using System.Collections.Generic;
using System.Windows.Documents;

namespace WPFNet5ExampleLibrary
{
    public record Person
    {
        public string Name { get; init; }
        public static Person NewPerson()
        {
            List<Person> People = new List<Person>();
            People.Add(new Person { Name = "edg3" });
            
            if (HasName(People[0]))
            {
                if (People[0] is not Person)
                {
                    throw new Exception("Isn't a person.");
                }
                else
                {
                    Person joe = new() { Name = "Joe Soap" };
                    People.Add(joe);

                    Person[] persons = { new() { Name = "Jane Doe" }, new() { Name = "Bob Bobsons" } };

                    var dog = new Pet("Boxer", "Scotish Terrior");
                }
            }

            return People[0] with { Name = "za" };
        }

        public static bool HasName(object person) =>
            person switch
            {
                Person p when p.Name == "edg3" => true,
                Person => false,
                _ => throw new Exception("Wasn't a person.")
            };
    }

    public record Pet(string Name, string Type);
    
    public abstract class Animal
    {
        public abstract string Food();
    }

    public class Dog : Animal
    {
        public override string Food() => "Boerewors";
    }
}

You’ll note, I played around a touch, took a look at some other ideas as well. We’ll stop there for random code snippets, perhaps you will see something I’ve done and not mentioned that interest you.

Reminder: You can download the actual example project files I share here at the end.

Step 3: Step Into WPF For Ourselves

Now, please note, we are not sticking to proper MVVM style here. If it’s requested I can do a better example of it with the new .Net 5 features. My MVVM examples are very minimal, I assume everyone usually knows what they need to.

For starters, I add a little sample data for us to use in the WPF Application we made.

        List<Person> _persons = new List<Person>()
            {
                new ("Joe", "Soap"),
                new ("Bob", "Blue"),
                new ("Jean", "Andrewson"),
                new ("Dan", "Dark")
            };
        public List<Pet> Pets => _pets;
        List<Pet> _pets = new List<Pet>()
            {
                new Pet() { Name = "Dog", Food = "Pork Chops"},
                new Pet() { Name = "Cat", Food = "Fish"}
            };

This is super simple to understand, except you’ll note how we need to instantiate our Pet here. When we initially create the Pet record we set it to init, however we don’t have a creation function. It isn’t that we’d always need it, it’s just so you can see the alternate ways to use this to your advantage.

Next, we implement the view:

    <Grid Loaded="Grid_Loaded">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <ListBox x:Name="lstPeople" Grid.Column="0" />
        <ListBox x:Name="lstPets" Grid.Column="1" />
    </Grid>

And because we aren’t using View Models or a View Model Locator, we implement the Load:

        private void Grid_Loaded(object sender, RoutedEventArgs e)
        {
            lstPeople.ItemsSource = Persons;
            lstPets.ItemsSource = Pets;
        }

This may seem crazy, but our record data is already usable!

Example data in a WPF Application we create

We can use our past experience with WPF Applications to our advantage now.

        <ListBox x:Name="lstPeople" Grid.Column="0">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid Background="LightGray" Width="300">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition />
                            <RowDefinition />
                        </Grid.RowDefinitions>
                        <Label Content="{Binding FirstName}" HorizontalAlignment="Center"/>
                        <Label Content="{Binding Surname}" HorizontalAlignment="Center" Grid.Column="1" Grid.Row="1" />
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <ListBox x:Name="lstPets" Grid.Column="1">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid Background="LightGreen" Width="300">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="1*"/>
                            <ColumnDefinition Width="3*"/>
                            <ColumnDefinition Width="1*"/>
                        </Grid.ColumnDefinitions>
                        <Label Grid.Column="1" HorizontalAlignment="Right" Content="{Binding Detailed}" />
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
We can make better styles for the record we use.

There will be tons of things you can get out of this for your WPF Projects, for me it will be a movement for my work projects.

Step 4: Take A Look

Our last step to share here, is quite obvious, try it out for yourself. I share examples for the setup, use, and binding, it should hopefully lead to you taking a look at the new .Net 5 for your projects!

Enjoy your steps into .NET 5!