Archives for : MVVM

Part One: Starting with MVVM
Part Two: The MVVM solution structure and basic framework
Part Three: Base Classes
Part 4: Sampler View, View Model and Model
Part 5: Running and working with the TPL samples
Part 6: Parallel.For Sample

In the last post we discussed where using a Parallel.For isn’t effective. The answer is fairly straightforward, Parallel.For (and by extension Parallel.ForEach) isn’t effective when you can’t give it enough work. Spinning off threads from the Thread Pool has its own overhead and if you can’t give the threads enough work it doesn’t make sense. Today we are going to discuss using Parallel.For effectively and what you have to change to convert from using a for to a Parallel.For.

GreyScaleSample.Run()

public override void Run(System.Drawing.Bitmap bmp = null, Action<string> UpdateLog = null)
{
	if(bmp == null)
		throw new InvalidOperationException("Bitmap must be defined.");
	
	Stopwatch s = new Stopwatch();
	s.Start();

	System.Drawing.Imaging.BitmapData bmData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
	int stride = bmData.Stride;
	System.IntPtr Scan0 = bmData.Scan0;
	unsafe
	{
		byte* p = (byte*)(void*)Scan0;
		byte red, green, blue;

		for (int y = 0; y < bmp.Height; ++y)
		{
			for (int x = 0; x < bmp.Width; ++x)
			{
				blue = p[0];
				green = p[1];
				red = p[2];

				p[0] = p[1] = p[2] = (byte)(.299 * red
					+ .587 * green
					+ .114 * blue);

				p += 3;
			}
		}
	}
	bmp.UnlockBits(bmData);

	s.Stop();
	RunTime = s.Elapsed;
}

In the above sample we iterate over the image, starting at the first row (which is Scan0 but is redefined as “p” for pixel just for clarity of the code) and then iterating over the columns in that row. A bitmap is made up of a long byte array where every three bytes is the blue, green and red colors (which seems opposite of what we expect) that make up a pixel. The width of the row is defined by the stride but this is really the same thing as the width of the bitmap. We get the RGB values and reset the pixels to the gray value of the color. We then increment the pixel by 3 (since it represents the 3 bytes of RGB) and move on to the next one.

There is some messy pointer stuff here but all-in-all the code should be clear in what we’re doing.

GreyScaleParallelSample.Run()

public override void Run(System.Drawing.Bitmap bmp = null, Action<string> UpdateLog = null)
{
	if(bmp == null)
		throw new InvalidOperationException("Bitmap must be defined.");
	
	Stopwatch s = new Stopwatch();
	s.Start();

	System.Drawing.Imaging.BitmapData bmData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
	int stride = bmData.Stride;
	System.IntPtr Scan0 = bmData.Scan0;
	unsafe
	{
		byte* start = (byte*)(void*)Scan0;

		int height = bmp.Height;
		int width = bmp.Width;

		Parallel.For(0, height, y =>
		{
			byte* p = start + (y * stride);
			for (int x = 0; x < width; ++x)
			{
				byte blue = p[0];
				byte green = p[1];
				byte red = p[2];

				p[0] = p[1] = p[2] = (byte)(.299 * red
					+ .587 * green
					+ .114 * blue);

				p += 3;
			}
		});
	}
	bmp.UnlockBits(bmData);

	s.Stop();
	RunTime = s.Elapsed;
}

In the Parallel.For sample things are a bit different and these differences are important.

First off we have to remember that each loop of the Parallel.For is a seperate thread. As such there can’t be any variables that will be modified that are common between the loops(at least not without using Interlocked but that’s a different post). Imagine if the pointer to the pixel was common between the threads like it is in the first sample. If the thread pool spawns off 10 threads they would all have that same initial value for the pixel. This is problematic and as such the code is changed here to recalculate the pixel at the start of the row at the beginning of each iteration.

Second we move the declaration of the bytes for blue, green and red into the inner loop. This was only done originally merely for more evident code is isn’t really a functional change.

GreyScaleDoubleParallelSample.Run()

public override void Run(System.Drawing.Bitmap bmp = null, Action<string> UpdateLog = null)
{
	if(bmp == null)
		throw new InvalidOperationException("Bitmap must be defined.");
	
	Stopwatch s = new Stopwatch();
	s.Start();

	System.Drawing.Imaging.BitmapData bmData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
	int stride = bmData.Stride;
	System.IntPtr Scan0 = bmData.Scan0;
	unsafe
	{
		byte* start = (byte*)(void*)Scan0;

		int height = bmp.Height;
		int width = bmp.Width;

		Parallel.For(0, height, y =>
		{
			Parallel.For(0, width, x =>
			{
				byte* p = (start + (y * stride)) + (x * 3);
				byte blue = p[0];
				byte green = p[1];
				byte red = p[2];

				p[0] = p[1] = p[2] = (byte)(.299 * red
					+ .587 * green
					+ .114 * blue);
			});
		});
	}
	bmp.UnlockBits(bmData);

	s.Stop();
	RunTime = s.Elapsed;
}

Finally we have a sample that works pretty much like LineParallelSample.Run() (except here we’re setting the pixel to gray instead of black). The code spins off a thread for each row and then within that thread spins off a thread for setting each pixel. Again, we have to move the pixel declaration internal to the inner Parallel.For since this value will be modified and must be unique to each thread.

Running the samples you will get results similar to:

Reseting Image
Starting Grey Scale Sample
Completed Grey Scale Sample
Grey Scale Sample ran in 00:00:00.0268376

Reseting Image
Starting Grey Scale Parallel Sample
Completed Grey Scale Parallel Sample
Grey Scale Parallel Sample ran in 00:00:00.0020127

Reseting Image
Starting Grey Scale Double Parallel Sample
Completed Grey Scale Double Parallel Sample
Grey Scale Double Parallel Sample ran in 00:00:00.0037469

This is the results run with the included image of my son which is 93KB, a small image.

I have another image I test against which is ~8MB. This results in:

Reseting Image
Starting Grey Scale Sample
Completed Grey Scale Sample
Grey Scale Sample ran in 00:00:02.2118701

Reseting Image
Starting Grey Scale Parallel Sample
Completed Grey Scale Parallel Sample
Grey Scale Parallel Sample ran in 00:00:00.1626661

Reseting Image
Starting Grey Scale Double Parallel Sample
Completed Grey Scale Double Parallel Sample
Grey Scale Double Parallel Sample ran in 00:00:00.2232706

You can see by these results the Parallel.For sample runs nearly 14 times faster. This is major. Now looking at the Parallel.For sample and the Double Parallel.For sample the results are actually detrimental in this case. Running the sample, as with the ParallelLine sample you don’t get any benefit to adding the interal Parallel.For just to set a pixel. Again, depending on how you use the Parallel.For, you may have an example where you can give the internal threads enough work that it may be beneficial, just not here.

Up next I’m going to add two new models showing Matrix multiplication. This sample is actually similar to the GreyScale samples here but I added it to the original source because we do a lot of matrix operations and I wanted to so a clear, real-world example that was directly applicable to the work we do.

Thanks,
Brian

The Task Parallel Library Sampler – Part 6: Parallel.For Sample

Part One: Starting with MVVM
Part Two: The MVVM solution structure and basic framework
Part Three: Base Classes
Part 4: Sampler View, View Model and Model
Part 5: Running and working with the TPL samples

In the solution directory Models, you will find the LineSample and LineParallelSample models. These are fairly straight forward samples.

LineSample.Run()

public override void Run(System.Drawing.Bitmap bmp = null, Action<string> UpdateLog = null)
{
	if(bmp == null)
		throw new InvalidOperationException("Bitmap must be defined.");
	
	double X1 = 0, Y1 = 0;
	double X2 = bmp.Width - 1, Y2 = bmp.Height - 1;

	Stopwatch s = new Stopwatch();
	s.Start();

	double slope = (Y2 - Y1) / (X2 - X1);
	double beta = Y1 - (slope * X1);

	System.Drawing.Imaging.BitmapData bmData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
	int stride = bmData.Stride;
	System.IntPtr Scan0 = bmData.Scan0;
	unsafe
	{
		byte* startPos = (byte*)(void*)Scan0;
		for (int x = (int)X1; x <= X2; x++)
		{
			GeneralMathOperations.DrawPixelByPointSlope(slope, beta, stride, startPos, x);
		}
	}
	bmp.UnlockBits(bmData);

	s.Stop();
	RunTime = s.Elapsed;
}

We start a stop watch. Then calculate our slope and beta for the point slope formula. Since we want to use the image so that we can compare the same operation between the two samples we have to use some pointer operations that makes all this a lot easier. Then we run through a for loop that just moves from the top left to the bottom right and sets each pixel in a line to black. We then unlock the image, stop the stop watch and then set our RunTime to the time it took for the loop to run.

LineParallelSample.Run()

public override void Run(System.Drawing.Bitmap bmp = null, Action UpdateLog = null)
{
	if(bmp == null)
		throw new InvalidOperationException("Bitmap must be defined.");

	double X1 = 0, Y1 = 0;
	double X2 = bmp.Width - 1, Y2 = bmp.Height - 1;

	Stopwatch s = new Stopwatch();
	s.Start();

	double slope = (Y2 - Y1) / (X2 - X1);
	double beta = Y1 - (slope * X1);

	System.Drawing.Imaging.BitmapData bmData = bmp.LockBits(new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
	int stride = bmData.Stride;
	System.IntPtr Scan0 = bmData.Scan0;
	unsafe
	{
		byte* startPos = (byte*)(void*)Scan0;
		Parallel.For((int)X1, (int)X2 + 1, x =>
		{
			GeneralMathOperations.DrawPixelByPointSlope(slope, beta, stride, startPos, x);
		});
	}
	bmp.UnlockBits(bmData);

	s.Stop();
	RunTime = s.Elapsed;
}

In LineParallelSample the only difference is the Parallel.For at line 21. Parallel.For’s first parameter is where to start, the second parameter is where to end and the third parameter is the body of the action. It’s important to remember that the “from” is inclusive meaning it includes the value and the “to” is exclusive meaning it goes to this amount doesn’t include it. That is why in LineSample we run to x <= X2 but in LineParallelSample we run to X2 + 1 which ends up being x < X2 + 1. We want to make sure we include that last pixel. What is really interesting is the results. Running the samples a few times with the included image (one of my son) you will see similar results such as these:

Reseting Image
Starting Line Sample
Completed Line Sample
Line Sample ran in 00:00:00.0009594

Reseting Image
Starting Parallel Line Sample
Completed Parallel Line Sample
Parallel Line Sample ran in 00:00:00.0009714

Changing to a much larger image you end up with similar results.
So, what is so exciting? Well, the Parallel.For doesn’t help. But, but… well, that can’t be right.
Ah, however, it is right. When using the Parallel.For and Parallel.ForEach you have to remember that there is a bit of overhead when managing the threads, spinning up the threads and context switching. I wrote this sample to explicitly show that the TPL isn’t a magic bullet. In order to maximize your use of the TPL you have to give each thread enough work. In this sample all it is doing is drawing a single point. This is pretty simple to do and the overhead of the threading doesn’t justify using the TPL in this instance.

In the next post we’ll go over the three grey scale samples where using a Parallel.For and Parallel.ForEach make a huge difference.

Thanks,
Brian

Part One: Starting with MVVM
Part Two: The MVVM solution structure and basic framework
Part Three: Base Classes
Part 4: Sampler View, View Model and Model

There is a new version of the solution available.

Finally, before getting in the actual TPL samples there is one last thing to cover. How do we run the samples? Well, as previously discussed the Submit button in SamplerView is bound to the SamplerViewModel.Submit().

public async void Submit()
{
	CurrentState = "Running";
	await Sampler.RunSamples();
	CurrentState = "Completed";
}

Using async/await, the model then runs the samples in the model via Sampler.RunSamples(). The async/await is critical here so the UI isn’t locked while the samples are run.

Here is Sampler.RunSamples()

public async Task RunSamples()
{
	await Task.Run(() =>
	{
		System.Drawing.Bitmap bmp = null;
		foreach (var sample in Samples)
		{
			if(!sample.IsEnabled)
				continue;

			if (sample.ImageRequired)
			{
				UpdateResults("Reseting Image");
				ResetDestinationImage();
				bmp = GetBitmapFromDestinationImage();
			}
			UpdateResults("Starting " + sample.SampleName);
			sample.Run(bmp, UpdateResults);
			UpdateResults("Completed " + sample.SampleName);
			UpdateResults(sample.SampleName + " ran in " + sample.RunTime.ToString() + Environment.NewLine);
		}

		if (bmp != null)
		{
			SetDestinationImageFromBitmap(bmp);
		}
	});
}

private void UpdateResults(string result)
{
	Results += result + Environment.NewLine;
}

The async keyword in the method declaration is what allows the ViewModel to run this method asynchronously. In order to define a method as asynchronous, it must contain an await call. To do this I call Task.Run with an await so the framework knows to spin off a thread and wait for it to return. There’s a bit more than that but I’ll discuss async/await in more detail in the TPL sample for it.

The really interesting thing here is passing the “UpdateResults” method into the run method of the sample model. You’ll recall in the “base classes” post that the abstract sample model takes a bitmap and Action<string>. The SamplerView has a text box that is bound to the Results property of our Sampler model. This way we can get real-time updating from the samples as they run. Since their running in their own thread (via the await Task.Run) it won’t block the UI and the binding takes care of invoking the update to the text so that it happens on the main thread without having to worry about updating the UI on the wrong thread.

And that’s it. It’s pretty simple. Next up I’ll go over the first three samples included in the solution that demonstrate when to and when not to use Parallel.For (and by extension Parallel.ForEach).

Thanks,
Brian

Part One: Starting with MVVM
Part Two: The MVVM solution structure and basic framework
Part Three: Base Classes

I want to go over the main view (SamplerView), view model (SamplerViewModel) and model (Sampler) classes next. I’ve gone over the ItemsControl that populates the TPL samples but I wanted to cover the other MVVM aspects as well as what isn’t MVVM here. There are two other primary MVVM components to this. One is the image chooser, the other is the log that is populated as the samples run. Remember that the DataContext of the SamplerView is a SamplerViewModel. This means that any binding is done on this object.

The Image Chooser:
Near the top of SamplerView is a TextBox that contains the path to the image that is used when a sample needs an image. Next to that is a Button that opens an OpenFileDialog to choose an image.

<Border Grid.Row="0" Grid.ColumnSpan="2" >
	<Grid>
		<Grid.ColumnDefinitions>
			<ColumnDefinition Width="*" />
			<ColumnDefinition Width="Auto" />
		</Grid.ColumnDefinitions>
		<TextBox Grid.Column="0" Grid.Row="0" VerticalAlignment="Bottom" Text="{Binding Sampler.ImagePath, Mode=TwoWay}" />
		<Button Grid.Column="1" Content="Change Image">
			<i:Interaction.Triggers>
				<i:EventTrigger EventName="Click">
					<ei:CallMethodAction TargetObject="{Binding}" MethodName="ChangeImagePath" />
				</i:EventTrigger>
			</i:Interaction.Triggers>
		</Button>
	</Grid>
</Border>

Like the sample view model, the Sampler model is directly exposed in the SamplerViewModel. As such the binding of the TextBox is to the ImagePath property of the Sampler model. The mode is set to two-way so that if a user wishes they could just paste a path into the TextBox directly. What’s new here is the Interaction.Trigger. This allows you to define a method to call for the EventTrigger, in this case the “Click” event.

Here is the SamplerViewModel.ChangeImagePath():

public void ChangeImagePath()
{
	OpenFileDialog ofd = new OpenFileDialog();
	ofd.CheckFileExists = true;
	ofd.CheckPathExists = true;
	ofd.Multiselect = false;
	if (ofd.ShowDialog() == true)
	{
		Sampler.ImagePath = ofd.FileName;
	}
}

This has the standard OpenFileDialog code but when the user chooses a file, that path is set to the model’s ImagePath. Since the ImagePath is bound to the TextBox in the view, setting the path will update the TextBox to the correct path. Setting this image path has the side-effect that the images within the application get updated.

Sampler.ImagePath:

string imagePath = "";
public string ImagePath
{
	get { return this.imagePath; }
	set
	{
		if (this.imagePath != value)
		{
			this.ValidateProperty("ImagePath", value);
			this.imagePath = value;
			this.RaisePropertyChanged("ImagePath");
			SetImageSources();
		}
	}
}

There are three important aspects to this.

One is the ValidateProperty:

protected override void ValidateProperty(string propertyName, object value)
{
	if (propertyName == "ImagePath")
	{
		var errors = new List();
		string path = value as string;
		if (string.IsNullOrEmpty(path))
		{
			errors.Add("Image path must be set.");
		}
		else if (!File.Exists(path))
		{
			errors.Add("The image indicated does not exist.");
		}

		this.ErrorsContainer.SetErrors(propertyName, errors);
	}
	else
	{
		base.ValidateProperty(propertyName, value);
	}
}

When ValidateProperty is called it verifies that there is an image path and that the file exists. If either of these are not true than an error is added to the error container in the base domain object that allows the application to provide feedback to the user that there is an error.

Two is the RaisePropertyChanged event. This is pretty standard when binding as this notifies any observers that are bound to this object that the property has changed, that way they can change the value as they need to.

Finally is the Sampler.SetImageSources():

private void SetImageSources()
{
	if(!File.Exists(ImagePath))
		return;

	BitmapImage sourceBitmapImage = new BitmapImage();
	sourceBitmapImage.BeginInit();
	sourceBitmapImage.UriSource = new Uri(ImagePath);
	sourceBitmapImage.EndInit();
	SourceImage = sourceBitmapImage;

	ResetDestinationImage();
}

public void ResetDestinationImage()
{
	if(!File.Exists(ImagePath))
		return;

	if (Application.Current.Dispatcher.Thread != Thread.CurrentThread)
	{ 
		Application.Current.Dispatcher.Invoke(() => 
		{
			ResetDestinationImage();
		});
		return;
	}
	BitmapImage destBitmapImage = new BitmapImage();
	destBitmapImage.BeginInit();
	destBitmapImage.UriSource = new Uri(ImagePath);
	destBitmapImage.EndInit();
	DestinationImage = destBitmapImage;
}

This is the side-effect of updating the image path. It causes the two images in the view, which are bound to the SourceImage and DestinationImage, to get updated. Since the ValidateProperty takes care of providing the user with the feedback that a file may not exists we don’t have to do any error handling beyond just making sure the image exists.

The last MVVM component of interest is the Submit button.

<Button  Content="Submit" Height="23" IsEnabled="{Binding CanSubmit}" Margin="5"  HorizontalAlignment="Right" Width="75">
	<i:Interaction.Triggers>
		<i:EventTrigger EventName="Click">
			<ei:CallMethodAction TargetObject="{Binding}" MethodName="Submit"/>
		</i:EventTrigger>
	</i:Interaction.Triggers>
</Button>

Like the ChangeImage button above, this is bound to a method in the SamplerModelView.

SamplerModelView.Submit()

public async void Submit()
{
	CurrentState = "Running";
	await Sampler.RunSamples();
	CurrentState = "Completed";
}

This method is run with async/await so the UI isn’t locked when the samples are run. I’ll discuss async/await in detail later in this series. It just runs the method to run the samples in the Sampler model. In the next post I’ll go more into depth on running samples.

Finally I want to discuss what is not MVVM here. The images are defined in SamplerView as:

<Border MinHeight="100" Grid.Row="1" Grid.Column="0" BorderBrush="Black" BorderThickness="2">
	<Image ClipToBounds="True" Source="{Binding Sampler.SourceImage}">
		<Image.RenderTransform>
			<TransformGroup>
				<ScaleTransform x:Name="imgScaleTransformSource" ScaleX="1" ScaleY="1" />
				<TranslateTransform x:Name="imgTranslateTransformSource"  />
			</TransformGroup>
		</Image.RenderTransform>
	</Image>
</Border>
<Border MinHeight="100" Grid.Row="1" Grid.Column="1" BorderBrush="Black" BorderThickness="2">
	<Image ClipToBounds="True" Source="{Binding Sampler.DestinationImage}">
		<Image.RenderTransform>
			<TransformGroup>
				<ScaleTransform x:Name="imgScaleTransformDest" ScaleX="1" ScaleY="1" />
				<TranslateTransform x:Name="imgTranslateTransformDest"  />
			</TransformGroup>
		</Image.RenderTransform>
	</Image>
</Border>
<StackPanel Grid.Row="1" Grid.Column="1" HorizontalAlignment="Right" VerticalAlignment="Bottom">
	<RepeatButton x:Name="btnPlus" Width="25" Margin="5" Click="btnPlus_Click">+</RepeatButton>
	<RepeatButton x:Name="btnMinus" Width="25" Margin="5" Click="btnMinus_Click">-</RepeatButton>
	<RepeatButton x:Name="btnUp" Width="25" Margin="5" Click="btnUp_Click">?</RepeatButton>
	<StackPanel Orientation="Horizontal">
		<RepeatButton x:Name="btnLeft" Width="25" Margin="5" Click="btnLeft_Click">?</RepeatButton>
		<RepeatButton x:Name="btnRight" Width="25" Margin="5" Click="btnRight_Click">?</RepeatButton>
	</StackPanel>
	<RepeatButton x:Name="btnDown" Width="25" Margin="5" Click="btnDown_Click">?</RepeatButton>
</StackPanel>

These are bound to the SourceImage and DestinationImage properties of the Sampler model, standard MVVM stuff. What’s not MVVM are the repeat buttons that move/zoom the images around. I opted for this approach, using regular code-behind, because the moving/zooming of the images doesn’t really have anything to do with our models. It doesn’t have anything to do with running samples or any data associated with the samples. Because of this it didn’t make sense to bind the buttons that move the images using an event trigger to methods in the SamplerViewModel. In this case it would have convoluted our ModelViews just for the sake of using MVVM. This is what I meant in the first post where I referred to this as a composite application. MVVM for the sake of MVVM is counter-intuitive and counter-productive. The purpose of our ModelViews and Models is to focus on running TPL samples and giving the results of those samples back to the user.

Up next is running samples, getting the data to the samples and getting the results back from the samples.

Thanks,
Brian

The Task Parallel Library Sampler – Part Three: Base Classes

Part One: Starting with MVVM
Part Two: The MVVM solution structure and basic framework

Let’s take a look at SampleView, SampleViewModel and the base Sample class all of our models extend from so we can get a better understanding of how this works.

In the first set of samples included with the code the only controls we need are a checkbox to identify which samples should be run. As we expand the capabilities of the samples to demonstrate more functionality of the TPL we’ll need to increase that. For now, however, you’ll see that the SampleView.xaml is really as simple as can be.

<UserControl x:Class="TPLSamples.Views.SampleView"
             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" 
             >
    <Grid>
        <CheckBox IsChecked="{Binding Sample.IsEnabled, Mode=TwoWay}" Content="{Binding Sample.SampleName}" ToolTip="{Binding Sample.SampleName}" />
    </Grid>
</UserControl>

We have the boilerplate WPF code with the standard references and <Grid> as well as our checkbox. The code-behind is the boilerplate created code with nothing added. Important here is how the checkbox data gets populated. Remember that in the ItemsControl of the SamplerView, each ViewModel that is added to the observable list the framework will bind to a view which, conversely, has as it’s data context the view model it’s bound to. Additionally, when constructing the ViewModels, they take an instance of a sample. This is how we get our View <-> ViewModel <-> Model. Let’s take a look at our SampleViewModel so we can understand what is happening in it.

public class SampleViewModel : NotificationObject
{
	private readonly Sample sample;
	public Sample Sample
	{
		get { return sample; }
	}

	public SampleViewModel(Sample sample)
	{
		if(sample == null)
			throw new ArgumentNullException("Sample is null");

		this.sample = sample;
	}
}

That’s it. It just exposes our sample directly. Looking back at the xaml for our view, you can see that the content of the checkbox is bound to “Sample.SampleName”. Since the view has the view model as it’s data context that means we are bind the content of the checkbox to the name of the sample model. Note that there are instances when you’re not dealing in clear-cut models that it makes sense to simply incorporate the aspects of a model into the view model. It also makes sense when you want to limit the exposure of your model that you may not expose the model directly but may wrap properties in calls to the model (for example if you need to handle multi-threaded scenarios where you have to lock on properties because there may be only one instance of the model). In this case we are dealing with very obvious models and there is no reason here to limit the exposure of the model so the model is just exposed directly for binding.

One of the critical aspects of this binding is the IsChecked property. You can see that we have a “Mode=TwoWay” parameter on the binding. This means that not only does the value of the IsChecked property get set from the model, but if the value of the IsChecked property changes it will update the model. In terms of the purest implementation of MVVM this is what is problematic with exposing the model directly. The view model is supposed to act as a controller for the interface from the view and to the model. Exposing the model directly means the the view model is no longer controlling the model but instead the view is. With our samples we could have rolled the model into the model view. To simplify what is already a fairly complex set of code for something so simple as well as showing how view models work in MVVM I created view models but exposed the model.

Finally we need to look at the Sample base model that all samples derive from.

public abstract class Sample : DomainObject
{
	public bool IsEnabled { get; set; }
	public string Results { get; set; }
	public TimeSpan RunTime { get; set; }

	public abstract string SampleName { get; }
	public abstract bool ImageRequired { get; }
	public abstract void Run(System.Drawing.Bitmap bmp = null, Action<string> updateLog = null);
}

The vast majority of my samples need a consistent set of data to work on so we can compare times of execution. The easiest way to do this is just take an image on the Run method. This way, if we want to test our samples under different loads we can just use a bigger or smaller image. The Results property is unused and will be removed from future sets of the code. Originally I had envisioned that as the sample needed to display something to the user it would just update the Results property. Obviously this doesn’t work as the user doesn’t get immediate feedback but instead will only get updated when the sample completes its run. I replaced this with an Action that takes a string and in my SamplerViewModel the action updates the results in the Sampler model. This way the user gets continuous feedback from the sample as it updates.

As the samples run, if they use an image they modify that image. The ImageRequired property is important because it is potentially expensive on the front-end to reload the image if a sample doesn’t need it. Especially in cases where a large image is used.

And that’s it for our Sample model. I realize that the initial set-up of MVVM can be complex. Even some of the implementation of the View through ViewModel to Model work-arounds that have be put into place to handle things that are fairly simple when working with code-behind can be downright ugly. The pay-off is that supporting long-term maintenance should be a lot easier. That’s the tough part to get across to a lot of people. You will have a lot more overhead when initally spinning up an MVVM solution but in the end you will find that it is all worth it during maintenance as you fix bugs and add features. If nothing else then because of how cleanly separate your tiers are.

Up next is a more in-depth explanation of our SamplerView, SamplerViewModel and Sampler model.

Thanks,
Brian

In the previous post I wrote a brief intro to MVVM along with some pros and cons. Next up in this series is an explanation of the layout of the solution and some of the rudimentary framework. Don’t forget you can download all the code here.

TPLSamplesSolutionLayout

In the image above you can see the layout of the solution with Views, ViewModels and Models. MainWindow.xaml has our SamplerView.xaml. SamplerView.xaml has as it’s DataContext a SamplerViewModel.

<UserControl.DataContext>
	<ViewModels:SamplerViewModel />
</UserControl.DataContext>

Looking at the constructor of the SamplerViewModel:

public SamplerViewModel()
{
	Samples = new ObservableCollection();
	Sampler = new Sampler();
	Sampler.Samples.Add(new LineSample());
	Sampler.Samples.Add(new LineParallelSample());
	Sampler.Samples.Add(new GreyScaleSample());
	Sampler.Samples.Add(new GreyScaleParallelSample());
	Sampler.Samples.Add(new GreyScaleDoubleParallelSample());
	ResetSampler();
}

private void ResetSampler()
{
	this.Samples.Clear();
	foreach (var sample in Sampler.Samples)
	{
		this.Samples.Add(CreateSampleViewModel(sample));
	}
}

private SampleViewModel CreateSampleViewModel(Sample sample)
{
	SampleViewModel vm = SamplerViewModelFactory.GetViewModelForSample(sample);
	return vm;
}
  1. we set up our observable collection for our sample view models
  2. construct our Sampler model
  3. construct all our samples
  4. using a Factory pattern get the view model for each of our samples

Now let’s take a step back to the SamplerView.xaml. If you look at the code you’ll see there is a lot going on in the xaml I’m not going to cover here. There are, however, two very important parts to the SamplerView.xaml that must be covered. The first is the DataContext mentioned above that creates a SamplerViewModel. The other is the ItemsControl that binds to the Samples collection.

<ItemsControl Grid.Row="1" IsTabStop="False" ItemsSource="{Binding Samples}">
	<ItemsControl.ItemsPanel>
		<ItemsPanelTemplate>
			<WrapPanel Orientation="Horizontal" IsItemsHost="True" Utility:MarginUtilities.Margin="5" />
		</ItemsPanelTemplate>
	</ItemsControl.ItemsPanel>
	<ItemsControl.ItemTemplate>
		<DataTemplate>
			<Views:SampleView DataContext="{Binding}" />
		</DataTemplate>
	</ItemsControl.ItemTemplate>
</ItemsControl>

When you set the data context in WPF you are exposing that object and it’s properties to binding within that control. In the code above you can see we are binding the ItemsControl to the Samples property of our view model which is an observable collection that contains all of the view models for the samples. In addition to that we are setting the ItemTemplate of the ItemsControl to a view entitled “SampleView” basically saying, “Anything we bind to will use the SampleView as our item” (note that this will be changed later to allow for more SampleView types). It’s this initial setup that can be rather complex but once the framework is in place adding new models (in this case samples) to the application is pretty straight forward.

So let’s walk through from the beginning how we get all of our samples into the application:

  1. MainWindow.xaml contains a user control, “SamplerView”
  2. SamplerView.xaml has as its data context a “SamplerViewModel”
  3. SamplerViewModel.cs has a “Sampler” model that we add all the samples to
  4. SamplerViewModel.cs has a list of “SampleViewModel”, called “Samples” with a factory that maps sample models to sample model views
  5. SamplerViewModel.Samples binds to the ItemsControl in “SamplerView”
  6. SamplerView.xaml ItemsControl has an ItemTemplate that maps those samples to “SampleView”

You’ll notice that I add all the samples to the Sampler model in the SamplerViewModel and not in the Sampler model constructor. Why do I do this? It’s really just a matter of making it easier to have a single place to go to for adding samples to the application. I’d like to keep to the SamplerViewModel as much as possible since that contains the Factory for mapping those samples to their respective view models.

In the next post I’ll go over the SampleView, SampleViewModel and the base Sample class all the samples extend from.

Thanks,
Brian

The Task Parallel Library Sampler – Part One: Starting with MVVM

About a year ago I did a session here at work going over the Task Parallel Library (TPL), it’s benefits and where it works and doesn’t work. To illustrate a lot of the TPL I wrote a simple WPF application with standard code-behind that contained a ton of code samples that demonstrated the concepts I was discussing. I’ve been thinking of doing a basic introduction to MVVM as well as expanding on some of the posts I’ve written here regarding the TPL and finally decided to just write a TPL Sampler application utilizing MVVM. The application could be generalized more than it is but since I wanted to work specifically with the TPL there are some choices I made that may seem a bit odd in general but work given the scope of the application.

So what is MVVM? MVVM stands for Model-View-View Model and derives from the MVC pattern. Wikipedia has a pretty good write up of it that goes fairly in depth into the theory of the pattern. MVVM grew from MVC to take advantage of the data binding abilities of WPF. As a generalization you can consider the Model, whether it’s a data object derived from a database abstraction layer or, in my case, a bit of sample code to run, the object that you are working with. The View is all the GUI components. Finally, the View Model works as the controller to manage interactions between the Model and the View.

So what are the advantages of MVVM? The biggest is a separation of concerns. By this I mean that your data layer can cleanly exist separate from your GUI. This allows for easy integration of unit test on the models and view models as well as easily allowing development to proceed in different areas of the application. All standard advantages to an n-tiered approach to application development apply.

So what are the disadvantages of MVVM? It can get complex pretty easy. There are so many things we take advantage of being able to do right in code-behind that aren’t “proper” within MVVM. While you can do anything in MVVM that you can do in regular code-behind, sometimes you have to go to pretty great lengths to do so. As an example, specifying custom click-events on leaf nodes in a tree where each branch has an arbitrary depth. This may seem contrived but this is a problem I’ve had to solve.

I would argue that MVVM isn’t the end-all, be-all solution to application development in WPF and I think most people would agree with me. I would also argue that you can blend both MVVM and the standard observer pattern with code-behind (which I’ll discuss when going over the sample application. It’s called a composite application and happens fairly often).

It’s an invaluable tool that can greatly ease development and maintenance but it is just one tool. That being said, I can’t think of many application scenarios where it isn’t applicable. Applications are generally data driven. For the most part we’re getting data, manipulating it and then doing something with the result. So why not have a framework in place that takes advantage of the binding that WPF presents?

The sample application (which is here and linked below) is probably one of the simplest MVVM projects you will find. It’s even a bit simpler than Microsoft’s MVVM QuickStart sample application.

Starting with References:
The following references were added beyond the standard references VS adds when creating a default project.
Microsoft.Expression.Interactions
Microsoft.Practices.Prism
Microsoft.Practices.Prism.Interactivity
Microsoft.Practices.ServiceLocation
System.Windows.Interactivity

The Prism libraries are included in the lib directory of the project and are from the Microsoft patterns & practices: Prism site. The Prism libraries aren’t an MVVM framework unto themselves but make utilizing a general MVVM approach easier. I had to add the following redirect in my app.config to compile without warnings because of how the Prism libraries are compiled:

<runtime>
	<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
		<dependentAssembly>
			<assemblyIdentity name="System.Windows.Interactivity" publicKeyToken="31bf3856ad364e35" />
			<bindingRedirect oldVersion="4.0.0.0" newVersion="4.5.0.0"/>
		</dependentAssembly>
	</assemblyBinding>
</runtime>

The ServiceLocation reference is needed by the Prism libs. It too is included in the lib directory but can also be downloaded from Microsoft patterns & practices: CommonServiceLocator

If you look at the MainWindow.xaml you’ll see that the only thing in it is:

<Grid>
    <Views:SamplerView />
</Grid>

The SamplerView contains all our GUI elements for enabling/disabling samples, adding an image for samples to use and the buttons for running the sample. In the next post I’ll work on explaining the SamplerView in more detail.

Thanks,
Brian

TPLSamples Application