I know it's been a while since I've posted anything new. I decided to take the month of December a little easy. Coming up soon I'll have some information on speaking engagements in January and also a review of Pro ASP.NET MVC2 by Steven Sanderson (preview: it's an excellent book).
I wish you a Happy New Year! And as always, Happy Coding!
Friday, December 31, 2010
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!
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!
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!
Saturday, October 30, 2010
Book Review: C# 4.0 in a Nutshell
A few weeks ago, I finished reading C# 4.0 in a Nutshell: The Definitive Reference by Joseph Albahari & Ben Albahari. I'll start off by saying this is an extremely large "nutshell" (the index starts on page 997), and I spent several months reading it in small pieces. The good news is that it was extremely worthwhile.
I had not read a book dedicated to C# since .NET 1.0 came out. And that was simply to get to know the language. Through the years, I've read numerous .NET books, but mostly focused on a particular technology, not on the C# language itself. So, this was a good chance for me to read up on the language from beginning to end. This helped refresh things that I had learned long ago and forgotten, as well as fill me in on the pieces that I missed over the years, and finally including all of the new features that we got with C# 4.0 including dynamic types, code contracts, and the parallel library.
In the preface, the book itself describes what it is not. It is not a replacement for IntelliSense or on-line help; meaning, it does not have a complete listing of all members of each class. Instead, it gives a good overview of select classes and the primary members that you need to know to utilize those classes. Also, it is not a beginner book or a replacement for tutorials that introduce a new programmer to specific topics.
With that said, I found the book extremely useful. The chapters are well laid-out, and I have found it easy to go back and use this as a reference book for particular topics when needed. Here's a list of the chapters:
One thing that is nice about this book that makes it a complete reference is that it covers parts of the language even if they are no longer the recommended techniques. For example, there is a complete chapter on LINQ to XML. For those of you who have not yet tried LINQ to XML, take a look at it. After trying it, you will never go back to the "old" way of parsing and creating XML documents. With that said, the book also has a chapter on "other" XML technologies. This is important because even if you are not creating new code using these technologies, you may experience existing code that uses them.
There are a number of advanced topics, which further complements the "not a beginner book" statement in the preface. These include things like reflection, the insides of building, signing and deploying assemblies, the security model (such as trusted callers and encryption), and the ins and outs of threading.
The new features in C# 4.0 are covered as well. This includes a full chapter on the parallel library. There were some interesting points that were made here including showing how the order that things happen in the parallel processes is indeterminate. Also, there is a discussion of the various ways of "partitioning" -- helping the parallel library know how to best split up the tasks. (Of course, you can also let the framework take it's best shot at splitting up the tasks, and this will work most of the time.)
Overall, this was an excellent (if extremely long) read. For me, I was reminded of some of the fundamentals of the C# language, I picked up a few tips on things I didn't know existed, and I also learned about the new pieces that were added to the 4.0 version of the language.
I'll recommend this book to intermediate level .NET programmers or experienced programmers who are new to C#. I'll keep this as a reference on my shelf and refer to it frequently.
Happy Coding!
I had not read a book dedicated to C# since .NET 1.0 came out. And that was simply to get to know the language. Through the years, I've read numerous .NET books, but mostly focused on a particular technology, not on the C# language itself. So, this was a good chance for me to read up on the language from beginning to end. This helped refresh things that I had learned long ago and forgotten, as well as fill me in on the pieces that I missed over the years, and finally including all of the new features that we got with C# 4.0 including dynamic types, code contracts, and the parallel library.
In the preface, the book itself describes what it is not. It is not a replacement for IntelliSense or on-line help; meaning, it does not have a complete listing of all members of each class. Instead, it gives a good overview of select classes and the primary members that you need to know to utilize those classes. Also, it is not a beginner book or a replacement for tutorials that introduce a new programmer to specific topics.
With that said, I found the book extremely useful. The chapters are well laid-out, and I have found it easy to go back and use this as a reference book for particular topics when needed. Here's a list of the chapters:
- Introducing C# and the .NET Framework
- C# Language Basics
- Creating Types in C#
- Advanced C#
- Framework Overview
- Framework Fundamentals
- Collections
- LINQ Queries
- LINQ Operators
- LINQ to XML
- Other XML Technologies
- Disposal and Garbage Collection
- Diagnostics and Code Contracts
- Streams and I/O
- Networking
- Serialization
- Assemblies
- Reflection and Metadata
- Dynamic Programming
- Security
- Threading
- Parallel Programming
- Asynchronous Methods
- Application Domains
- Native and COM Interoperability
- Regular Expressions
One thing that is nice about this book that makes it a complete reference is that it covers parts of the language even if they are no longer the recommended techniques. For example, there is a complete chapter on LINQ to XML. For those of you who have not yet tried LINQ to XML, take a look at it. After trying it, you will never go back to the "old" way of parsing and creating XML documents. With that said, the book also has a chapter on "other" XML technologies. This is important because even if you are not creating new code using these technologies, you may experience existing code that uses them.
There are a number of advanced topics, which further complements the "not a beginner book" statement in the preface. These include things like reflection, the insides of building, signing and deploying assemblies, the security model (such as trusted callers and encryption), and the ins and outs of threading.
The new features in C# 4.0 are covered as well. This includes a full chapter on the parallel library. There were some interesting points that were made here including showing how the order that things happen in the parallel processes is indeterminate. Also, there is a discussion of the various ways of "partitioning" -- helping the parallel library know how to best split up the tasks. (Of course, you can also let the framework take it's best shot at splitting up the tasks, and this will work most of the time.)
Overall, this was an excellent (if extremely long) read. For me, I was reminded of some of the fundamentals of the C# language, I picked up a few tips on things I didn't know existed, and I also learned about the new pieces that were added to the 4.0 version of the language.
I'll recommend this book to intermediate level .NET programmers or experienced programmers who are new to C#. I'll keep this as a reference on my shelf and refer to it frequently.
Happy Coding!
Monday, October 25, 2010
Thanks for Coming - SoCal Code Camp Los Angeles
Thank you to everyone who came to my sessions at the SoCal Code Camp this last weekend. And a special thank you to all of you who came to more than one of my sessions. I had a great time doing the presentations and meeting all of you. I hope that you found it worthwhile. As a reminder, the slides, code samples and walkthroughs are available on my website: http://www.jeremybytes.com/Demos.aspx.
I've collected a number of questions that came up and will have answers posted here in the near future. A couple questions even came up in both the Saturday and Sunday sessions, so those will go to the top of the list.
Still coming, I also have a book review for C# 4.0 in a Nutshell by Albahari & Albahari. Short version: excellent book in a gigantic nutshell (over 1,000 pages). I've been a little delayed in getting the review out with my preparation for Code Camp (plus, I started a new job this week). I've started reading my next book: Pro ASP.NET MVC 2 Framework by Steven Sanderson. This has been a great read so far and will most likely end up on my "recommended" list.
In the meantime...
Happy Coding!
I've collected a number of questions that came up and will have answers posted here in the near future. A couple questions even came up in both the Saturday and Sunday sessions, so those will go to the top of the list.
Still coming, I also have a book review for C# 4.0 in a Nutshell by Albahari & Albahari. Short version: excellent book in a gigantic nutshell (over 1,000 pages). I've been a little delayed in getting the review out with my preparation for Code Camp (plus, I started a new job this week). I've started reading my next book: Pro ASP.NET MVC 2 Framework by Steven Sanderson. This has been a great read so far and will most likely end up on my "recommended" list.
In the meantime...
Happy Coding!
Tuesday, September 28, 2010
Upcoming Speaking Engagements
I have several speaking engagements coming up in October and November. If you've always wanted to meet me in person, come on out. I'd love to meet you.
October 19, 2010
ASP.NET SIG - San Diego, CA
http://www.sandiegodotnet.com/
October 23 - 24, 2010
So Cal Code Camp - Los Angeles, CA
http://www.socalcodecamp.com/
November 13, 2010
Desert Code Camp - Chandler, AZ
http://nov2010.desertcodecamp.com/
Hope to see you there!
October 19, 2010
ASP.NET SIG - San Diego, CA
http://www.sandiegodotnet.com/
October 23 - 24, 2010
So Cal Code Camp - Los Angeles, CA
http://www.socalcodecamp.com/
November 13, 2010
Desert Code Camp - Chandler, AZ
http://nov2010.desertcodecamp.com/
Hope to see you there!
Tuesday, September 21, 2010
Learn the Lingo: Design Patterns
You already use Design Patterns but probably don't know it. Observer, Adapter, Iterator, Proxy -- Learning the lingo allows you to better communicate your ideas with other developers. We'll take a look at several GoF patterns that we regularly use without realizing it. Don't know who the GoF is? Read on to find out.
Get It Here
You can get the walkthrough and sample code here: http://www.jeremybytes.com/Demos.aspx.
Direct Links:
Walkthrough (PDF)
Code Download -- Visual Studio 2010
Code Download -- Visual Studio 2008
I'll be presenting this topic at the upcoming So Cal Code Camp, October 23rd and 24th in Los Angeles, CA. Hope to see you there!
Happy Coding!
Get It Here
You can get the walkthrough and sample code here: http://www.jeremybytes.com/Demos.aspx.
Direct Links:
Walkthrough (PDF)
Code Download -- Visual Studio 2010
Code Download -- Visual Studio 2008
I'll be presenting this topic at the upcoming So Cal Code Camp, October 23rd and 24th in Los Angeles, CA. Hope to see you there!
Happy Coding!
Monday, September 20, 2010
So Cal Code Camp - Los Angeles
The So Cal Code Camp is coming to Los Angeles October 23rd & 24th. As always, Code Camp is FREE! It's a great chance to get some training and hook up with other developers / coders / hackers in your area. I'll be presenting several sessions, so it's your chance to see me, too.
Hope to see you there!
Hope to see you there!
Tuesday, August 24, 2010
Learn To Love Lambdas
Lambda expressions can be confusing the first time you walk up to them. But once you get to know them, you’ll see that they are a great addition to your toolbox. Used properly, they can add elegance and simplicity to your code. And some .NET constructs (such as LINQ) lend themselves to lambda expressions. We’ll take a look at how lambda expressions work and see them in action.
Get It Here
You can get the walkthrough and sample code here: http://www.jeremybytes.com/Demos.aspx.
Direct Links:
PDF Walkthrough
Code Download -- Visual Studio 2010 (Silverlight 4)
Code Download -- Visual Studio 2008 (Silverlight 3)
I'll be presenting this topic at the upcoming So Cal Code Camp, October 23rd and 24th in Los Angeles, CA. Hope to see you there!
Happy Coding!
Get It Here
You can get the walkthrough and sample code here: http://www.jeremybytes.com/Demos.aspx.
Direct Links:
PDF Walkthrough
Code Download -- Visual Studio 2010 (Silverlight 4)
Code Download -- Visual Studio 2008 (Silverlight 3)
I'll be presenting this topic at the upcoming So Cal Code Camp, October 23rd and 24th in Los Angeles, CA. Hope to see you there!
Happy Coding!
Thursday, August 19, 2010
Quick Bytes: Extension Methods
Extension methods allow you to add functionality to existing types by adding new methods -- no subtyping required. Here's a quick overview of how they work.
Get It Here
You can get the walkthrough (just a short 3-page one) and sample code here:
http://www.jeremybytes.com/Demos.aspx.
Direct Links:
PDF Walkthrough
Code Download
As always, feel free to let me know what you think: feedback@jeremybytes.com.
Happy Coding!
Get It Here
You can get the walkthrough (just a short 3-page one) and sample code here:
http://www.jeremybytes.com/Demos.aspx.
Direct Links:
PDF Walkthrough
Code Download
As always, feel free to let me know what you think: feedback@jeremybytes.com.
Happy Coding!
Tuesday, August 3, 2010
The Ticker Class - Ready for Production?
My "Introduction to XAML" code samples -- both the WPF and Silverlight versions -- include a Ticker class that does the work behind the scenes. (You can find the walkthroughs and code samples here: http://www.jeremybytes.com/Downloads.aspx.) The Ticker.cs file contains the following comment at the top:
No Guarantees
This class uses a DispatchTimer that fires a Tick event based on a specified interval. Our sample application uses a 100 millisecond interval. But here's the trick: the Tick event is not guaranteed to fire at exactly the interval specified. The only guarantee that we have is that the Tick event will never fire *before* the interval has elapsed. And depending on what else your computer is doing at the time, the discrepancies may be quite significant.
Let's Experiment
So let's take a look at the completed code sample from "Introduction to XAML with WPF". (This will work the same with the Silverlight version.)
1. Navigate to the Ticker.cs file in the WPFStopWatch project.
2. Modify the "UpdateValues" method so it looks like the following:
We've modified the last line to include milliseconds in our display. Now, if you run the app and click the Start and Stop buttons repeatedly, you will notice that the display doesn't stop at exactly a 100 millisecond interval. Here's a screenshot from my run:
But it's still hard to see exactly what's going on here. Let's add each "tick" to an output that we can look at more closely.
3. Add one more line to the "UpdateValues" method to output the value to the Console:
4. Open the "Output" window in Visual Studio -- on the "View" menu if you don't already have it showing.
5. Run the application in "Debug" mode.
Now when you click the Start / Stop buttons, each interval value is recorded in the Output window. (The Output window is the standard output for "Console" when running a WPF application.). Here's a screenshot of the output from one my application runs:
What you can see here is that the "1 second" tick occurs a full 1/10th of a second after the 1 second mark. The time drift on my machine is between 4 and 12 milliseconds for this run. But this is based on my computer/processor (a 2.66 GHz Core2Duo) and what was happening at the time. If my machine was busy doing something else, then the tick events would fire further apart. The good news is that the time reported (the DisplayInterval property of the class) is correct. So, the "00:01.100" value itself is accurate.
You can do further experimentation by changing the DispatchTimer interval to 10 milliseconds or even 1 millisecond. By doing this, you can see the minimum time resolution that you can get on your computer with the Ticker class as it currently exists. On my machine, it varies between 10 and 20 milliseconds with only Visual Studio and this application running.
Is This Really So Bad?
For a simple timer (like we created in the sample), this behavior really isn't a big deal. I keep a timer such as this on my desktop to get a rough idea how long other processes take (such as running a report or fetching data from a web service). It works great for that. But if I wanted to do a "real" stop watch that could be used for high resolution timing (such as millisecond), then I would want to approach this a little differently.
I haven't had to create a high-resolution timer, so I don't have a recommendation on exactly what to do. A first step may be looking at the DispatcherPriority (an optional parameter in the constructor). The default DispatcherPriority for the DispatchTimer is Background, which according to the documentation means "Operations are processed after all other non-idle operations are completed." You can find a complete listing of values on MSDN here: http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcherpriority.aspx.
Also, we need to consider the limitations of the .NET Framework and the underlying operating system. Desktop PCs just weren't designed for ultra-high resolution timing purposes. People who do have time-critical activities, such as complex music sequencing, often have specialized hardware and software (although software-only solutions have become more practical with the increase in processor speed and number of cores).
Ready for Production?
So what we see is that the Ticker class will work perfectly well for a simple timer (which is what we created in the sample project). But we can also see that there are limitations in the timer resolution. The good news is that the DisplayInterval value is always correct -- this value does not drift; the drift is in the times between the Tick event firing.
So whether this class is ready for production depends on your needs. I added the caveat in the comments since there are quirks that need to be considered.
Happy Coding!
// This class is a simple time ticker class. Note: thisI recently received an e-mail from Tim M. asking about this comment. Let's take a closer look to see why this class may or may not be "Ready for Production."
// class is for the included demo only and would require
// modifications before using in a production application
No Guarantees
This class uses a DispatchTimer that fires a Tick event based on a specified interval. Our sample application uses a 100 millisecond interval. But here's the trick: the Tick event is not guaranteed to fire at exactly the interval specified. The only guarantee that we have is that the Tick event will never fire *before* the interval has elapsed. And depending on what else your computer is doing at the time, the discrepancies may be quite significant.
Let's Experiment
So let's take a look at the completed code sample from "Introduction to XAML with WPF". (This will work the same with the Silverlight version.)
1. Navigate to the Ticker.cs file in the WPFStopWatch project.
2. Modify the "UpdateValues" method so it looks like the following:
We've modified the last line to include milliseconds in our display. Now, if you run the app and click the Start and Stop buttons repeatedly, you will notice that the display doesn't stop at exactly a 100 millisecond interval. Here's a screenshot from my run:
But it's still hard to see exactly what's going on here. Let's add each "tick" to an output that we can look at more closely.
3. Add one more line to the "UpdateValues" method to output the value to the Console:
4. Open the "Output" window in Visual Studio -- on the "View" menu if you don't already have it showing.
5. Run the application in "Debug" mode.
Now when you click the Start / Stop buttons, each interval value is recorded in the Output window. (The Output window is the standard output for "Console" when running a WPF application.). Here's a screenshot of the output from one my application runs:
What you can see here is that the "1 second" tick occurs a full 1/10th of a second after the 1 second mark. The time drift on my machine is between 4 and 12 milliseconds for this run. But this is based on my computer/processor (a 2.66 GHz Core2Duo) and what was happening at the time. If my machine was busy doing something else, then the tick events would fire further apart. The good news is that the time reported (the DisplayInterval property of the class) is correct. So, the "00:01.100" value itself is accurate.
You can do further experimentation by changing the DispatchTimer interval to 10 milliseconds or even 1 millisecond. By doing this, you can see the minimum time resolution that you can get on your computer with the Ticker class as it currently exists. On my machine, it varies between 10 and 20 milliseconds with only Visual Studio and this application running.
Is This Really So Bad?
For a simple timer (like we created in the sample), this behavior really isn't a big deal. I keep a timer such as this on my desktop to get a rough idea how long other processes take (such as running a report or fetching data from a web service). It works great for that. But if I wanted to do a "real" stop watch that could be used for high resolution timing (such as millisecond), then I would want to approach this a little differently.
I haven't had to create a high-resolution timer, so I don't have a recommendation on exactly what to do. A first step may be looking at the DispatcherPriority (an optional parameter in the constructor). The default DispatcherPriority for the DispatchTimer is Background, which according to the documentation means "Operations are processed after all other non-idle operations are completed." You can find a complete listing of values on MSDN here: http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcherpriority.aspx.
Also, we need to consider the limitations of the .NET Framework and the underlying operating system. Desktop PCs just weren't designed for ultra-high resolution timing purposes. People who do have time-critical activities, such as complex music sequencing, often have specialized hardware and software (although software-only solutions have become more practical with the increase in processor speed and number of cores).
Ready for Production?
So what we see is that the Ticker class will work perfectly well for a simple timer (which is what we created in the sample project). But we can also see that there are limitations in the timer resolution. The good news is that the DisplayInterval value is always correct -- this value does not drift; the drift is in the times between the Tick event firing.
So whether this class is ready for production depends on your needs. I added the caveat in the comments since there are quirks that need to be considered.
Happy Coding!
Wednesday, July 28, 2010
The Use and Misuse of Design Patterns
Design Patterns have always been of great interest to me. (If you doubt this, you can see that I have a section of my Bookshelf dedicated to the topic.) One of the greatest advantages to learning the basic patterns is to share a common language with your fellow developers, so when you talk about a Factory Method or Decorator, I know what you are talking about. But at the same time, I see a tendency for some developers to use patterns for the sake of using patterns without fully considering the benefits and costs.
Rocky Lhotka has a great article about what developers should think about when considering patterns in their projects. You can find it here: On the use and misuse of patterns. Go take a look at it now. Don't worry; I'll wait.
Okay, are you done reading it? Go back and read it again. It's that important.
Welcome back. I've experienced a few of the issues that Rocky mentions. First, I have seen the "Pattern of the Year" phenomenon. It seems like some of the developers in my group get stuck on the current popular pattern. I won't mention any specifics, because as Rocky notes, there's nothing wrong with the pattern itself. The problem is that the popularity leads to a sort of cult of people who feel like they need to implement the pattern whether it fits in with the application or not.
Second, I have seen developers that get so enamored with a particular pattern than they try to use it at every turn. Rocky's analogy is great on this:
I do have an issue that I'm not quite sure how to approach: I have worked with a developer and talked about the benefits and costs of a specific design pattern. We both agreed on the strengths (what the pattern was trying to solve for) and the weaknesses (the added complexity). And we also agreed that we would not get the benefits of the pattern in the current application we were discussing. The frustration is that the other developer still wanted to use the pattern because "we might need it later." Experience shows that this would be unlikely.
So, if you have any suggestions on how to approach this type of situation, let me know. I'll be sure to share the good responses here. Send them to feeback@jeremybytes.com.
If you are new to the design patterns world, I would encourage you to learn the benefits and costs of each pattern. And above all, consider their usage carefully. Patterns are a wonderful tool. But don't get so wrapped up in the tool that you forget the problem you are trying to solve.
Before you go, go back and read Rocky's article one more time: On the use and misuse of patterns.
Happy Coding!
Rocky Lhotka has a great article about what developers should think about when considering patterns in their projects. You can find it here: On the use and misuse of patterns. Go take a look at it now. Don't worry; I'll wait.
Okay, are you done reading it? Go back and read it again. It's that important.
Welcome back. I've experienced a few of the issues that Rocky mentions. First, I have seen the "Pattern of the Year" phenomenon. It seems like some of the developers in my group get stuck on the current popular pattern. I won't mention any specifics, because as Rocky notes, there's nothing wrong with the pattern itself. The problem is that the popularity leads to a sort of cult of people who feel like they need to implement the pattern whether it fits in with the application or not.
Second, I have seen developers that get so enamored with a particular pattern than they try to use it at every turn. Rocky's analogy is great on this:
"It is kind of like a carpenter who spends a lot of money buying some really nice new power tool. And then trying to use that power tool for every part of the construction process -- even if that means being less efficient or increasing the complexity of the job -- just to use the tool."Design patterns are just tools. Part of being a good developer is understanding the strengths and weaknesses of each of those tools. As developers, we need to focus on the problem space that we are working on and pick the appropriate tools for that job. (As a side note, this extends beyond design patterns to the technologies that we use -- whether WPF, Silverlight, or WebForms -- and even further out to the platform -- whether .NET, LAMP, Java, or whatever.)
I do have an issue that I'm not quite sure how to approach: I have worked with a developer and talked about the benefits and costs of a specific design pattern. We both agreed on the strengths (what the pattern was trying to solve for) and the weaknesses (the added complexity). And we also agreed that we would not get the benefits of the pattern in the current application we were discussing. The frustration is that the other developer still wanted to use the pattern because "we might need it later." Experience shows that this would be unlikely.
So, if you have any suggestions on how to approach this type of situation, let me know. I'll be sure to share the good responses here. Send them to feeback@jeremybytes.com.
If you are new to the design patterns world, I would encourage you to learn the benefits and costs of each pattern. And above all, consider their usage carefully. Patterns are a wonderful tool. But don't get so wrapped up in the tool that you forget the problem you are trying to solve.
Before you go, go back and read Rocky's article one more time: On the use and misuse of patterns.
Happy Coding!
Saturday, July 10, 2010
Intro to XAML Questions
While presenting the Intro to XAML session at recent code camp and user groups, a few questions came up. Here's some more information on those topics that I didn't have at my fingertips at the time.
FrameworkElement in the Ticker Class
Question: Why does the Ticker class in the demo code descend from FrameworkElement?
Answer: As I noted during the session, the Ticker class exposes the DisplayInterval property as a DependencyProperty. A DependencyProperty is a WPF/Silverlight construct that adds functionality above a normal property. This is used for features such as animation, styles, and data binding. We used it for data binding in our sample.
So where does FrameworkElement come in? A dependency property can only be added to a DependencyObject (or a class that descends from DependencyObject). FrameworkElement happens to be a descendent of DependencyObject. And since it is also the base class for most of the elements in WPF and Silverlight, it also makes a convenient base class for our custom Ticker class.
If you want more information on dependency properties, you can check out MSDN here: http://msdn.microsoft.com/en-us/library/ms752914.aspx.
User Controls in WPF/Silverlight
Question: Can you create user controls in XAML that would allow you to use the same control on multiple screens?
Answer: The answer to this is definitely yes. "UserControl" is one of the common root-level elements in XAML UIs (in addition to "Window" and "Page"). UserControl is now the default root element for Silverlight, but you can create your own user controls and embed them in other screens (whether they are Window, Page, or another UserControl).
I do have an example in Silverlight that creates a UserControl in a separate XAML file and then uses it on a screen. The sample is available here: http://jeremybytes.blogspot.com/2009/06/more-silverlight-part-2-user-controls.html. There is a small caveat to this, though: it is Silverlight 2. Fortunately, the part that shows how to create a user control and use it in your application is still relevant in Silverlight 4 (and WPF as well). The section on events is also still accurate; however, there is a much easier way to build this particular sample in Silverlight 3 or 4 by using object binding instead of events.
Attached Properties
Question: The XAML syntax for attached properties is intriguing. How do they work?
Answer: An attached property is a construct in WPF and Silverlight, and how the framework handles it internally is more information that you probably want. So, let's just take a look at a short sample.
In the demo code, we use an attached property by setting Grid.Row="0" inside of our TextBlock. Here's a reminder of the code:
To get an idea of how this property gets set, let's take a look at how we would set this property in code rather than in the XAML. We'll assume that our text block is named "myTextblock". There are actually 2 ways we can set the property: either from the point of view of the Grid or from the point of view of the TextBlock.
From the Grid's viewpoint, the property is set like this:
Grid.SetRow(myTextBlock, 0);
From the TextBlock's viewpoint, the property is set like this:
myTextBlock.SetValue(Grid.RowProperty, 0);
Although this doesn't explain the internals, it does give you an idea of how it works. With the first method, we are passing the element (myTextBlock) and value (0) to the Grid's SetRow method. SetRow is a static method of the Grid class that allows for the "Row" attached property to be set. With the second method, we use the SetValue method which allows us to set an attached property from the element (myTextBlock) itself.
Of course, there is more info on attached properties available on MSDN: http://msdn.microsoft.com/en-us/library/ms749011.aspx.
ZoomIt
Question: Where can I get the zooming tool used during the presentation?
Answer: ZoomIt is a tool that was created by a Microsoft employee (Mark Russinovich) for his own use in presentations. It has several features including zooming the screen (like a magnifier), adding annotations (either drawing or text), and showing a break timer. I ran across it while watching a webcast where the speaker was using the tool.
You can download ZoomIt for free here: http://technet.microsoft.com/en-us/sysinternals/bb897434.aspx
Additional XAML Samples
Not exactly a questions, but there are additional XAML samples available on my website. The Target Practice application is a sample I built to see if I could build an application using XAML only. I did this in both WPF and Silverlight 3. Here are the links to the walkthroughs:
WFP: http://jeremybytes.blogspot.com/2009/03/wpf-xaml-sample.html
Silverlight: http://jeremybytes.blogspot.com/2009/09/target-practice-silverlight-3-xaml.html
As with all of my samples, the code can be downloaded from my website: http://www.jeremybytes.com/Demos.aspx.
That's it for now. If you have any questions, feel free to send them to feedback@jeremybytes.com.
Happy Coding!
FrameworkElement in the Ticker Class
Question: Why does the Ticker class in the demo code descend from FrameworkElement?
Answer: As I noted during the session, the Ticker class exposes the DisplayInterval property as a DependencyProperty. A DependencyProperty is a WPF/Silverlight construct that adds functionality above a normal property. This is used for features such as animation, styles, and data binding. We used it for data binding in our sample.
So where does FrameworkElement come in? A dependency property can only be added to a DependencyObject (or a class that descends from DependencyObject). FrameworkElement happens to be a descendent of DependencyObject. And since it is also the base class for most of the elements in WPF and Silverlight, it also makes a convenient base class for our custom Ticker class.
If you want more information on dependency properties, you can check out MSDN here: http://msdn.microsoft.com/en-us/library/ms752914.aspx.
User Controls in WPF/Silverlight
Question: Can you create user controls in XAML that would allow you to use the same control on multiple screens?
Answer: The answer to this is definitely yes. "UserControl" is one of the common root-level elements in XAML UIs (in addition to "Window" and "Page"). UserControl is now the default root element for Silverlight, but you can create your own user controls and embed them in other screens (whether they are Window, Page, or another UserControl).
I do have an example in Silverlight that creates a UserControl in a separate XAML file and then uses it on a screen. The sample is available here: http://jeremybytes.blogspot.com/2009/06/more-silverlight-part-2-user-controls.html. There is a small caveat to this, though: it is Silverlight 2. Fortunately, the part that shows how to create a user control and use it in your application is still relevant in Silverlight 4 (and WPF as well). The section on events is also still accurate; however, there is a much easier way to build this particular sample in Silverlight 3 or 4 by using object binding instead of events.
Attached Properties
Question: The XAML syntax for attached properties is intriguing. How do they work?
Answer: An attached property is a construct in WPF and Silverlight, and how the framework handles it internally is more information that you probably want. So, let's just take a look at a short sample.
In the demo code, we use an attached property by setting Grid.Row="0" inside of our TextBlock. Here's a reminder of the code:
To get an idea of how this property gets set, let's take a look at how we would set this property in code rather than in the XAML. We'll assume that our text block is named "myTextblock". There are actually 2 ways we can set the property: either from the point of view of the Grid or from the point of view of the TextBlock.
From the Grid's viewpoint, the property is set like this:
Grid.SetRow(myTextBlock, 0);
From the TextBlock's viewpoint, the property is set like this:
myTextBlock.SetValue(Grid.RowProperty, 0);
Although this doesn't explain the internals, it does give you an idea of how it works. With the first method, we are passing the element (myTextBlock) and value (0) to the Grid's SetRow method. SetRow is a static method of the Grid class that allows for the "Row" attached property to be set. With the second method, we use the SetValue method which allows us to set an attached property from the element (myTextBlock) itself.
Of course, there is more info on attached properties available on MSDN: http://msdn.microsoft.com/en-us/library/ms749011.aspx.
ZoomIt
Question: Where can I get the zooming tool used during the presentation?
Answer: ZoomIt is a tool that was created by a Microsoft employee (Mark Russinovich) for his own use in presentations. It has several features including zooming the screen (like a magnifier), adding annotations (either drawing or text), and showing a break timer. I ran across it while watching a webcast where the speaker was using the tool.
You can download ZoomIt for free here: http://technet.microsoft.com/en-us/sysinternals/bb897434.aspx
Additional XAML Samples
Not exactly a questions, but there are additional XAML samples available on my website. The Target Practice application is a sample I built to see if I could build an application using XAML only. I did this in both WPF and Silverlight 3. Here are the links to the walkthroughs:
WFP: http://jeremybytes.blogspot.com/2009/03/wpf-xaml-sample.html
Silverlight: http://jeremybytes.blogspot.com/2009/09/target-practice-silverlight-3-xaml.html
As with all of my samples, the code can be downloaded from my website: http://www.jeremybytes.com/Demos.aspx.
That's it for now. If you have any questions, feel free to send them to feedback@jeremybytes.com.
Happy Coding!
Thursday, July 8, 2010
What's Wrong with VB.NET?
VB.NET has the reputation of being a second class language in the .NET world. A lot of this has to do with the history of VB and its transformation from VB6 into VB.NET. Conversely, there is a perception that C# is the "real" .NET language, and I think that comes from its (much shorter) history.
At a recent user group meeting, someone joked that VB had been deprecated, and I will admit that I picked up and echoed that joke. I hope that folks could tell that I wasn't serious. When I'm talking to people, I try to point out VB resources where I can -- for example, my favorite Silverlight and WPF books have both VB and C# versions available -- but I'm personally more familiar with the C# resources since those are the ones I use on a day-to-day basis.
Today, VB.NET and C# are pretty much the same language with different syntax (at least that's how I like to think of them). And the great thing about .NET is that whatever language you work with still gets compiled down to the same IL, and you can use assemblies in your project that are created in any .NET language (in fact, you probably don't even know what language a third-party assembly was created with).
Real programmers don't get stuck on syntax. Programmers in general are opinionated and have their tools and languages of choice. Good programmers generally have several different languages under their belts (and not just .NET languages, but things like Ruby, Python, Perl, Delphi, and Java). I have my language of choice (which is currently C#, but has been different in the past), and before I start a task I try to make sure there isn't another tool that would do the job better.
Why the Bum Rap?
So, why does VB.NET have this reputation? My theory is based on looking at the history of .NET. When .NET launched, it was a brand new platform. Along with that launch, Microsoft was promoting a brand new language (C#) that was created just for that platform. In order for .NET to succeed, Microsoft had to get as many people on board as possible. C# was the vehicle they used for most of their demonstrations. This was because C# had all of the capabilities of .NET (at the time). Because of this, C# became equated in many people's minds as the "primary" .NET language.
But Microsoft also knew that there were millions of people invested in VB. They could not succeed if they forced all of the programmers who were comfortable with the VB syntax to switch over to a C-based syntax. And more importantly, they couldn't force those developers to abandon all of their existing code. So, we got VB.NET. And that's sort of where the problems started.
First of all, VB.NET was very different from VB6. There were a number of "features" that were put in to VB.NET to make migration of existing VB6 code easier. But if programmers wanted to really start using the .NET platform to its full potential, they needed to re-write quite a bit of code to fit in with the new paradigm.
VB.NET and C# had quite a few differences in the early versions. There were some constructs in C# that did not have an equivalent in VB.NET (and vice-versa). In addition, Visual Studio tended to favor C# when it came to features such as refactoring and IntelliSense. C# would get these feature updates first, and then they were made available to VB.NET later (as much later as the next release).
Forget Everything You Thought You Knew
But it's time to forget everything you thought you knew about the differences between VB.NET and C#. With the latest release of .NET 4, the languages are almost equivalent; there are a few minor differences, but for all intents and purposes, you can accomplish the same tasks in similar ways.
Steve K. pointed me to this blog article from Steve Wiltamuth regarding the futures of both languages: VB and C# Coevolution. In short, Microsoft is committed to moving both languages forward in the same direction and keep parity in the features and tools (such as the refactoring and IntelliSense features in Visual Studio).
Wrap Up
The good news of the similarities between the languages is that both C# and VB.NET programmers can take advantage of the vast amount of sample code that's available on the net.
Having both C# and VB.NET is great for the .NET development community. C# (and the C-based syntax) provided a comfortable migration for folks using Java and C++; VB.NET provide a comfortable migration path for folks using VB. Together, this has created a mix of developers that can share code and still hang on to their preferred syntax. That sounds like the best of both worlds to me.
Happy Coding!
At a recent user group meeting, someone joked that VB had been deprecated, and I will admit that I picked up and echoed that joke. I hope that folks could tell that I wasn't serious. When I'm talking to people, I try to point out VB resources where I can -- for example, my favorite Silverlight and WPF books have both VB and C# versions available -- but I'm personally more familiar with the C# resources since those are the ones I use on a day-to-day basis.
Today, VB.NET and C# are pretty much the same language with different syntax (at least that's how I like to think of them). And the great thing about .NET is that whatever language you work with still gets compiled down to the same IL, and you can use assemblies in your project that are created in any .NET language (in fact, you probably don't even know what language a third-party assembly was created with).
Real programmers don't get stuck on syntax. Programmers in general are opinionated and have their tools and languages of choice. Good programmers generally have several different languages under their belts (and not just .NET languages, but things like Ruby, Python, Perl, Delphi, and Java). I have my language of choice (which is currently C#, but has been different in the past), and before I start a task I try to make sure there isn't another tool that would do the job better.
Why the Bum Rap?
So, why does VB.NET have this reputation? My theory is based on looking at the history of .NET. When .NET launched, it was a brand new platform. Along with that launch, Microsoft was promoting a brand new language (C#) that was created just for that platform. In order for .NET to succeed, Microsoft had to get as many people on board as possible. C# was the vehicle they used for most of their demonstrations. This was because C# had all of the capabilities of .NET (at the time). Because of this, C# became equated in many people's minds as the "primary" .NET language.
But Microsoft also knew that there were millions of people invested in VB. They could not succeed if they forced all of the programmers who were comfortable with the VB syntax to switch over to a C-based syntax. And more importantly, they couldn't force those developers to abandon all of their existing code. So, we got VB.NET. And that's sort of where the problems started.
First of all, VB.NET was very different from VB6. There were a number of "features" that were put in to VB.NET to make migration of existing VB6 code easier. But if programmers wanted to really start using the .NET platform to its full potential, they needed to re-write quite a bit of code to fit in with the new paradigm.
VB.NET and C# had quite a few differences in the early versions. There were some constructs in C# that did not have an equivalent in VB.NET (and vice-versa). In addition, Visual Studio tended to favor C# when it came to features such as refactoring and IntelliSense. C# would get these feature updates first, and then they were made available to VB.NET later (as much later as the next release).
Forget Everything You Thought You Knew
But it's time to forget everything you thought you knew about the differences between VB.NET and C#. With the latest release of .NET 4, the languages are almost equivalent; there are a few minor differences, but for all intents and purposes, you can accomplish the same tasks in similar ways.
Steve K. pointed me to this blog article from Steve Wiltamuth regarding the futures of both languages: VB and C# Coevolution. In short, Microsoft is committed to moving both languages forward in the same direction and keep parity in the features and tools (such as the refactoring and IntelliSense features in Visual Studio).
Wrap Up
The good news of the similarities between the languages is that both C# and VB.NET programmers can take advantage of the vast amount of sample code that's available on the net.
Having both C# and VB.NET is great for the .NET development community. C# (and the C-based syntax) provided a comfortable migration for folks using Java and C++; VB.NET provide a comfortable migration path for folks using VB. Together, this has created a mix of developers that can share code and still hang on to their preferred syntax. That sounds like the best of both worlds to me.
Happy Coding!
Monday, June 28, 2010
Upcoming User Groups
I'll be presenting at a couple of upcoming users groups in the Greater Los Angeles area. Here are the dates and links to the websites:
Tuesday, July 6
LA C# (Manhattan Beach, CA) - http://www.lacsharp.org/
Wednesday, July 7
SoCal .NET (Buena Park, CA) - http://www.socaldotnet.org/
Meetings start at 6:00 p.m., and it's a great chance to interact with other developers in your local area. Hope to see you there!
Tuesday, July 6
LA C# (Manhattan Beach, CA) - http://www.lacsharp.org/
Wednesday, July 7
SoCal .NET (Buena Park, CA) - http://www.socaldotnet.org/
Meetings start at 6:00 p.m., and it's a great chance to interact with other developers in your local area. Hope to see you there!
Sunday, June 27, 2010
Thanks for Coming - SoCal Code Camp San Diego
Thank you to everyone who took the time to attend my sessions at the SoCal Code Camp this weekend. I had a great time doing the presentations, and I hope you found the information useful.
As a reminder, all of my sessions are available on my website here: JeremyBytes.com - Demos.
If you liked the sessions (or didn't like the sessions), feel free to drop me a note at feedback@jeremybytes.com. I'll also be glad to answer any follow-up questions you may have.
Happy Coding!
As a reminder, all of my sessions are available on my website here: JeremyBytes.com - Demos.
If you liked the sessions (or didn't like the sessions), feel free to drop me a note at feedback@jeremybytes.com. I'll also be glad to answer any follow-up questions you may have.
Happy Coding!
Sunday, June 20, 2010
Book Review: Effective C# - Second Edition
I just finished up Effective C#: 50 Specific Ways to Improve your C# (Second Edition) by Bill Wagner. This is a collection of expert tips presentented in a clear and concise manner. These are targeted at the intermediate/advanced developer; it is assumed that you understand the basics of C# programming. With that said, this is an excellent resource for folks like me. Bill Wagner brings to light best practices, some pitfalls, and issues to consider, especially if you are designing libraries/APIs for consumption by other developers.
Overview
This is an updated version of Effective C# (First Edition) and More Effective C#. Each of these covered different versions of the .NET framework. This edition covers C# 4; the content is not limited to "what's new in C# 4." It covers items that go back to the earliest versions of .NET, but also includes new items such as dynamic typing and parallel programming with PLINQ.
As the title suggests, there are 50 "items" (spread over 6 chapters). The book is a fairly brief 300 pages; which translates into an average of 6 pages per item. The items are well-presented with an introduction to the problem space, a recommendation (based on a set of parameters), and clearly written code snippets. Each item is also summarized in a closing paragraph that reiterates the problem and solution.
Here's one thing that I like: Bill Wagner does not say "always do this." Each recommendation includes the pros and cons as well as when you may want to do things one way versus another. Many items will also refer to other items in the book. This helps build a cohesion to the overall text.
Chapters
Here's a quick listing of the chapters with a few items from each to give you an idea of the types of things covered in each:
Item 8: Prefer Query Syntax to Loops
Wagner takes a look at advantages that query syntax (LINQ) has over loops (for, while, do, foreach). He doesn't say that standard loops are bad or that we should stop using them. Instead, he shows some specific examples that illustrate how query syntax can make your code more readable and maintainable.
Personally, I've become a big fan of LINQ. But it did take me a while to get to that point. Wagner challenges the developer to step out of his/her comfort zone (loops) and take a look at query syntax and to consider the difference between the imperative model (telling your code how to do the task) and the declarative model (telling your code what task you want to do).
Item 14: Minimize Duplicate Initialization Logic
Wagner points out the pitfalls of having multiple constructors as part of your class and having "copy/paste" code in each of the constructors. This seems obvious once you think about it; after all, we always strive to minimize duplicate logic. The first tendency may be to move all of the logic into a shared private method, but Wagner points out that this is not the optimum solution. Instead look toward having the simpler constructors (those with fewer or no parameters) call the more complex constructors (those with several parameters).
Then he goes a step further and shows specific cases where you may introduce bugs in your code if you are not careful with how you implement the shared logic. In addition, he takes a look at the efficiency of the code generated by the C# compiler in various situations.
Overall Quality
The overall quality of the text is very good. I did notice a few typos here and there (no one is perfect -- I'm sure you'll also find some typos in this post). There was only one item (#23) that had what I would consider significant issues with the code samples. Fortunately, there is a blog on the SRT Solutions (co-founded by Wagner) web site that lists the errata. Be sure to check this out.
Tech books are notoriously hard to produce due to how quickly technology changes (especially Microsoft technologies). The errors that I noticed were well within the tolerable range and did not distract from my understanding of the content.
Recommendation
I would definitely recommend this book to intermediate and advanced C# developers. There are a number of items (especially in the dynamic and parallel items) that gave me insight into things to watch for as I look into the new features in C# 4. As any developer advances, he/she usually ends up creating shared libraries (shared utilities, for example). Wagner includes many items that cover best practices for creating shared libraries and APIs that are consumed by other developers. This is also helpful when one works as part of of a team on projects that have multiple interoperating assemblies/modules.
So, pick this book up. It has bite-sized chunks of good information and some good tips on new C# features.
Happy Coding!
Overview
This is an updated version of Effective C# (First Edition) and More Effective C#. Each of these covered different versions of the .NET framework. This edition covers C# 4; the content is not limited to "what's new in C# 4." It covers items that go back to the earliest versions of .NET, but also includes new items such as dynamic typing and parallel programming with PLINQ.
As the title suggests, there are 50 "items" (spread over 6 chapters). The book is a fairly brief 300 pages; which translates into an average of 6 pages per item. The items are well-presented with an introduction to the problem space, a recommendation (based on a set of parameters), and clearly written code snippets. Each item is also summarized in a closing paragraph that reiterates the problem and solution.
Here's one thing that I like: Bill Wagner does not say "always do this." Each recommendation includes the pros and cons as well as when you may want to do things one way versus another. Many items will also refer to other items in the book. This helps build a cohesion to the overall text.
Chapters
Here's a quick listing of the chapters with a few items from each to give you an idea of the types of things covered in each:
- C# Language Idioms
Item 3: Prefer the is or as Operators to Cast
Item 5: Always Provide ToString()
Item 8: Prefer Query Syntax to Loops - .NET Resource Management
Item 14: Minimize Duplicate Initialization Logic
Item 15: Utilize using and try/finally for Resource Cleanup
Item 18: Distinguish Between Value Types and Reference Types - Expressing Designs in C#
Item 22: Prefer Defining and Implementing Interfaces to Inheritance
Item 24: Express Callbacks with Delegates
Item 25: Implement the Event Pattern for Notifications - Working with the Framework
Item 32: Avoid ICloneable
Item 35: Learn how PLINQ Implements Parallel Algorithms
Item 37: Construct Parallel Algorithms with Exceptions in Mind - Dynamic Programming
Item 38: Understand the Pros and Cons of Dynamic
Item 40: Use Dynamic for Parameters That Receive Anonymous Types
Item 44: Minimize Dynamic Objects in Public APIs - Miscellaneous
Item 45: Minimize Boxing and Unboxing
Item 47: Prefer the Strong Exception Guarantee
Item 48: Prefer Safe Code
Item 8: Prefer Query Syntax to Loops
Wagner takes a look at advantages that query syntax (LINQ) has over loops (for, while, do, foreach). He doesn't say that standard loops are bad or that we should stop using them. Instead, he shows some specific examples that illustrate how query syntax can make your code more readable and maintainable.
Personally, I've become a big fan of LINQ. But it did take me a while to get to that point. Wagner challenges the developer to step out of his/her comfort zone (loops) and take a look at query syntax and to consider the difference between the imperative model (telling your code how to do the task) and the declarative model (telling your code what task you want to do).
Item 14: Minimize Duplicate Initialization Logic
Wagner points out the pitfalls of having multiple constructors as part of your class and having "copy/paste" code in each of the constructors. This seems obvious once you think about it; after all, we always strive to minimize duplicate logic. The first tendency may be to move all of the logic into a shared private method, but Wagner points out that this is not the optimum solution. Instead look toward having the simpler constructors (those with fewer or no parameters) call the more complex constructors (those with several parameters).
Then he goes a step further and shows specific cases where you may introduce bugs in your code if you are not careful with how you implement the shared logic. In addition, he takes a look at the efficiency of the code generated by the C# compiler in various situations.
Overall Quality
The overall quality of the text is very good. I did notice a few typos here and there (no one is perfect -- I'm sure you'll also find some typos in this post). There was only one item (#23) that had what I would consider significant issues with the code samples. Fortunately, there is a blog on the SRT Solutions (co-founded by Wagner) web site that lists the errata. Be sure to check this out.
Tech books are notoriously hard to produce due to how quickly technology changes (especially Microsoft technologies). The errors that I noticed were well within the tolerable range and did not distract from my understanding of the content.
Recommendation
I would definitely recommend this book to intermediate and advanced C# developers. There are a number of items (especially in the dynamic and parallel items) that gave me insight into things to watch for as I look into the new features in C# 4. As any developer advances, he/she usually ends up creating shared libraries (shared utilities, for example). Wagner includes many items that cover best practices for creating shared libraries and APIs that are consumed by other developers. This is also helpful when one works as part of of a team on projects that have multiple interoperating assemblies/modules.
So, pick this book up. It has bite-sized chunks of good information and some good tips on new C# features.
Happy Coding!
Monday, May 31, 2010
Updated Sessions
I have updated a number of my sessions for Visual Studio 2010 and/or Silverlight 4. I will be presenting three of these sessions at the So Cal Code Camp coming up on June 26 & 27, 2010. These are all available for download here: http://www.jeremybytes.com/demos.aspx.
Introduction to the BackgroundWorker Component with WPF
Long running processes are a user experience killer. How many times have you had an application "lock up" while trying to do some function? The BackgroundWorker component in .NET allows you to spawn those long running processes in the background and keep your WPF, Silverlight, or WinForms user interface responsive. We'll take a look at the features of the BackgroundWorker in a WPF application including running a background process, updating the progress in the UI, and cancelling the process before it has completed.
This session has been expanded to include Exception Handling and additional error checking.
Walkthrough: BackgroundWorker-WPF2010.pdf
Sample Code: BackgroundWorker-WPF2010.zip
Introduction to Data Templates and Value Converters in Silverlight
Business applications are all about data, and laying out that data is critical to creating a good user experience. Silverlight has several tools, including Data Templates and Value Converters, that make this easier for the business developer to manage. By the time we're done, you will have a good understanding of the basics of both of these valuable tools.
This session has been updated for Silverlight 4.
Walkthrough: DataTemplatesAndConverters2010.pdf
Sample Code: DataTemplatesAndConverters2010.zip
Introduction to XAML - WPF 2010 / Silverlight 4
Understanding XAML (eXtensible Application Markup Language) is a key to creating the latest .NET user experiences in WPF and Silverlight. We will introduce the basic concepts around XAML and take a look at various features such as namespaces, elements, properties, events, attached properties and some basic layout. We’ll create a simple WPF or Silverlight application that covers these fundamentals. Although you will probably end up doing most of your UI design with a drag-and-drop tool such as Expression Blend, knowing the internals gives you a leg up in making the final tweaks to ensure an excellent user experience.
This session has been updated to include both WPF and Silverlight versions. The same core XAML features are covered in each environment.
Walkthrough (WPF): IntroToXAML-WPF2010.pdf
Sample Code (WPF): IntroToXAML-WPF2010.zip
Walkthrough (Silverlight): IntroToXAML-Silverlight4.pdf
Sample Code (Silverlight): IntroToXAML-Silverlight4.zip
As always, your feedback/questions on any of these sessions is appreciated: feedback@jeremybytes.com.
Happy Coding!
Introduction to the BackgroundWorker Component with WPF
Long running processes are a user experience killer. How many times have you had an application "lock up" while trying to do some function? The BackgroundWorker component in .NET allows you to spawn those long running processes in the background and keep your WPF, Silverlight, or WinForms user interface responsive. We'll take a look at the features of the BackgroundWorker in a WPF application including running a background process, updating the progress in the UI, and cancelling the process before it has completed.
This session has been expanded to include Exception Handling and additional error checking.
Walkthrough: BackgroundWorker-WPF2010.pdf
Sample Code: BackgroundWorker-WPF2010.zip
Introduction to Data Templates and Value Converters in Silverlight
Business applications are all about data, and laying out that data is critical to creating a good user experience. Silverlight has several tools, including Data Templates and Value Converters, that make this easier for the business developer to manage. By the time we're done, you will have a good understanding of the basics of both of these valuable tools.
This session has been updated for Silverlight 4.
Walkthrough: DataTemplatesAndConverters2010.pdf
Sample Code: DataTemplatesAndConverters2010.zip
Introduction to XAML - WPF 2010 / Silverlight 4
Understanding XAML (eXtensible Application Markup Language) is a key to creating the latest .NET user experiences in WPF and Silverlight. We will introduce the basic concepts around XAML and take a look at various features such as namespaces, elements, properties, events, attached properties and some basic layout. We’ll create a simple WPF or Silverlight application that covers these fundamentals. Although you will probably end up doing most of your UI design with a drag-and-drop tool such as Expression Blend, knowing the internals gives you a leg up in making the final tweaks to ensure an excellent user experience.
This session has been updated to include both WPF and Silverlight versions. The same core XAML features are covered in each environment.
Walkthrough (WPF): IntroToXAML-WPF2010.pdf
Sample Code (WPF): IntroToXAML-WPF2010.zip
Walkthrough (Silverlight): IntroToXAML-Silverlight4.pdf
Sample Code (Silverlight): IntroToXAML-Silverlight4.zip
As always, your feedback/questions on any of these sessions is appreciated: feedback@jeremybytes.com.
Happy Coding!
Saturday, May 15, 2010
So Cal Code Camp - San Diego Coming in June
The So Cal Code Camp is coming to San Diego June 26th & 27th. As always, Code Camp is FREE! It's a great chance to get some training and hook up with other developers / coders / hackers in your area. I'll be presenting a few sessions, so it's your chance to see me, too.
Hope to see you there!
Hope to see you there!
Thursday, April 29, 2010
More Thoughts on ASP.NET MVC
I've had two months to work with ASP.NET MVC since my last post on the topic. Since then, I've worked through two projects and have picked up some good experience. There are plenty of pros and cons (more pros in my opinion). Let's take a look at how it differs from other .NET web technologies.
Routing
ASP.NET MVC is more than just Model-View-Controller pattern (the MVC which lends its name). One of the key features is routing. With routing, a URL does not point to a physical resource on the server. Instead, it contains information that allows the Controller to instantiate the appropriate Model and send the data to a specific View. You're probably familiar with the pattern. Let's take a look at the URL for my previous post: http://jeremybytes.blogspot.com/2010/02/new-to-me-aspnet-mvc.html.
The first part is (http://jeremybytes.blogspot.com) points to the server. The next part (2010) would normally be parsed as a physical path (file folder) on the server. But instead, it is a parameter that references the year of the post. The same is true of the "02" portion (the original post is from February 2010). The final part is the name of the article. Now, I can't tell you what lies behind the blogspot link or how it is parsed, but I'm pretty sure that there are no physical directories that refer to the year and month of my posts.
You use this same type of routing in the ASP.NET MVC world. The default is for a URL to take the form of {controller}/{action}/{id}, but you can alter this default implementation however you like. As an example: http://www.example.com/sales/customer/217. This would call the "Sales" controller and ask for Customer #217.
As mentioned previously, this is an "action-first" or "resource-first" model (as opposed to WebForms "page-first" model). I say "action" or "resource" because that will depend on what you are doing. In the above example, we are requesting a specific Customer resource. But we could just as well be requesting an action, such as "UpdateCustomer".
This strikes me as very REST-ful, although that is a topic for another time. The good news for those who like the idea of routing but aren't ready to dive into the rest of ASP.NET MVC: Routing is included in ASP.NET 4.0 (it's actually also available somewhat in 3.5 but requires some extra work).
ASP.NET MVC vs. WebForms: Repeaters
I spent 3 years developing WebForms apps, so I've tried quite a few different techniques for displaying data. The control I ended up liking best is the Repeater. This gives me the most flexibility in laying out my data. But it does have one severe limitation: you cannot nest Repeaters.
The idea of a Repeater is that it will loop through your data set and "repeat" a specified section for each record. This is fine for single level lists, but it gets more complex when you have parent-child relationships.
Let's say that I have data that includes Category, Sub-Category, and Details. I only want to display the Category label at the top of each Category (not on each record). The same is true for Sub-Category. But since I can't nest Repeaters, that means that I must include Category, Sub-Category, and Detail in every single one of my records (flattened data rather than a hierarchy). Then, to get the display that I want, I hook into the Event that runs before displaying each record. In that event handler, I check to see if the current Category is the same as the Category of the previous record. If so, then I suppress (hide) the Category display. Same for Sub-Category. This creates quite a bit of messy, conditional code.
ASP.NET MVC handles this situation entirely different. You are much closer to the metal. So, if I wanted to implement the above scenario, it's quite a bit more elegant. In the View, I simply have a foreach loop that goes through all of the Categories and displays the Category header. Inside there, I have a nested loop that goes through the Sub-Categories and displays that. And inside there, I have a nested loop that goes through the details. This means that I can have a much more natural structure to my data (Model) with a parent-child-grandchild relationship. Add some LINQy goodness, and you have an easily understandable solution without the messy conditionals.
ASP.NET MVC vs. WebForms: File Size
Yes, file size is still important -- just take a look at how prominent smart phones and other mobile devices are becoming. I took an existing WebForms application and converted it to ASP.NET MVC. This was a proof-of-concept so I could try out the technologies. Since the existing application had a well-defined business layer and clear separation from the UI, it was easy to put the ASP.NET MVC front end in place.
Here's what I found: a particular page on the WebForms apps that was 24KB was only 9KB in the ASP.NET MVC version!
I know your initial reaction: just turn off ViewState, moron. But ViewState was turned off. The WebForms page is so much bigger because it uses server-generated names for all of the controls. This can look like "ctl00_mainRepeater_headerLabel_001". When you multiply this by the number of controls for each record and the number of records in the data set, it all adds up.
Conversely, the majority of the ASP.NET MVC output is text -- the equivalent of using a Response.Write instead of using a server-side control. When you look at the output (view source in the browser), it looks like hand-coded HTML rather than machine-generated code. This will vary depending on how you code up your Views, of course. My experience is that the output is pretty straight forward compared to WebForms output.
ASP.NET MVC vs. Silverlight
I won't really get into this debate. Both technologies have their uses and benefits. I was recently listening to .NET Rocks! and heard about a "challenge" that took place at the Visual Studio 2010 Launch Event. Apparently Phil Haack (and team) and Rocky Lhotka (and team) were tasked with creating an application in ASP.NET MVC and Silverlight, respectively. I have a great deal of respect for both of these guys, so I'll just leave that discussion there.
After using Silverlight myself, I was determined that I would never create another WebForms app again (the programming style is just so much more natural). But there is a problem (mentioned above): mobile users.
The reason that I started using ASP.NET MVC is because I needed to create a solution for Blackberry users. And I'm not talking about the shiny-new Blackberry Bolds. I'm talking about (relatively) old devices with browsers that are a step above WAP. Obviously, Silverlight was not an option. ASP.NET MVC, however, allowed me to put together a clean and efficient application.
One Last Thing: Parameters
There are a number of things I like about ASP.NET MVC, but I'll wrap up with one item: Action parameters. The ASP.NET MVC framework does everything it can to automatically pull in the parameters for you.
Let's say that I have an Action (method) like this: UpdateCustomer(int Id, string firstName, string lastName). When this method gets called, the framework tries to populate the parameters from the following locations:
Wrap Up
I've grown to like ASP.NET MVC. At a later date, I'll put together a case study with my actual code to give you a better idea of exactly how the technology works. For now, we'll just stay with what we've discussed so far.
ASP.NET MVC 2 is now shipping as part of Visual Studio 2010. I've only taken a cursory look at it, but it seems to have added some good features to make views even easier and cleaner to generate. Plus, having it included in Visual Studio means that other members of your team will also have it available without having to install the bits separately. If you're doing web programming, this is definitely something to look into.
Happy Coding!
Routing
ASP.NET MVC is more than just Model-View-Controller pattern (the MVC which lends its name). One of the key features is routing. With routing, a URL does not point to a physical resource on the server. Instead, it contains information that allows the Controller to instantiate the appropriate Model and send the data to a specific View. You're probably familiar with the pattern. Let's take a look at the URL for my previous post: http://jeremybytes.blogspot.com/2010/02/new-to-me-aspnet-mvc.html.
The first part is (http://jeremybytes.blogspot.com) points to the server. The next part (2010) would normally be parsed as a physical path (file folder) on the server. But instead, it is a parameter that references the year of the post. The same is true of the "02" portion (the original post is from February 2010). The final part is the name of the article. Now, I can't tell you what lies behind the blogspot link or how it is parsed, but I'm pretty sure that there are no physical directories that refer to the year and month of my posts.
You use this same type of routing in the ASP.NET MVC world. The default is for a URL to take the form of {controller}/{action}/{id}, but you can alter this default implementation however you like. As an example: http://www.example.com/sales/customer/217. This would call the "Sales" controller and ask for Customer #217.
As mentioned previously, this is an "action-first" or "resource-first" model (as opposed to WebForms "page-first" model). I say "action" or "resource" because that will depend on what you are doing. In the above example, we are requesting a specific Customer resource. But we could just as well be requesting an action, such as "UpdateCustomer".
This strikes me as very REST-ful, although that is a topic for another time. The good news for those who like the idea of routing but aren't ready to dive into the rest of ASP.NET MVC: Routing is included in ASP.NET 4.0 (it's actually also available somewhat in 3.5 but requires some extra work).
ASP.NET MVC vs. WebForms: Repeaters
I spent 3 years developing WebForms apps, so I've tried quite a few different techniques for displaying data. The control I ended up liking best is the Repeater. This gives me the most flexibility in laying out my data. But it does have one severe limitation: you cannot nest Repeaters.
The idea of a Repeater is that it will loop through your data set and "repeat" a specified section for each record. This is fine for single level lists, but it gets more complex when you have parent-child relationships.
Let's say that I have data that includes Category, Sub-Category, and Details. I only want to display the Category label at the top of each Category (not on each record). The same is true for Sub-Category. But since I can't nest Repeaters, that means that I must include Category, Sub-Category, and Detail in every single one of my records (flattened data rather than a hierarchy). Then, to get the display that I want, I hook into the Event that runs before displaying each record. In that event handler, I check to see if the current Category is the same as the Category of the previous record. If so, then I suppress (hide) the Category display. Same for Sub-Category. This creates quite a bit of messy, conditional code.
ASP.NET MVC handles this situation entirely different. You are much closer to the metal. So, if I wanted to implement the above scenario, it's quite a bit more elegant. In the View, I simply have a foreach loop that goes through all of the Categories and displays the Category header. Inside there, I have a nested loop that goes through the Sub-Categories and displays that. And inside there, I have a nested loop that goes through the details. This means that I can have a much more natural structure to my data (Model) with a parent-child-grandchild relationship. Add some LINQy goodness, and you have an easily understandable solution without the messy conditionals.
ASP.NET MVC vs. WebForms: File Size
Yes, file size is still important -- just take a look at how prominent smart phones and other mobile devices are becoming. I took an existing WebForms application and converted it to ASP.NET MVC. This was a proof-of-concept so I could try out the technologies. Since the existing application had a well-defined business layer and clear separation from the UI, it was easy to put the ASP.NET MVC front end in place.
Here's what I found: a particular page on the WebForms apps that was 24KB was only 9KB in the ASP.NET MVC version!
I know your initial reaction: just turn off ViewState, moron. But ViewState was turned off. The WebForms page is so much bigger because it uses server-generated names for all of the controls. This can look like "ctl00_mainRepeater_headerLabel_001". When you multiply this by the number of controls for each record and the number of records in the data set, it all adds up.
Conversely, the majority of the ASP.NET MVC output is text -- the equivalent of using a Response.Write instead of using a server-side control. When you look at the output (view source in the browser), it looks like hand-coded HTML rather than machine-generated code. This will vary depending on how you code up your Views, of course. My experience is that the output is pretty straight forward compared to WebForms output.
ASP.NET MVC vs. Silverlight
I won't really get into this debate. Both technologies have their uses and benefits. I was recently listening to .NET Rocks! and heard about a "challenge" that took place at the Visual Studio 2010 Launch Event. Apparently Phil Haack (and team) and Rocky Lhotka (and team) were tasked with creating an application in ASP.NET MVC and Silverlight, respectively. I have a great deal of respect for both of these guys, so I'll just leave that discussion there.
After using Silverlight myself, I was determined that I would never create another WebForms app again (the programming style is just so much more natural). But there is a problem (mentioned above): mobile users.
The reason that I started using ASP.NET MVC is because I needed to create a solution for Blackberry users. And I'm not talking about the shiny-new Blackberry Bolds. I'm talking about (relatively) old devices with browsers that are a step above WAP. Obviously, Silverlight was not an option. ASP.NET MVC, however, allowed me to put together a clean and efficient application.
One Last Thing: Parameters
There are a number of things I like about ASP.NET MVC, but I'll wrap up with one item: Action parameters. The ASP.NET MVC framework does everything it can to automatically pull in the parameters for you.
Let's say that I have an Action (method) like this: UpdateCustomer(int Id, string firstName, string lastName). When this method gets called, the framework tries to populate the parameters from the following locations:
- Routing Parameters: These are the parameters that appear as part of the URL "path", such as the "217" in the Customer example above.
- Query String: These are additional parameters that are part of the URL query string. These are separated from the rest of the URL with a question mark and take the form name=value (separated by ampersands).
- Form Data: These are pulled from fields that are posted back in a form.
- Post Parameters: These are the parameters provided as part of a POST (not necessarily part of a form).
- Header Information: These items can be pulled from the request header.
Wrap Up
I've grown to like ASP.NET MVC. At a later date, I'll put together a case study with my actual code to give you a better idea of exactly how the technology works. For now, we'll just stay with what we've discussed so far.
ASP.NET MVC 2 is now shipping as part of Visual Studio 2010. I've only taken a cursory look at it, but it seems to have added some good features to make views even easier and cleaner to generate. Plus, having it included in Visual Studio means that other members of your team will also have it available without having to install the bits separately. If you're doing web programming, this is definitely something to look into.
Happy Coding!
Tuesday, April 6, 2010
A Programmer's Bookshelf
Due to several requests, I added a Bookshelf to my website. This has a listing of many of the books that I have read over the last several years. My ultimate goal is to create a searchable Silverlight application, but I'm waiting for Silverlight 4 to come out before I get started on that. In the meantime, we'll have to settle for a static list.
If you have any books that you are fond of, feel free to drop me a note.
Happy Coding!
If you have any books that you are fond of, feel free to drop me a note.
Happy Coding!
Monday, April 5, 2010
BackgroundWorker Component Questions
I recently received an e-mail with a few questions regarding the BackgroundWorker Component (original article). I decided to share the answers here.
Page Navigation with the BackgroundWorker
Question: I want to navigate to another page in the BackgroundWorker thread -- for example: "frameNavigator.Navigate(new OtherPage());" in the DoWork method. I tried this, but an exception occurred because the Page class uses the main thread whereas the BackgroundWorker uses a separate thread. How can I get around this?
Answer: As you noticed, things like Pages, Winodws and ListBoxes are all items on the UI thread (and they need to stay on the UI thread). And the BackgroundWorker component processes items on a different thread (not the UI thread). So, you will not be able to do things like "Navigate" in the DoWork method.
But here's what you should do: try to figure out why the navigation process is slow. This is usually due to something that happens when your new Page loads -- it could be loading data from a database, transferring a file across the network, or calling a web service. So, even though you cannot put the "Navigate" into the background, you may be able to take whatever is in your Page Load process and put that in the background. In this type of scenario, you could put the database call method or the file transfer method into the background, not the entire Page object. This will have the effect of keeping your UI thread running and responsive while your data loads in the background.
Using the Progress Bar
Question: I want to get the progress completed from the actual process time, not from a predetermined time as you used in the walkthrough. The application must know how much time the BackgroundWorker process will take to navigate to the target page and then show a progress bar based on this information. How can I accomplish this?
Answer: Progress is a tricky subject. In the example in my walkthrough, I am not technically doing the progress bar based on a predetermined time; I am calculating the progress (a percentage) based on the number of iterations completed in the loop. I purposely kept my background process simple so that I could focus on the methods, events and properties of the BackgroundWorker component itself. But you can use the progress event for anything you can calculate a percentage complete for. For a more complex example, you can look at the BackgroundWorker examples on MSDN: http://msdn.microsoft.com/en-us/library/c8dcext2.aspx. One in particular, calculates a Fibonacci sequence using a recursive method call and calculates a percentage for a progress bar.
As an example of a calculation: if you are doing a file transfer, you can calculate a percentage based on the number of bytes received compared to the total number of bytes. So, if you have received 257 bytes of a 1,356 byte file, you are 19% complete. The limitation is that you have to know how far along you are in the process. If you are doing something like making a database call or a web service call, you may not know how long it will take to complete or how much data you are getting back. In those situations, you cannot calculate a percentage and so you may be better off using a "busy animation" (and there are plenty of examples available on the web for WPF and Silverlight).
Complex Results
Question: I don't like examples of BackgroundWorker using results of "string" or "int". I want a real object. How would I do this?
Answer: The e.Result parameter in the DoWork and RunWorkerCompleted can be as simple or as complex as you like. In my example, I simply use an "int", but e.Result is of type "object", so you can put whatever you want in there (including an entire database result set). There are a few limitations such as the objects that need to be on the UI thread (like we mentioned above). As another option, you can use a separate variable (or set of variables) that is accessible to both the UI and the background process. If you do this, you will want to look into the "lock" method to ensure that you don't end up with multiple processes trying to modify the value at the same time.
Round Up
The BackgroundWorker component is not the right solution for everything. But it can be helpful in quite a few situations. As we saw above, you may not be able to do exactly what you want (such as navigating in the background), but if you think about the problem a little differently, you can often come up with a workable solution.
Happy Coding!
Page Navigation with the BackgroundWorker
Question: I want to navigate to another page in the BackgroundWorker thread -- for example: "frameNavigator.Navigate(new OtherPage());" in the DoWork method. I tried this, but an exception occurred because the Page class uses the main thread whereas the BackgroundWorker uses a separate thread. How can I get around this?
Answer: As you noticed, things like Pages, Winodws and ListBoxes are all items on the UI thread (and they need to stay on the UI thread). And the BackgroundWorker component processes items on a different thread (not the UI thread). So, you will not be able to do things like "Navigate" in the DoWork method.
But here's what you should do: try to figure out why the navigation process is slow. This is usually due to something that happens when your new Page loads -- it could be loading data from a database, transferring a file across the network, or calling a web service. So, even though you cannot put the "Navigate" into the background, you may be able to take whatever is in your Page Load process and put that in the background. In this type of scenario, you could put the database call method or the file transfer method into the background, not the entire Page object. This will have the effect of keeping your UI thread running and responsive while your data loads in the background.
Using the Progress Bar
Question: I want to get the progress completed from the actual process time, not from a predetermined time as you used in the walkthrough. The application must know how much time the BackgroundWorker process will take to navigate to the target page and then show a progress bar based on this information. How can I accomplish this?
Answer: Progress is a tricky subject. In the example in my walkthrough, I am not technically doing the progress bar based on a predetermined time; I am calculating the progress (a percentage) based on the number of iterations completed in the loop. I purposely kept my background process simple so that I could focus on the methods, events and properties of the BackgroundWorker component itself. But you can use the progress event for anything you can calculate a percentage complete for. For a more complex example, you can look at the BackgroundWorker examples on MSDN: http://msdn.microsoft.com/en-us/library/c8dcext2.aspx. One in particular, calculates a Fibonacci sequence using a recursive method call and calculates a percentage for a progress bar.
As an example of a calculation: if you are doing a file transfer, you can calculate a percentage based on the number of bytes received compared to the total number of bytes. So, if you have received 257 bytes of a 1,356 byte file, you are 19% complete. The limitation is that you have to know how far along you are in the process. If you are doing something like making a database call or a web service call, you may not know how long it will take to complete or how much data you are getting back. In those situations, you cannot calculate a percentage and so you may be better off using a "busy animation" (and there are plenty of examples available on the web for WPF and Silverlight).
Complex Results
Question: I don't like examples of BackgroundWorker using results of "string" or "int". I want a real object. How would I do this?
Answer: The e.Result parameter in the DoWork and RunWorkerCompleted can be as simple or as complex as you like. In my example, I simply use an "int", but e.Result is of type "object", so you can put whatever you want in there (including an entire database result set). There are a few limitations such as the objects that need to be on the UI thread (like we mentioned above). As another option, you can use a separate variable (or set of variables) that is accessible to both the UI and the background process. If you do this, you will want to look into the "lock" method to ensure that you don't end up with multiple processes trying to modify the value at the same time.
Round Up
The BackgroundWorker component is not the right solution for everything. But it can be helpful in quite a few situations. As we saw above, you may not be able to do exactly what you want (such as navigating in the background), but if you think about the problem a little differently, you can often come up with a workable solution.
Happy Coding!
Friday, April 2, 2010
Target Practice Live Demo
I have finally posted a live demo of the Silverlight 3 Target Practice demo application: Target Practice Live Demo.
As a reminder, this is a mini-app created entirely with XAML (no code-behind). The original article is here: Silverlight Target Practice.
And you can get the source code here: SilverlightTargetPractice.zip
Happy Coding!
As a reminder, this is a mini-app created entirely with XAML (no code-behind). The original article is here: Silverlight Target Practice.
And you can get the source code here: SilverlightTargetPractice.zip
Happy Coding!
Monday, March 1, 2010
Book Review: ASP.NET MVC Framework Unleashed
I just finished reading ASP.NET MVC Framework Unleased by Stephen Walther. It was an extremely fast read: I finished it in a little under two weeks. Unfortunately, I was able to finish it so quickly because it contained very little information. I was rather disappointed by the content. I really don't like giving bad reviews, but I feel like I should get my thoughts down for other folks who may be interested in this topic. Please note, this is a review of the book itself, not the underlying ASP.NET MVC technology.
Beginner, Intermediate, or Advanced?
My biggest problem with Unleashed is that it cannot decide what level it is targeted at. The cover lists it as "User Level: Intermediate-Advanced," but the actual content seems to jump from one level to another. For example, there are step-by-step instructions on configuring and using the ASP.NET Membership Database (ASPNETDB.mdf). I would consider this to be "beginner" level content. For the majority of real-world applications, you will not use the ASPNETDB.mdf database for your user authentication / authorization, instead going for a more robust security model such as implementing a custom MembershipProvider. This is not covered, however.
But the text does not qualify as Intermediate or Advanced as there is very little actual content. The majority of the book is code samples. Code samples are generally a good thing, but the code samples here are full-files. This means that when looking at the various elements (such as Views and Controllers), you end up seeing the same "boiler-plate" code over and over again. Many times there are only a few unique lines of code in a 30 line listing. In addition, descriptions of the code samples are limited to a paragraph or two with no in-depth description of the concepts at hand. This is combined with listings in both C# and VB (again, not necessarily a bad thing). I often felt like I was "skimming" a 30 page chapter in just 10 minutes or so due to the use of code samples and lack of description.
As a final example, there are 2 chapters devoted to AJAX and jQuery. In the introduction to the book, the author assumes that the reader is familiar with HTML and .NET (either C# or VB). However, it does not mention AJAX or jQuery as pre-requisites. AJAX is used much differently in ASP.NET MVC than it is in Web Forms, yet there is no discussion of those differences. There is just a handful of samples with little explanation.
Lack of Focus
Another problem is the lack of focus. ASP.NET MVC has many unique features, but many of the concepts are shared with ASP.NET Web Forms and the .NET framework at large. I wanted the book to focus on the concepts that differ from non-ASP.NET MVC applications, but there was a lot of overlap.
To expand on the example above (the Membership database), the security concepts (users, roles, principles, etc.) are the same as ASP.NET Web Forms applications, but there were several large sections dedicated to authentication. And as noted above, this was only at the "beginner" level and did not touch on intermediate or advanced topics.
As another example, Unleashed spends a lot of time with the Entity Framework. There are step-by-step instructions on creating a SQL Express database and setting up Entity Framework entities. In addition, it also spends a bit of time talking about the Repository pattern and Service layers of the application. These all related to the "M" (Model) of MVC. But the point of the "M" is that you can implement your model in an infinite number of ways. Again, this may be appropriate for a "beginner" level book, but it should go beyond merely mentioning other options if it is trying to be something more.
Ironically, I think that the topic covered best by this book is Test Driven Development (TDD). Throughout the text, there is a focus on the "Red / Green / Refactor" methodology of TDD. And the final part of the book (6 chapters on building a sample application) is a very good walkthrough of using the test-first method to fulfill the use cases. Had this book been called Test Driven Development with ASP.NET MVC, I would probably give this book a much better review.
Summary
Ultimately, the only reason that I was able to follow this book is because I went through ASP.NET MVC training. But the reason that I purchased the book was so that I could have a reference with more detail. As an example, I was looking for details on HTML Helpers, both the helpers "in the box" and custom helpers. The book has a few mentions of the existing helpers, but does not go into any detail on the options and parameters available. As for creating custom helpers, there is an example of it, but nothing much beyond the sample code.
I really don't like giving bad reviews. I realize that putting any technical book together is a lot of work. However, technical books are also my life-blood. They are my primary source of in-depth learning. In addition, they are quite expensive. I do have enough information to complete my project (which was the primary goal of training + book), but I'm still looking for a good reference book. Since ASP.NET MVC version 2 is just around the corner (releasing with .NET 4.0 in April), I'll probably hold out before purchasing another.
In working with ASP.NET MVC, I'm becoming a fan of it. So, I'll be posting more about the technology topic in the future. I'll also keep you informed of other useful resources that I run across.
[Update: I have found a good book on this topic: Pro ASP.NET MVC 4 by Adam Freeman. You can see my review here: Book Review: Pro ASP.NET MVC 4.]
Happy Coding!
Beginner, Intermediate, or Advanced?
My biggest problem with Unleashed is that it cannot decide what level it is targeted at. The cover lists it as "User Level: Intermediate-Advanced," but the actual content seems to jump from one level to another. For example, there are step-by-step instructions on configuring and using the ASP.NET Membership Database (ASPNETDB.mdf). I would consider this to be "beginner" level content. For the majority of real-world applications, you will not use the ASPNETDB.mdf database for your user authentication / authorization, instead going for a more robust security model such as implementing a custom MembershipProvider. This is not covered, however.
But the text does not qualify as Intermediate or Advanced as there is very little actual content. The majority of the book is code samples. Code samples are generally a good thing, but the code samples here are full-files. This means that when looking at the various elements (such as Views and Controllers), you end up seeing the same "boiler-plate" code over and over again. Many times there are only a few unique lines of code in a 30 line listing. In addition, descriptions of the code samples are limited to a paragraph or two with no in-depth description of the concepts at hand. This is combined with listings in both C# and VB (again, not necessarily a bad thing). I often felt like I was "skimming" a 30 page chapter in just 10 minutes or so due to the use of code samples and lack of description.
As a final example, there are 2 chapters devoted to AJAX and jQuery. In the introduction to the book, the author assumes that the reader is familiar with HTML and .NET (either C# or VB). However, it does not mention AJAX or jQuery as pre-requisites. AJAX is used much differently in ASP.NET MVC than it is in Web Forms, yet there is no discussion of those differences. There is just a handful of samples with little explanation.
Lack of Focus
Another problem is the lack of focus. ASP.NET MVC has many unique features, but many of the concepts are shared with ASP.NET Web Forms and the .NET framework at large. I wanted the book to focus on the concepts that differ from non-ASP.NET MVC applications, but there was a lot of overlap.
To expand on the example above (the Membership database), the security concepts (users, roles, principles, etc.) are the same as ASP.NET Web Forms applications, but there were several large sections dedicated to authentication. And as noted above, this was only at the "beginner" level and did not touch on intermediate or advanced topics.
As another example, Unleashed spends a lot of time with the Entity Framework. There are step-by-step instructions on creating a SQL Express database and setting up Entity Framework entities. In addition, it also spends a bit of time talking about the Repository pattern and Service layers of the application. These all related to the "M" (Model) of MVC. But the point of the "M" is that you can implement your model in an infinite number of ways. Again, this may be appropriate for a "beginner" level book, but it should go beyond merely mentioning other options if it is trying to be something more.
Ironically, I think that the topic covered best by this book is Test Driven Development (TDD). Throughout the text, there is a focus on the "Red / Green / Refactor" methodology of TDD. And the final part of the book (6 chapters on building a sample application) is a very good walkthrough of using the test-first method to fulfill the use cases. Had this book been called Test Driven Development with ASP.NET MVC, I would probably give this book a much better review.
Summary
Ultimately, the only reason that I was able to follow this book is because I went through ASP.NET MVC training. But the reason that I purchased the book was so that I could have a reference with more detail. As an example, I was looking for details on HTML Helpers, both the helpers "in the box" and custom helpers. The book has a few mentions of the existing helpers, but does not go into any detail on the options and parameters available. As for creating custom helpers, there is an example of it, but nothing much beyond the sample code.
I really don't like giving bad reviews. I realize that putting any technical book together is a lot of work. However, technical books are also my life-blood. They are my primary source of in-depth learning. In addition, they are quite expensive. I do have enough information to complete my project (which was the primary goal of training + book), but I'm still looking for a good reference book. Since ASP.NET MVC version 2 is just around the corner (releasing with .NET 4.0 in April), I'll probably hold out before purchasing another.
In working with ASP.NET MVC, I'm becoming a fan of it. So, I'll be posting more about the technology topic in the future. I'll also keep you informed of other useful resources that I run across.
[Update: I have found a good book on this topic: Pro ASP.NET MVC 4 by Adam Freeman. You can see my review here: Book Review: Pro ASP.NET MVC 4.]
Happy Coding!
Tuesday, February 23, 2010
New to Me: ASP.NET MVC
ASP.NET MVC was New 18 Months Ago
I first heard about ASP.NET MVC in October 2008 (at the VSLive! conference). Scott Hanselman gave a keynote that presented an overview and announced the beta release. At that point, it looked interesting, but with all of the new technologies that have been thrown at us over the last several years, I couldn't devote any time to look into it. Plus, I was comfortable with WebForms, having spent the previous 3 years developing fairly significant web apps.
So, here we are a year and a half later. I was struggling with a project at work. I knew that I could accomplish the task with WebForms, but all of my UI designs that I had worked through on the whiteboard seemed to come out as a mess. I had a nagging feeling that ASP.NET MVC was the solution to this problem. I took some time to look into it some more, and it turns out that it was the right direction.
Why ASP.NET MVC was the Answer
My main problem is that I needed to present data to the user in a different format depending on the record type. And I wouldn't know the record type until run time. ASP.NET WebForms is a "page first" model. This means that the user requests a particular page (through a URL). The page is then processed on the server which then presents the output to the user. ASP.NET MVC is an "action first" model. This means that instead of requesting a physical page, the user requests an action (also through a URL). This action is processed by a Controller. In my situation, the Controller can instantiate the Model (from my business layer) and then, based on the record type, can present the specific View (aspx page) that is appropriate.
So, I've taken a crash course in ASP.NET MVC. After going through some on-line training and working through a simple test app, I'm convinced that this is the right solution for this particular project. The design is much cleaner and will be easier to maintain.
Resources
I was fortunate enough to win a 1-year subscription to the Pluralsight OnDemand! library. In the library is a 10 hour on-line course for ASP.NET MVC, and I took a couple of days last week to go through it. This was an excellent resource. (If you are interested in trying Pluralsight OnDemand! yourself, just stop by the website; they offer 7-day trial subscriptions if you drop them a note.)
In addition, I picked up "ASP.NET MVC Framework Unleashed" by Stephen Walther as a printed reference. I'm still working my way through the book, but I've found a lot of useful information so far.
More to Come
Stay tuned for more to come. My project at work is still in progress. I'll have a lot of learnings from it (as I do with most of my projects). When I run across interesting items, good tips, and pitfalls, I'll be sure to post them here.
Happy Coding!
I first heard about ASP.NET MVC in October 2008 (at the VSLive! conference). Scott Hanselman gave a keynote that presented an overview and announced the beta release. At that point, it looked interesting, but with all of the new technologies that have been thrown at us over the last several years, I couldn't devote any time to look into it. Plus, I was comfortable with WebForms, having spent the previous 3 years developing fairly significant web apps.
So, here we are a year and a half later. I was struggling with a project at work. I knew that I could accomplish the task with WebForms, but all of my UI designs that I had worked through on the whiteboard seemed to come out as a mess. I had a nagging feeling that ASP.NET MVC was the solution to this problem. I took some time to look into it some more, and it turns out that it was the right direction.
Why ASP.NET MVC was the Answer
My main problem is that I needed to present data to the user in a different format depending on the record type. And I wouldn't know the record type until run time. ASP.NET WebForms is a "page first" model. This means that the user requests a particular page (through a URL). The page is then processed on the server which then presents the output to the user. ASP.NET MVC is an "action first" model. This means that instead of requesting a physical page, the user requests an action (also through a URL). This action is processed by a Controller. In my situation, the Controller can instantiate the Model (from my business layer) and then, based on the record type, can present the specific View (aspx page) that is appropriate.
So, I've taken a crash course in ASP.NET MVC. After going through some on-line training and working through a simple test app, I'm convinced that this is the right solution for this particular project. The design is much cleaner and will be easier to maintain.
Resources
I was fortunate enough to win a 1-year subscription to the Pluralsight OnDemand! library. In the library is a 10 hour on-line course for ASP.NET MVC, and I took a couple of days last week to go through it. This was an excellent resource. (If you are interested in trying Pluralsight OnDemand! yourself, just stop by the website; they offer 7-day trial subscriptions if you drop them a note.)
In addition, I picked up "ASP.NET MVC Framework Unleashed" by Stephen Walther as a printed reference. I'm still working my way through the book, but I've found a lot of useful information so far.
More to Come
Stay tuned for more to come. My project at work is still in progress. I'll have a lot of learnings from it (as I do with most of my projects). When I run across interesting items, good tips, and pitfalls, I'll be sure to post them here.
Happy Coding!
Wednesday, February 17, 2010
Jeremy on .NET Rocks! (sort of)
Okay, so now that I have your attention, I wasn't really on .NET Rocks!. But Carl and Richard did read my e-mail on show #525. Here's a link (if you're curious): .NET Rocks! Show #525. You can skip ahead to about 4 minutes in.
And BTW, they are sending me a hoody.
And BTW, they are sending me a hoody.
Saturday, February 13, 2010
Quick Byte: Statement Lambdas
Overview
The first time I came across a lambda expression, I was perplexed. I could tell that something important was going on, but I got stuck on the new syntax. As I studied them some more, I had an "aha" moment, and it all clicked into place. This is a brief runthrough of that process with statement lambdas.
Get It Here
You can get the walkthrough (just a short 3-page one) and sample code here: http://www.jeremybytes.com/Demos.aspx.
Direct Links:
PDF Walkthrough
Code Download
Let me know what you think. If you find this useful (or not), drop me a note at feedback@jeremybytes.com.
Happy Coding!
The first time I came across a lambda expression, I was perplexed. I could tell that something important was going on, but I got stuck on the new syntax. As I studied them some more, I had an "aha" moment, and it all clicked into place. This is a brief runthrough of that process with statement lambdas.
Get It Here
You can get the walkthrough (just a short 3-page one) and sample code here: http://www.jeremybytes.com/Demos.aspx.
Direct Links:
PDF Walkthrough
Code Download
Let me know what you think. If you find this useful (or not), drop me a note at feedback@jeremybytes.com.
Happy Coding!
Sunday, January 31, 2010
SoCal Code Camp
Thank you!
A big thank you to everyone who attended my sessions at the SoCal Code Camp. I had a great time, and I hope that all of you did, too.
As a reminder, for all of my sessions: the slides, code samples, and walkthroughs are available here: http://www.jeremybytes.com/Demos.aspx.
Drop me a note if you had a chance to attend. I'd love to hear what you thought.
A big thank you to everyone who attended my sessions at the SoCal Code Camp. I had a great time, and I hope that all of you did, too.
As a reminder, for all of my sessions: the slides, code samples, and walkthroughs are available here: http://www.jeremybytes.com/Demos.aspx.
Drop me a note if you had a chance to attend. I'd love to hear what you thought.
Sunday, January 10, 2010
Introduction to XAML with WPF
(Editor's note: I will be presenting this topic at the SoCal Code Camp Jan 30 & 31, 2010.)
Overview
Understanding XAML (eXtensible Application Markup Language) is a key to creating the latest .NET user experiences in WPF and Silverlight. We will introduce the basic concepts around XAML and take a look at various features such as namespaces, elements, properties, events, attached properties and some basic layout. We’ll create a simple WPF application that covers these fundamentals. Although you will probably end up doing most of your UI design with a drag-and-drop tool such as Expression Blend, knowing the internals gives you a leg up in making the final tweaks to ensure an excellent user experience.
Get It Here
As mentioned in a previous post, the demos are now available in PDF form here: http://www.jeremybytes.com/Demos.aspx.
Direct Links:
PDF Walkthrough
Code Download
Happy coding!
Overview
Understanding XAML (eXtensible Application Markup Language) is a key to creating the latest .NET user experiences in WPF and Silverlight. We will introduce the basic concepts around XAML and take a look at various features such as namespaces, elements, properties, events, attached properties and some basic layout. We’ll create a simple WPF application that covers these fundamentals. Although you will probably end up doing most of your UI design with a drag-and-drop tool such as Expression Blend, knowing the internals gives you a leg up in making the final tweaks to ensure an excellent user experience.
Get It Here
As mentioned in a previous post, the demos are now available in PDF form here: http://www.jeremybytes.com/Demos.aspx.
Direct Links:
PDF Walkthrough
Code Download
Happy coding!
Monday, January 4, 2010
Introduction to Data Templates and Value Converters in Silverlight 3
(Editor's note: I will be presenting this topic at the SoCal Code Camp Jan 30 & 31, 2010.)
Overview
Business applications are all about data, and laying out that data is critical to creating a good user experience. Fortunately, Silverlight 3 has several tools, including Data Templates and Value Converters, that make this easier for the business application developer to manage. Today, we'll take a look at consuming a WCF service and creating the layout of the data. By the time we're done, you should have a good understanding of the basics of Data Templates and Value Converters.
Get It Here
As mentioned in a previous post, the demos are now available in PDF form here: http://www.jeremybytes.com/Demos.aspx.
Here's some direct links:
PDF Walkthough
Code Download
Happy coding!
Overview
Business applications are all about data, and laying out that data is critical to creating a good user experience. Fortunately, Silverlight 3 has several tools, including Data Templates and Value Converters, that make this easier for the business application developer to manage. Today, we'll take a look at consuming a WCF service and creating the layout of the data. By the time we're done, you should have a good understanding of the basics of Data Templates and Value Converters.
Get It Here
As mentioned in a previous post, the demos are now available in PDF form here: http://www.jeremybytes.com/Demos.aspx.
Here's some direct links:
PDF Walkthough
Code Download
Happy coding!
Friday, January 1, 2010
More Demos Coming
A New Direction
Okay, so I've posted several demo articles here so far. The unfortunate thing is that the blogging tool I've been using is not the easiest thing to use for these demos. One of the primary shortcomings is the inability to have code samples that can easily be copy/pasted. With this in mind, I've decided to post upcoming demos as PDFs (along with downloadable code samples). I think this should improve usability for me and my readers.
You can get the PDFs and code samples here: http://www.jeremybytes.com/Demos.aspx.
If you miss the HTML walkthroughs and really want to see them again, just post me a message at feedback@jeremybytes.com, and I'll see what I can do for future articles.
Okay, so I've posted several demo articles here so far. The unfortunate thing is that the blogging tool I've been using is not the easiest thing to use for these demos. One of the primary shortcomings is the inability to have code samples that can easily be copy/pasted. With this in mind, I've decided to post upcoming demos as PDFs (along with downloadable code samples). I think this should improve usability for me and my readers.
You can get the PDFs and code samples here: http://www.jeremybytes.com/Demos.aspx.
If you miss the HTML walkthroughs and really want to see them again, just post me a message at feedback@jeremybytes.com, and I'll see what I can do for future articles.