Saturday, November 20, 2010

Learn to Love Lambdas Session Questions

Here are a couple of questions that came up during the Learn to Love Lambdas sessions at recent Code Camps.  If you would like to review the session, you can check out the walkthrough and code samples here: Learn to Love Lambdas.

Extension Methods
Question: Could the AddSort() and AddFilter() methods be rewritten as extension methods?

Answer: This question came up during two presentations, so there are at least two people who are curious about this.  The answer in this case is no.  Let's look at the signuatures of the methods as we created them:



If we wanted to convert these to extension methods, we would need to make these methods "public" (instead of private) and "static" (instead of instance methods).  For a quick review of how to create and use extension methods, you can check here: Quick Byte: Extension Methods.  The problem is that we cannot make these methods static since they reference specific UI elements on the form.  We could do some refactoring and pass in values (for example, the check box true/false values) as parameters.  That would allow us to make these methods static; however, this may not be a good idea.

First, I like to reserve extension methods for generic methods that I am planning on re-using.  In this case, we have a very specific use case that we are implementing based on UI elements.  Second, in making these methods public and static, it exposes them to broader usage than simply as private members of the class.  Because these methods are so specific, this may just end up resulting in errors if they are used elsewhere.  So, even though it is technically possible to convert these to extension methods, I would not recommend it in this case.

Captured Variables
Question: You metioned that if the callback method grew any larger, you would be tempted to refactor it out into a separate method.  How would this affect the captured variable?

Answer: Even if we refactored the method, we would not eliminate the lambda expression itself; we would simply move the body of the lamba to another method.  In this case, we could add the captured variable as a parameter, and it would remain available to the separate method.

Here's the refactored code:


Here, you can see that we take the "selPerson" variable (the variable that is captured by the lambda expression) and pass it as a parameter to the "UpdateUI" method.  Since the "UpdateUI" method is called within the body of the lambda expression, we still has access to the captured variable which we can pass through to the method.  This maintains the same functionality that we have before and allows us to keep the "selPerson" variable as a method-level variable.

Thank you for the great questions.  Feel free to drop me a note if you have any more.

Happy Coding!

Monday, November 15, 2010

BackgroundWorker Session Questions

I want to thank everyone who attended my sessions at the So Cal Code Camp in Los Angeles, CA and at the Desert Code Camp in Chandler, AZ.  As I mentioned, I take the questions that come up in my sessions and look into them further.  Here's the good news: I have some answers for questions that came up regarding the BackgroundWorker Component.  (If you want to take a look at the session walkthrough and code download, you can get them here: Keep Your UI Responsive with the BackgroundWorker Component.)

Passing Additional Data During Progress Updates
Question #1: What is the "UserState" property that shows up in the ProgressChangedEventArgs?
Question #2: Is there a way to pass data from the background thread to the UI thread?

Answer: As you might guess since I grouped these questions together, the UserState property can be used to pass additional information from the background thread to the UI thread during the ProgressChanged event.

As a reminder, we call the ReportProgress method in the background thread which then fires the ProgressChanged event on the UI thread.  In the sample code, we used the ReportProgress method that takes a single integer paramter (the percentProgress).  But there is an overload that takes both a percentProgress and an additional object parameter called userState.  As you might imagine, this will populate the UserState property of our ProgressChangedEventArgs.  Let's take a look at updating our application.

First, on the background thread, we will add an additional "update message" where we calculate the progress and call ReportProgress:


This "update message" will contain a string such as "Iteration 45 of 150".

Next, we'll use the new UserState to update the text in our output box:

And here's the output from the running application:

As you can see we have now passed some relevant information from our background thread to our UI thread.  It is easy to imagine several uses for this type of behavior.  For example, if we were downloading multiple files, we could show the name of the current file in the UI.  In addition, since the parameter and UserState are of type "object", we can put anything we want in there, including complex types or collections of complex types.

BackgroundWorker and MVVM
Question: The BackgroundWorker component can be used with WPF and Silverlight.  Does this mean that it can be used with MVVM (Model-View-ViewModel)?

Answer: I've thought about this one quite a bit.  The question isn't just can the BackgroundWorker be used with MVVM, but whether it makes sense to do so.  I've decided that the answer is yes, it does fit in with MVVM.

In the MVVM pattern, the UI elements on the screen (the View) are data-bound to properties and methods in the ViewModel.  The ViewModel is responsible for making data from the Model available to the View.  In this situation, we would place the BackgroundWorker in the ViewModel.  If we were to convert our sample application to MVVM, we could imagine a property for the percent complete that would be bound to the progress bar, and a property for the output that would be bound to the output text box.

The BackgroundWorker would live in the ViewModel and kick off the long running process in the background.  When the ProgressChanged event fired (in the ViewModel), it would update the percent complete property (which would in turn update the View due to the data binding).  The same would be true of the output property.  This would prevent the ViewModel (and the View) from "hanging" while waiting for the long-running process to complete.

MVVM is a much larger topic, and there are a variety of different ways to implement it.  But it seems like the BackgroundWorker component may be a useful addition when we are making sure our UI stays responsive.

Again, thank you for the great questions.  I hope that I'll see you at one of my sessions in the future.

Happy Coding!