Gigi Labs

Please follow Gigi Labs for the latest articles.
Showing posts with label advanced. Show all posts
Showing posts with label advanced. Show all posts

Friday, March 14, 2014

C#: Authenticating with Active Directory

Hi! :)

If you work in a corporate environment, chances are that your Windows machine is connected to a domain based on Active Directory. In today's article, we're going to write a very simple program that allows us to verify a user's credentials for the domain using Active Directory.

In order to try this out, you're going to need an Active Directory domain. In my case, I installed Windows Server 2008 R2 and followed these instructions to set up a domain, which I called "ranch.local". You may also be able to connect to your domain at work to save yourself the trouble of setting this up.

Let us now create a new Console Application using either SharpDevelop or Visual Studio. After adding a reference to System.DirectoryServices.AccountManagement, add the following statement near the top of your Program.cs file:

using System.DirectoryServices.AccountManagement;

Next, remove any code in Main() and add a simple prompt for the username and password to authenticate against Active Directory:

            // prompt for username

            Console.Write("Username: ");
            string username = Console.ReadLine();

            // prompt for password

            Console.Write("Password: ");
            string password = Console.ReadLine();

For the authentication part, we can use a simple method described here. After obtaining a reference to the domain using the PrincipalContext class (specifying the domain as a parameter), we simply use the ValidateCredentials() method to perform the authentication. This gives us a boolean value indicating whether the authentication was successful or not.

            // authenticate

            using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "RANCH"))
            {
                bool authenticated = pc.ValidateCredentials(username, password);

                if (authenticated)
                    Console.WriteLine("Authenticated");
                else
                    Console.WriteLine("Get lost.");
            }

At this point, we need only add a simple statement to wait for user input before letting the application terminate:

            Console.ReadLine();

Now, we can build our application and test it on the server (or on any machine that is part of the domain). First, let's try a valid login:


Very good! And now, a user that doesn't even exist:


Excellent! As you can see, it only takes a couple of lines of code to perform authentication against Active Directory. I hope you found this useful. Follow the Ranch to read more articles like this! :)

Saturday, February 22, 2014

SDL2: Converting an Image to Grayscale

Hello folks! :)

[Update 2015-11-14: This article is out of date. Check out the latest version at Gigi Labs.]

In the previous article, "SDL2: Pixel Drawing", we saw how to draw pixels onto a blank texture that we created in code. Today, on the other hand, we'll see how we can manipulate pixels on an existing image, such as a photo we loaded from disk. We'll also learn how to manipulate individual bits in an integer using what are called bitwise operators, and ultimately we'll convert an image to grayscale.

We first need to set up an SDL2 project. After following the steps in "SDL2: Setting up SDL2 in Visual Studio (2013 or any other)", you will also need to add SDL2_image.lib to your Linker Input (so that it reads "SDL2.lib; SDL2main.lib; SDL2_image.lib", and place the Visual C++ development libraries obtained from the SDL_image 2.0 homepage into the appropriate folders of your SDL2 directory. After you build your project the first time, make sure you also place all the necessary DLLs (including SDL2.dll, SDL2_image.dll and all the rest) into the same folder as your executable - see "SDL2: Loading Images with SDL_image" in case you need a refresher.

And in fact we're going to start with the code from "SDL2: Loading Images with SDL_image", which is the following (adapted a little bit):

#include <SDL.h>
#include <SDL_image.h>

int main(int argc, char ** argv)
{
    bool quit = false;
    SDL_Event event;

    SDL_Init(SDL_INIT_VIDEO);
    IMG_Init(IMG_INIT_JPG);

    SDL_Window * window = SDL_CreateWindow("SDL2 Grayscale",
        SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
    SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
    SDL_Surface * image = IMG_Load("PICT3159.JPG");
    SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer,
        image);

    while (!quit)
    {
        SDL_WaitEvent(&event);

        switch (event.type)
        {
        case SDL_QUIT:
            quit = true;
            break;
        }

        SDL_RenderCopy(renderer, texture, NULL, NULL);
        SDL_RenderPresent(renderer);
    }

    SDL_DestroyTexture(texture);
    SDL_FreeSurface(image);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    IMG_Quit();
    SDL_Quit();

    return 0;
}

We can also use the same sample image as in that project, so make sure it's in the appropriate folders where Visual Studio can find it.

Now, let's get down to business.

You see, the problem here is that we can't quite touch the texture pixels directly. So instead, we need to work a little bit similarly to "SDL2: Pixel Drawing": we create our own texture, and then copy the surface pixels over to it. So we throw out the line calling SDL_CreateTextureFromSurface(), and replace it with the following:

    SDL_Texture * texture = SDL_CreateTexture(renderer,
        SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STATIC,
        image->w, image->h);

Then, at the beginning of the while loop, add this:

        SDL_UpdateTexture(texture, NULL, image->pixels,
            image->w * sizeof(Uint32));

If you try and run program now, it will pretty much explode. That's because our code is assuming that our image uses 4 bytes per pixel (ARGB - see "SDL2: Pixel Drawing"). That's something that depends on the image, and this particular JPG image is most likely 3 bytes per pixel. I don't know much about the JPG format, but I'm certain that it doesn't support transparency, so the alpha channel is out.

The good news is that it's possible to convert the surface into one that has a familiar pixel format. To do this, we use SDL_ConvertSurfaceFormat(). Add the following before the while loop:

    image = SDL_ConvertSurfaceFormat(image, SDL_PIXELFORMAT_ARGB8888, 0);

What this does is take our surface (in this case the one that image points to) and return an equivalent surface with the pixel format we specify. Now that the new image has the familiar ARGB format, we can easily access and manipulate the pixels. Add the following after the line you just added (before the while loop) to typecast the surface pixels from void * to Uint32 * which we can work with:

    Uint32 * pixels = (Uint32 *)image->pixels;

So far so good:


Now, let's add some code do our grayscale conversion. We're going to convert the image to grayscale when the user presses the 'G' key, so let us first add some code within the switch statement to handle that:

        case SDL_KEYDOWN:
            switch (event.key.keysym.sym)
            {
            case SDLK_g:
                for (int y = 0; y < image->h; y++)
                {
                    for (int x = 0; x < image->w; x++)
                    {
                        Uint32 pixel = pixels[y * image->w + x];
                        // TODO convert pixel to grayscale here
                    }
                }
                break;
            }
            break;

This is where bit manipulation comes in. You see, each pixel is a 32-bit integer which in concept looks something like this (actual values are invented, just for illustration):

Alpha Red Green Blue
11111111 10110101 10101000 01101111

So let's say we want to extract the Red component. Its value is 10110101 in binary, or 181 in decimal. But since it's in the third byte from right, its value is much greater than that. So we first shift the bits to the right by 16 spaces to move it to the first byte from right:



Alpha Red
00000000 00000000 11111111 10110101

...but we still can't interpret the integer as just red, since the alpha value is still there. We want to extract just that last byte. To do that, we perform a bitwise AND operation:

Pixel 11111111 10110101
Mask 00000000 11111111
Red AND Mask 00000000 10110101

We do an AND operation between our pixel value and a value where only the last byte worth of bits are set to 1. That allows us to extract our red value.

In code, this is how it works:

                        Uint8 r = pixel >> 16 & 0xFF;
                        Uint8 g = pixel >> 8 & 0xFF;
                        Uint8 b = pixel & 0xFF;

The >> operator shifts bits to the right, and the & is a bitwise AND operator. Each colour byte is shifted to the last byte and then ANDed with the value 0xFF, which is hexadecimal notation for what would be 255 in decimal, or 11111111 in binary. That way, we can extract all three colours individually.

We can finally perform the actual grayscaling operation. A simple way to do this might be to average the three colours and set each component to that average:

                        Uint8 v = (r + g + b) / 3;

Then, we pack the individual colour bytes back into a 32-bit integer. We follow the opposite method that we used to extract them in the first place: they are each already at the last byte, so all we need to do is left-shift them into position. Once that is done, we replace the actual pixel in the surface with the grayscaled one:

                        pixel = (0xFF << 24) | (v << 16) | (v << 8) | v;
                        pixels[y * image->w + x] = pixel;

If we now run the program and press the 'G' key, this is what we get:


It looks right, doesn't it? Well, it's not. There's an actual formula for calculating the correct grayscale value (v in our code), which according to Real-Time Rendering is:

Y = 0.212671R + 0.715160G + 0.072169B

The origin of this formula is beyond the scope of this article, but it's due to the fact that humans are sensitive to different colours in different ways - in fact there is a particular affinity to green, hence why it is allocated the greatest portion of the pixel colour. So now all we have to do is replace the declaration of v with the following:

                        Uint8 v = 0.212671f * r
                            + 0.715160f * g
                            + 0.072169f * b;

And with this, the image appears somewhat different:


This approach gives us a more even distribution of grey shades - in particular certain areas such as the trees are much lighter and we can make out the details more easily.

That's all, folks! :) In this article, we learned how to convert an image to grayscale by working on each individual pixel. To do this, we had to resort to converting an image surface to a pixel format we could work with, and then copy the pixels over to a texture for display in the window. To actually perform the grayscale conversion, we learned about bitwise operators which assisted us in dealing with the individual colours. Finally, although averaging the colour channels gives us something in terms of shades of grey, there is a formula that is used for proper grayscale conversion.

Thanks for reading. Come back for the next article! :)

Monday, November 25, 2013

C# WCF: A Minimal Client and Server Using Visual Studio 2012

Hey there! :)

In this article we'll be taking a brief look at how to set up a very simple WCF client and server. We're actually going to let Visual Studio generate the server, and see how we can interact with it. WCF allows us to create applications that communicate remotely with one another - for instance, a client can call a method on a remote server and obtain the result. To follow along, you'll need a version of Visual Studio from 2008 onwards. Sadly, you can't do this in SharpDevelop.

To start off, set up a new WCF Service Library:


You'll notice that Visual Studio has generated some files for us, but let's worry about those later. For now, press F5. When you do that, this program comes up:


This WCF Test Client is actually a program that is communicating with our service (the one autogenerated by Visual Studio). We can see that there is this service at a particular URL on localhost:8733. This service is exposing a couple of methods, one of which is GetData(). Both methods are part of an interface (called a contract) called IService1. If you double-click on GetData(), you can see a Request section at the top, which shows the input parameters it can take.

Let's change the Value of the value parameter from 0 to 35, and then hit the Invoke button. If you get the following security warning, just click OK:


Once you click Invoke, the Response section at the bottom shows the return value, and echoes your input:


Let us now take a look at how this works. Our service exposes the two methods we have seen via the IService1 interface, and the Service1 class which implements it:


Notice how the IService1 interface is adorned with the ServiceContract attribute, and its methods are adorned with the OperationContract. That's how a WCF service exposes its functionality; a client will talk to the server through this interface. We'll see that in a moment. But first, let's take a look at how the service is configured. If you open the App.config file, you'll notice there is quite a bit of configuration in there:


The important things to notice at this stage are the base address and the endpoints. The base address shows the URL where the service is being hosted, and it's the same URL that clients will connect to. The endpoints, on the other hand, define how clients will connect to the service. In this case we have two endpoints: a basic HTTP binding which is used when a client connects to the base address, and which uses the IService1 interface as a contract. If you read more about WCF, you'll find these endpoints referred to as ABC (address, binding, contract). The other endpoint, mex, is a metadata exchange feature by which clients can discover what a server has to offer - that's how the WCF Test Client we used earlier manages to discover the functionality offered by our service.

If you are thinking that the configuration file looks complicated, that's understandable. Fortunately, however, you don't have to edit it by hand. If you right click on App.config, and select Edit WCF Configuration...


...then you can use this handy editor to set things up as you like:


When you press F5 and run the service, it's actually being hosted inside this WCF Service Host, that you can access from the System Tray:


The WCF Test Client, on the other hand, is being invoked via a command line argument. You can see this if you right click on the project, select Properties, and then select the Debug tab, you'll see the following:


Now, let's see how we can actually communicate with our service without using the WCF Test Client. First, copy the service URL (by default it's http://localhost:8733/Design_Time_Addresses/CsWcfMinimal/Service1/). Add a new project (Console Application) to the solution; this project will act as the client. Once that is done, right click on References and select Add Service Reference...:


Enter the service URL in the Address field and hit Go:


Notice the Namespace field is set to ServiceReference1 by default - we'll use this in a minute to identify the service from the client code. Press OK. This generates a bunch of code in the background that makes life easier for the client. In fact, let us now write some code in the client's Main() method to use the service. We start off by creating a client using the code generated by the service reference:

            ServiceReference1.IService1 service = new ServiceReference1.Service1Client();

If you click on Service1Client() and press F12 (Go to Definition), you'll be able to see the service reference code that was so conveniently generated for you:


...and if you open the client's App.config file, you'll see that the endpoint has been set up for us:


Let's get back to the code. All we have left to do is use the methods we want to use. Here's the full code for the client's Main() method:

        static void Main(string[] args)
        {
            ServiceReference1.IService1 service = new ServiceReference1.Service1Client();
            String response = service.GetData(5);
            Console.WriteLine(response);

            Console.ReadLine();
        }

Now, since the service is still your startup project, press Ctrl+F5 to run it without debugging. Once that is up and running, start the client either via the appropriate context menu option (see screenshot below), or by setting it up as the startup project and then pressing F5.


Rejoice, for it works:


Lovely! :) In this article, we explored the sample WCF Service Library project that is provided when you start a new project of that type. We saw how it is hosted in the WCF Service Host, and how we can interact with it via the WCF Test Client, which is launched by means of a command line argument. We also learned how to consume it from a client program, by first adding a service reference based on the service URL, and then using the handy autogenerated code to invoke the methods on the service.

We didn't actually make any funky server functionality though - we simply used that provided in the project. If you want to try your hand at writing your own service, Mahak Gupta's "A Simple Example of WCF Service" is a great article showing how you can make a simple WCF calculator service.

Saturday, November 16, 2013

C# EF: Setting Connection Strings at Runtime with Entity Framework 5.0, Database First, VS2012

Hi everyone! :)

This article deals with how to solve the problem of building and setting an Entity Framework connection string at runtime, based on a database-first approach (i.e. you have generated an Entity Data Model based on an existing database). You are expected to be familiar with ADO .NET and the Entity Framework. The first part of the article deals with setting up an Entity Data Model and simple interactions with it; this should appeal to all readers. The second part deals with the custom connection string issue, and will be helpful only to those who have actually run into that problem.

We're going to be using Visual Studio 2012, and Entity Framework 5.0. Start a new Console Application so that you can follow along.

Setting up the database


You can use whatever database you want, but in my case I'm using SQL Server Compact edition (SQLCE). If you're using something else and already have a database, you can just skip over this section.

Unlike many of the more popular databases such as SQL Server and MySQL, SQLCE is not a server and stores its data in a file with .sdf extension. This file can be queried and updated using regular SQL, but is not designed to handle things like concurrent users - something which isn't a problem in our case. Such file-based databases are called embedded databases.

If you have Visual Studio, then you most likely already have SQLCE installed. Look for it in "C:\Program Files (x86)\Microsoft SQL Server Compact Edition\v4.0". Under the Desktop or Private folders you'll find a file called System.Data.SqlServerCe.dll which we need to interact with SQLCE. Add a reference to it from your Console Application.

Now, we're going to create the database and a simple one-table schema. We'll use good old ADO.NET for that. We'll create the database only if it doesn't exist already. First, add the following usings at the top of Program.cs:

using System.IO;
using System.Data.SqlServerCe;

In Main(), add the following:

            String filename = "people.sdf";
            String connStr = "Data Source=" + filename;

Since SQLCE works with just a file, we can create a basic connection string using just the name of the file we're working with.

The following code actually creates the database and a single table called person.

            try
            {
                // create database if it doesn't exist already

                if (!File.Exists(filename))
                {
                    // create the actual database file

                    using (SqlCeEngine engine = new SqlCeEngine(connStr))
                    {
                        engine.CreateDatabase();
                    }

                    // create the table schema

                    using (SqlCeConnection conn = new SqlCeConnection(connStr))
                    {
                        conn.Open();

                        String sql = @"create table person(
                                       id int identity not null primary key,
                                       name nvarchar(20),
                                       surname nvarchar(30)
                                   );";

                        using (SqlCeCommand command = new SqlCeCommand())
                        {
                            command.CommandText = sql;
                            command.Connection = conn;
                            int result = command.ExecuteNonQuery();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }

We first use SqlCeEngine to create the database file. Then we use ADO .NET to create the person table. Each row will have an auto-incrementing id (primary key), as well as a name and surname. Note that SQLCE does not support the varchar type, so we have to use nvarchar (Unicode) instead.

If you now build and run the application, you should find a people.sdf file in the bin\Debug folder. We'll use that to create an Entity Data Model for the Entity Framework.

Creating the Data Model


Right click on the project and select Add -> New Item...:


From the Data category, select ADO.NET Entity Data Model. You can choose a name for it, or just leave it as the default Model1.edmx; it doesn't really matter.


Click The Add button. This brings up the Entity Data Model Wizard.


The "Generate from database" option is the default selection, so just click Next.


Hit the New Connection... button to bring up the Connection Properties window.


If SQL Server Compact 4.0 is not already selected as the Data source, click the Change... button and select it from the Change Data Source window:


Back in the Connection Properties window, click the Browse... button and locate the people.sdf file in your bin\Debug folder that we generated in the previous section. Leave the Password field empty, and click Test Connection. If all is well, you'll get a message box saying that the test succeeded.

Once you click OK, the Entity Data Model Wizard should become populated with a connection string and a default name for the model:


When you click Next, you'll get the following message:


Just click Yes and get on with it. In the next step, import the person table into your model by ticking the checkbox next to it:


Click Finish. The files for your model are added to the project. You may also get the following warning:


You don't have to worry about it. Just click OK. If you click Cancel instead, you won't have the necessary autogenerated code that you need for this project.

Interacting with the database using the Entity Framework


After the database-creation code from the first section, and before the end of the try scope, add the following code:

                // interact with the database

                using (peopleEntities db = new peopleEntities())
                {
                    db.people.Add(new person() { name = "John", surname = "Smith" });
                    db.SaveChanges();

                    foreach (person p in db.people)
                    {
                        Console.WriteLine("{0} {1} {2}", p.id, p.name, p.surname);
                    }
                }

Here, we create an instance of our entity context (peopleEntities) and then use it to interact with the database. We add a new row to the person table, and then commit the change via db.SaveChanges(). Finally, We retrieve all rows from the table and display them.

Also, add the following at the end of the Main() method so that we can see the output:

            Console.ReadLine();

Run the program by pressing F5. The output shows that a row was indeed added:


The Entity Framework knows where to find the database because it has a connection string in the App.config file:

  <connectionStrings>
    <add name="peopleEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlServerCe.4.0;provider connection string=&quot;data source=|DataDirectory|\people.sdf&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>

This might be good enough in some situations, but other times, we might want to build such connection string in code and ask the Entity Framework to work with it. A reason for this might be because the connection string contains a password, and you want to obtain it from an encrypted source. The following two sections illustrate how this is done.

Building a raw Entity Framework connection string


Let's start out by commenting out the connection string in the App.config file:

  <connectionStrings>
    <!--
    <add name="peopleEntities" connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlServerCe.4.0;provider connection string=&quot;data source=|DataDirectory|\people.sdf&quot;" providerName="System.Data.EntityClient" />
    -->
  </connectionStrings>

If you try running the program now, you'll get a nice exception.

Now, what we want to do is add the connection string into our code and pass it to the entity context (the peopleEntities). So before our Entity Framework code (which starts with using (peopleEntities...), add the following:

                String entityConnStr = @"metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlServerCe.4.0;provider connection string=&quot;data source=|DataDirectory|\people.sdf&quot;";

If you now try to pass this connection string to the peopleEntities constructor, you'll realise that you can't. You can see why if you expand Model1.edmx and then Model1.Context.tt in Solution Explorer, and finally open the Model1.Context.cs file:


The peopleEntities class has only a parameterless constructor, and it calls the constructor of DbContext with the connection string name defined in App.config. The DbContext constructor may accept a connection string instead, but we have no way of passing it through peopleEntities directly.

While you could add another constructor to peopleEntities, it is never a good idea to modify autogenerated code. If you regenerate the model, any code you add would be lost. Fortunately, however, peopleEntities is a partial class, which means we can add implementation to it in a separate file (see this question and this other question on Stack Overflow).

Add a new class and name it peopleEntities. Add the following at the top:

using System.Data.Entity;

Implement the class as follows:

    public partial class peopleEntities : DbContext
    {
        public peopleEntities(String connectionString)
            : base(connectionString)
        {

        }
    }

We can now modify our instantiation of peopleEntities to use our connection string as defined in code:

using (peopleEntities db = new peopleEntities(entityConnStr))

Since we are using a partial class defined in a separate file, any changes to the model will cause the autogenerated peopleEntities to be recreated, but will not touch the code we added in peopleEntities.cs.

When we run the program, we now get a very nice exception (though different from what we got right after commenting out the connection string in App.config):


Apparently this happens because of the &quot; values, which are necessary in XML files but cause problems when supplied in a String literal in code. We can replace them with single quotes instead, as follows:

                String entityConnStr = @"metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;provider=System.Data.SqlServerCe.4.0;provider connection string='data source=|DataDirectory|\people.sdf'";

If we run the program now, it works fine, and a new row is added and retrieved:


Using EntityConnectionStringBuilder


You'll notice that the connection string we've been using is made up of three parts: metadata, provider, and the provider connection string that we normally use with ADO.NET.

We can use a class called EntityConnectionStringBuilder to provide these values separately and build a connection string. Using this approach avoids the problem with quotes illustrated at the end of the previous section.

First, remove or comment out the entityConnStr variable we have been using so far.

Then add the following near the top of Program.cs:

using System.Data.EntityClient;

Finally, add the following code instead of the connection string code we just removed:

                EntityConnectionStringBuilder csb = new EntityConnectionStringBuilder();
                csb.Metadata = "res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl";
                csb.Provider = "System.Data.SqlServerCe.4.0";
                csb.ProviderConnectionString = "data source=people.sdf";
                String entityConnStr = csb.ToString();

When you run the program, it should work just as well:


Summary


This article covered quite a bit of ground:
  • We first used the SqlceEngine and ADO .NET to create a SQL Server Compact database.
  • When then created an Entity Data Model for this database.
  • We added some code to add rows and retrieve data using the Entity Framework.
  • We provided the Entity Framework with a raw connection string in code. To do this, we used a partial class to add a new constructor to the entity context class that can pass the connection string to the parent DbContext. We also observed a problem with using &quot; in the connection string, and solved it by using single quotes instead.
  • We used EntityConnectionStringBuilder to build a connection string from its constituent parts, and in doing so completely avoided the &quot; problem.
I hope you found this useful. Feel free to leave any feedback in the comments below. Check back for more articles! :)

Wednesday, October 16, 2013

C# WPF: Filter ListBox As You Type, Using MVVM

Hellooooo! :)

In this article, I'm going to show how you can set things up so that typing in a WPF TextBox instantly filters the items in a ListBox, within an MVVM setting.

This is an advanced article, and to understand it, you'll need to know your C#, WPF and data binding as well as a little touch of MVVM and LINQ.

So, let's get to it. Create a new WPF Application in SharpDeveloper or whichever IDE you prefer.

In your Window's XAML view, replace the default Grid element with the following:

     <DockPanel>
        <TextBox DockPanel.Dock="Top" />
        <ListBox />
    </DockPanel>

Simple enough? The TextBox is where you type your text, and the ListBox will show a list of items.

Let us now create a ViewModel for our Window. Create a new class (right click on project, Add -> New Item...) and name it MainVM. At the beginning of the MainVM class, add the following member variables:

        private List<String> names;
        private String filter;

Right after that, add the following properties to expose them:

        public List<String> FilteredNames
        {
            get
            {
                return (from name in names where name.Contains(filter) select name).ToList<String>();
            }
        }

        public String Filter
        {
            get
            {
                return this.filter;
            }
            set
            {
                this.filter = value;
            }
        }

Notice how we aren't exposing our names variable as it is; we are returning only those names that contain the filter text (which will be set via the TextBox later). You might prefer to use StartsWith() instead of Contains() - that's up to you.

If you're using SharpDevelop, don't forget to add the following at the top for the Lists and the LINQ:

using System.Collections.Generic;
using System.Linq;

In the MainVM() constructor, let's initialise our variables:

            this.names = new List<string>() { "Jerry""Joey""Roger""Raymond""Jessica""Mario""Jonathan" };
            this.filter = "";

In your Window's codebehind (Window1.xaml.cs if you're in SharpDevelop, or MainWindow.xaml.cs if you're using Visual Studio), set up the viewmodel as the datacontext for the window by adding this line at the end of the constructor:

             this.DataContext = new MainVM();

Back in the window's XAML, we can now change our controls and add bindings in order to get our list to show:

        <TextBox DockPanel.Dock="Top" Text="{Binding Path=Filter}" />
        <ListBox ItemsSource="{Binding Path=FilteredNames, Mode=OneWay}" />

Here's the result:


Great, the list is showing. But as you can see, the list isn't being filtered by the text in the TextBox. To get this working, there are two things we need to do. First, we need to update the TextBox's binding to use an UpdateSourceTrigger as follows:

<TextBox DockPanel.Dock="Top" Text="{Binding Path=Filter, UpdateSourceTrigger=PropertyChanged}" />

This causes the underlying property to be updated with every keypress, rather than when the TextBox loses focus. This will give the idea that the list is being updated in real-time.

The second thing we need to do is actually let the WPF binding know that FilteredNames needs to be updated when the Filter property is set. WPF allows us to do this by implementing INotifyPropertyChanged. We can actually implement INotifyPropertyChanged ourselves, or use the functionality by means of an MVVM library. Let's see how both these methods work.

Method 1: Implement INotifyPropertyChanged

Add the following code at the end of your MainVM class:

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChanged(thisnew PropertyChangedEventArgs(propertyName));
        }

Then make your MainVM class implement INotifyPropertyChanged:

     public class MainVM : INotifyPropertyChanged

Change your Filter property's set accessor as follows to let the binding know that it has to refresh the FilteredNames:

            set
            {
                this.filter = value;
                NotifyPropertyChanged("FilteredNames");
            }

Finally, add the following at the top so that the compiler knows what an INotifyPropertyChanged is:

using System.ComponentModel;

Hit F5 and try it out to see that it works:

Method 2: Use MVVM Light

There's this library called MVVM Light written by a dude called Laurent Bugnion that packages some stuff we normally need for MVVM. It's not comfortable to have to keep an event in all our viewmodels, so instead we can inherit from a common base class.

First, download and install MVVM Light to some local folder. Then, locate Mvvm Light Toolkit\Binaries\WPF4\GalaSoft.MvvmLight.WPF4.dll and add a reference to it (right click project, Add Reference, then select the .NET Assembly Browser tab and locate the .dll via the Browse... button.

At the top of your MainVM.cs file, put the following to allow you to make use of this library:

using GalaSoft.MvvmLight;

Next, let the MainVM class inherit from ViewModelBase, a common base class for viewmodels available in MVVM Light:

     public class MainVM : ViewModelBase

Now, you only need to update your Filter property's set accessor as follows in order to make things work:

            set
            {
                this.filter = value;
                RaisePropertyChanged("FilteredNames");
            }

RaisePropertyChanged() is a method inherited from ViewModelBase, and does pretty much the same thing as NotifyPropertyChanged() from Method 1 above.

Press F5 to give it a shot:


Summary

In this article we saw how easy it is to filter a ListBox as you type into a TextBox. We exploited data binding in an MVVM manner, and used INotifyPropertyChanged (either directly or through MVVM Light) to reflect changes in the ListBox.

This is not necessarily the most efficient way of doing this, but it's simple to implement and is pretty fast even if you have several hundred items in your ListBox.

I hope you found this useful, and check back for more articles! :)

Wednesday, October 9, 2013

C# WPF: Control Panel using MVVM

Hi all! :)

In this article I'm going to show how you can implement a simple control panel in WPF using the MVVM design pattern. A control panel is a special case of a master/detail layout, where options are usually few and predefined, so you don't need to load any detail dynamically as options are selected.

This is an advanced article, so read on only if you have a fair grasp of the following: C#, WPF, data binding, and MVVM. I'm going to be using Visual Studio 2013 RC for the examples (just to try it out, really), but you should be able to use SharpDevelop or any version of Visual Studio from 2008 onwards.

Before we begin, a brief note on MVVM is in order. MVVM (Model-View-ViewModel) is an approach that promotes using data binding and commands over events. What we're going to do in this article can easily be done using the event-driven model (a la Windows Forms), but I'm writing this mainly for those who are trying to adopt the MVVM approach and who (like me) had a hard time grasping how it works.

So let's start off by adding a new C# WPF Application:


The New Project window above is an example of a master/detail layout. As you click on items in the treeview on the left (e.g. Windows or Web), the list of items in the middle changes accordingly. The treeview is a master view, while the area in the middle is the detail view.

For starters, in the XAML view, we can do away with the default <Grid> and set up our (not yet functional) master/detail layout as follows:

    <DockPanel>
        <ListBox Width="150" DockPanel.Dock="Left" />
        <ContentControl />
    </DockPanel>

Here's a screenshot of what it looks like in Visual Studio:


Isn't that simple? We use a ListBox for the master view, and move it to the left thanks to the DockPanel that contains it. The detail view is a ContentControl, which is a container we can use to hold user controls.

Next, we need a ViewModel for our MainWindow. Add a new class (right click on project, select Add -> New Item...) and call it MainVM. Make the class public, and set up some hardcoded values for the options that will appear in the master view:

    public class MainVM
    {
        private List<String> operations;

        public List<String> Operations
        {
            get
            {
                return this.operations;
            }
        }

        public MainVM()
        {
            this.operations = new List<String>() { "Add User", "List Users" };
        }
    }

In MainWindow's codebehind (i.e. MainWindow.xaml.cs), set the DataContext to an instance of MainVM in the constructor. This is important because when we do our data binding, the properties are always relative to the DataContext.

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = new MainVM();
        }
    }

Back in our XAML view for MainWindow.xaml, we can now see that our binding works by adding an ItemsSource to the master ListBox:

<ListBox Width="150" DockPanel.Dock="Left" ItemsSource="{Binding Path=Operations}" />

Note how we're binding to the Operations property, and this is interpreted as belonging to the DataContext, which is a MainVM in this case. Sure enough, pressing F5 to debug the project shows that the ListBox is filled with the values we hardcoded earlier:


Right, now to actually fill in the detail view depending on what master option is selected. We'll first create each detail as a separate UserControl - this will allow us to easily plug them into our window.

Add your first UserControl (right click on project, Add -> New Item... and select "User Control (WPF)" - don't confuse it for the "User Control" which is actually a Windows Forms thing) and name it AddUserControl.xaml. Instead of implementing functionality to add or list users (which isn't the point of this article, we'll just stick some static content instead. Put this instead of the default grid:

    <StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock VerticalAlignment="Center">Name:</TextBlock>
            <TextBox Width="100" Margin="5 5 5 5" />
        </StackPanel>
    </StackPanel>

Create another UserControl, ListUsersControl.xaml, and replace the grid with the following:

    <StackPanel>
        <TextBlock>John Doe</TextBlock>
        <TextBlock>Mary Jane</TextBlock>
        <TextBlock>John Smith</TextBlock>
        <TextBlock>Chuck Norris</TextBlock>
    </StackPanel>

Now, we need to map each operation name (e.g. "Add User") to the corresponding UserControl. One option is to use a Tuple, but a better solution is to create a dedicated class. Add a new class named Operation and implement it like this:

    public class Operation
    {
        public String Name { get; set; }
        public UserControl Control { get; set; }

        public Operation(String name, UserControl control)
        {
            this.Name = name;
            this.Control = control;
        }
    }

You will also need to add the following near the top for UserControl to make sense:

using System.Windows.Controls;

Back in MainVM, replace the whole (String-based) class with the following (Operation-based):

    public class MainVM
    {
        private List<Operation> operations;

        public List<Operation> Operations
        {
            get
            {
                return this.operations;
            }
        }

        public MainVM()
        {
            this.operations = new List<Operation>();
            this.operations.Add(new Operation("Add User", new AddUserControl()));
            this.operations.Add(new Operation("List Users", new ListUsersControl()));
        }
    }

All we have left to do is wire up the bindings on the XAML view of MainWindow.xaml. First, we need to change our ListBox as follows:

        <ListBox Name="MasterView" Width="150" DockPanel.Dock="Left"
                 ItemsSource="{Binding Path=Operations}" DisplayMemberPath="Name" />

I've added two things here. First, I added a name to the ListBox so that I can refer to it from my ContentControl. I also added a DisplayMemberPath. This tells the ListBox that for each Operation item, it needs to show the Name property. If you leave that out, it will just display Operation.ToString() by default.

Next, we bind our ContentControl's Content property as follows:

        <ContentControl Content="{Binding ElementName=MasterView, Path=SelectedItem.Control}" />

The binding refers to the control named MasterView (i.e. our ListBox), and we hook it up with the ListBox's SelectedItem property. Since the SelectedItem is actually an Operation, we get the UserControl associated with that Operation (via the Control property). Setting the Path to SelectedItem.Control does the trick.

That's it! Press F5 to test the application. When you click on "Add User", you get the correct UserControl:


...and clicking on "List Users" works just as well:


Woohoo! :) We managed to implement an MVVM master/detail control panel with just three lines of XAML (two controls, really) and some data binding magic.

As you have seen, the particular nature of a control panel makes an MVVM implementation particularly easy, because each detail view can reside in memory. This does not apply to all master/detail layouts though: if the master list is really long, it may be a better idea to load detail views lazily on demand. That could be the topic for a future article. Stay tuned! :)