Exploring the TimeCheck Application (Part 12)

Last week, in the Exploring the TimeCheck Application (Part 11) post, you discovered some of the requirements for making the Add, Edit, and Delete buttons for the Standard Project Entries and Standard Tasks lists work. This addition included creating a new dialog box so that the user could provide the information required by the lists. Now that you have the basics down, let’s look at the code for performing the task. This first bit of code performs tasks with projects.

private void btnProjAdd_Click(object sender, EventArgs e)
{
   // Create the project dialog box.
   frmProjectTask ThisProject = new frmProjectTask();
 
   // Display the project dialog box on screen.
   if (ThisProject.ShowDialog(this) == DialogResult.OK)
   {
      // Create a new project and add it to the list.
      Project NewProject = new Project();
      NewProject.Name = ThisProject.txtProject.Text;
      GroupData.ProjectList.Add(NewProject);
      GroupSettings.SaveSettings(GroupData);
   }
 
   // Update the list information.
   ClearLists();
   FillLists();
}
 
private void btnProjEdit_Click(object sender, EventArgs e)
{
   // Make sure the user has selected a value to edit.
   if (lstStandardProjects.SelectedIndex == -1)
   {
      // Display a message box telling the user to select an item.
      MessageBox.Show("You must select an item to edit.",
         "Selection Error", MessageBoxButtons.OK,
         MessageBoxIcon.Error);
 
      // Exit the event handler.
      return;
   }
 
   // Create the project dialog box.
   frmProjectTask ThisProject = new frmProjectTask("Edit a Project",
      lstStandardProjects.SelectedItem.ToString(), "&Edit");
 
   // Display the project dialog box on screen.
   if (ThisProject.ShowDialog(this) == DialogResult.OK)
   {
      // Edit the existing project name and save it to disk.
      GroupData.ProjectList[lstStandardProjects.SelectedIndex].Name
         = ThisProject.txtProject.Text;
      GroupSettings.SaveSettings(GroupData);
   }
 
   // Update the list information.
   ClearLists();
   FillLists();
}
 
private void btnProjDelete_Click(object sender, EventArgs e)
{
   // Make sure the user has selected a value to delete.
   if (lstStandardProjects.SelectedIndex == -1)
   {
      // Display a message box telling the user to select an item.
      MessageBox.Show("You must select an item to delete.",
         "Selection Error", MessageBoxButtons.OK,
         MessageBoxIcon.Error);
 
      // Exit the event handler.
      return;
   }
 
   // Remove the selected project from the list.
   GroupData.ProjectList.RemoveAt(lstStandardProjects.SelectedIndex);
   GroupSettings.SaveSettings(GroupData);
 
   // Update the list information.
   ClearLists();
   FillLists();
}

The btnProjAdd_Click() event handler begins by creating the default frmProjectTask object, ThisProject. It then displays the dialog box. When the user clicks OK, the code creates a new Project entry, NewProject, adds the project name to it from ThisProject.txtProject.Text, adds the entry to GroupData.ProjectList, and then saves GroupData. Now you know why ThisProject.txtProject.Text has to be public. There are other ways you could handle the situation, such as using a property, but this approach is faster and shouldn’t pose any security issues. You must save the changes by calling SaveSettings(). Because the list has changed, you must call ClearLists() to remove existing data from the lists and FillLists() to add the new data.

In most respects, the btnProjEdit_Click() event handler works like the btnProjAdd_Click() event handler. However, in this case, the user must choose an entry to edit, rather than create a new entry. When the user has failed to select an entry, the code displays an error message and exits. As before, the code displays the dialog box, but this time it changes the button and title bar text to reflect the difference in task. In addition, the code modifies the existing entry, rather than creating a new one. As before, you must call both ClearLists() and FillLists() to update the application.

Deleting an entry in the btnProjDelete_Click() event handler is the simplest of the three tasks. The code begins by verifying that the user has actually selected an entry and reacting if the user hasn’t. It then looks for the requested entry in the list and calls RemoveAt() to remove the entry from the list. A call to ClearLists() and FillLists() completes the process.

The three event handlers for tasks work much like those used for projects. Of course, the code makes additional changes to the frmProjectTask dialog box to ensure the user sees the right information. Here is the code for these three event handlers.

private void btnTaskAdd_Click(object sender, EventArgs e)
{
   // Create the project dialog box.
   frmProjectTask ThisTask = new frmProjectTask("Add a Task", "&Task");
 
   // Display the project dialog box on screen.
   if (ThisTask.ShowDialog(this) == DialogResult.OK)
   {
      // Create a new task and add it to the list.
      Task NewTask = new Task();
      NewTask.Name = ThisTask.txtProject.Text;
      GroupData.TaskList.Add(NewTask);
      GroupSettings.SaveSettings(GroupData);
   }
 
   // Update the list information.
   ClearLists();
   FillLists();
}
 
private void btnTaskEdit_Click(object sender, EventArgs e)
{
   // Make sure the user has selected a value to edit.
   if (lstStandardTasks.SelectedIndex == -1)
   {
      // Display a message box telling the user to select an item.
      MessageBox.Show("You must select an item to edit.",
         "Selection Error", MessageBoxButtons.OK,
         MessageBoxIcon.Error);
 
      // Exit the event handler.
      return;
   }
 
   // Create the task dialog box.
   frmProjectTask ThisTask = new frmProjectTask("Edit a Task",
      "&Task", lstStandardTasks.SelectedItem.ToString(), "&Edit");
 
   // Display the project dialog box on screen.
   if (ThisTask.ShowDialog(this) == DialogResult.OK)
   {
      // Edit the existing project name and save it to disk.
      GroupData.TaskList[lstStandardTasks.SelectedIndex].Name
         = ThisTask.txtProject.Text;
      GroupSettings.SaveSettings(GroupData);
   }
 
   // Update the list information.
   ClearLists();
   FillLists();
}
 
private void btnTaskDelete_Click(object sender, EventArgs e)
{
   // Make sure the user has selected a value to edit.
   if (lstStandardTasks.SelectedIndex == -1)
   {
      // Display a message box telling the user to select an item.
      MessageBox.Show("You must select an item to edit.",
         "Selection Error", MessageBoxButtons.OK,
         MessageBoxIcon.Error);
 
      // Exit the event handler.
      return;
   }
 
   // Remove the selected task from the list.
   GroupData.TaskList.RemoveAt(lstStandardTasks.SelectedIndex);
   GroupSettings.SaveSettings(GroupData);
 
   // Update the list information.
   ClearLists();
   FillLists();
}

As you can see, the differences aren’t all that much. Well, that’s it for this week. Please let me know if you have any questions at all about the code for these six event handlers. Next week we’ll begin looking at the code for some of the other configuration dialog box controls. In the meantime, contact me at John@JohnMuellerBooks.com with your questions and concerns. You can read the next segment in this series at Exploring the TimeCheck Application (Part 13).

 

.NET Framework Version Error When Installing Visual Studio 2012

I received a few messages from readers recently asking about an error message they receive when trying to install the release version of Visual Studio 2012 on their Windows 8 system (I imagine that the same error will occur when installing on Windows Server 2012, but no one has contacted me about it). The error says that Visual Studio 2012 can’t install because the version of the .NET Framework 4.5 is wrong.

Unfortunately, the error message isn’t very helpful. You can’t install a new version of the .NET Framework 4.5 over the top of the existing installation. In addition, you can’t uninstall the old version and then install the new version because Windows 8 requires the .NET Framework 4.5 for certain operating system elements. In short, there isn’t any apparent way to fix the problem.

The issue will go away at some point because it originates as a conflict between the Windows 8 version and the Visual Studio 2012 requirements. Every reader who has had this problem is using a non-released version of Windows 8 (normally the RC version). You can’t install the release version of Visual Studio 2012 on a non-release version of Windows 8. I’m assuming that the same error occurs if you try to install a release version of Visual Studio 2012 on a non-release version of Windows Server 2012, but I’d like to hear if anyone has tried this out at John@JohnMuellerBooks.com.

What concerns me about this particular error is that it’s one time where Microsoft could have (and probably should have) come up with a substantially better error message or provided some sort of Knowledge Base article on the topic. As far as I know, there isn’t any such article and developers are currently having to rely on community support to fix this problem. It isn’t the first time Microsoft has left developers wondering. If you ever encounter this sort of problem, please let me know about it. If I can confirm the issue, I’ll put together a blog entry about it to get the word out to others in order to save them a bit of time.

 

Information Overload

I’m always looking for ways to serve your needs better. Of course, that means reviewing the statistics for this blog so I know what you find most useful, reflecting on your comments both in the blog and in e-mail, and looking at the latest trends in content presentation. This third possible source of useful information has made me wonder whether I’m not overloading you with information. Check out the post entitled, “Why I Will Be Posting Less” to see for yourself. Information overload is indeed a problem in our society and I would want to be the last one to add to anyone’s burden, especially after writing posts such as Learning to Unplug.

Of course, every blog is different, as are the people who read it. I’m taking a page from Mr. Hyatt’s blog and considering what you need from me in the way of usable information. What I’d like you to do is tell me how often you’d like me to post new additions to this blog:

 

  • Two times a week
  • Three times a week
  • Four times a week
  • Five times a week


You can tell me as a comment to this post or through e-mail at John@JohnMuellerBooks.com. It’s important to me to provide you with enough information, but not to overwhelm you. Of course, if I end up posting less often, I’ll cover some topics a little less often too.

From what I’ve been able to garner from the statistics that the blog software automatically maintains for me, you really do like the eclectic mix of topics on this blog, so I’ll continue in that vein and using about the same percentages of posts as I do now. However, I’d like to hear about any topics you particularly like or dislike. Be sure to e-mail me about your concerns. It’s important to me to serve your needs the best way I can.

I’ll gather statistics for a couple of weeks from you (reminding you at times about this post), and then provide an update here on what I’ve learned. These sorts of discoveries are always interesting and often produce unexpected results. I’m sure you’ll want to know what I discover just as much as I want to learn your thoughts and opinions about this blog. In the meantime, happy reading!

 

After the First Frost

First frost is always a hectic time around here. The day before sees Rebecca and me running around trying to harvest everything that won’t survive the frost intact (such as tomatoes, okra, and eggplants). We had our first frost on Saturday, so we spent the day trying to get everything picked (after waiting until the last second for the plants to grow as much as possible.

On Sunday Rebecca and I went out to the garden to start picking the items that actually require a frost to taste good. This year we started with the squash and sweet potatoes. Despite the bad summer, we ended up with a nice assortment of both butternut and acorn squash.

SquashandSweetPotatoes01

It wasn’t our largest harvest, but it was a lot more than we expected considering we didn’t plant that many plants. We actually had squash growing up inside the tomato cages. The squash performed amazingly well this year. I wish we had planted more of them.

However, the big news for us was the sweet potatoes. We planted just one plant and expected to receive four or five standard sized sweet potatoes and a few smaller ones for our efforts. What we received instead was eight relatively large sweet potatoes and a wealth of smaller ones. The largest sweet potato is a monster that weighs nearly 7 pounds.

SquashandSweetPotatoes02

Yes, that really is just one sweet potato. It’s misshapen, but there is only one little crack in the surface and the potato is quite firm. I was expecting something around four pounds, so we were both surprised when we weighed it and the scale showed 6¾ pounds.

SquashandSweetPotatoes03

We’re planning to use this one sweet potato to feed our entire family during Thanksgiving this year. I’m not sure how we’d be able to use it otherwise. That’s one big potato.

I’ve said it before and I’ll say it again, Every Year is a Good and a Bad Year. This year we had great results with okra and squash. We’ll never forget this monster sweet potato though. What did well for you in your garden this year?  Let me know at John@JohnMuellerBooks.com.

 

Review of V for Vendetta

V for Vendetta is a movie that you can sum up with a single phrase, “People shouldn’t fear their government; the government should fear its people.” The phrase has become so famous that I turned up 55,330 hits when looking for it on Google. Hugo Weaving (V) and Natalie Portman (Evey) provide an amazing depiction of an Orwellian world in which the government has taken over the lives of its citizens to protect them from a dire plague. The question of whether the loss of freedom is worth the perceived protection that government can provide is the locus of content in this movie. The location is England, but there are constant references to the United States, which is in chaos from the plague. The fate of the rest of the world is unimportant as far as the movie is concerned and knowing how the rest of the world has fared would only prove to be a distraction. (The movie is an adaptation of the V for Vendetta graphic novel written by Alan Moore and illustrated by David Lloyd.)

To understand the movie completely, you have to consider both recent and historical facts. The Gunpowder Revolution was a failed attempt to garner religious freedom during the reign of King James I in 1605. Knowing that most Americans know nothing about the Gunpowder Revolution or one of its favored participants, Guy Fawkes, the movie does take time to explain both in a short overview manner that doesn’t detract from the flow or entertainment value of the movie even a little. The reason Guy Fawkes is important is not the man, but the idea encapsulated by the man’s actions. Freedom to be who you want to be is the focus of both the movie and the history event. Guy Fawkes Day is still celebrated each November 5th with bonfires and fireworks.

Recent history comes into play because the movie makes constant references to the sorts of things that are happening in the American political arena today. Some people have gone so far as to cast the movie as anti-American, while others see it as a call for political activities, such as the Occupy movement. There are even some groups that are drawing a parallel between the events in the movie and the loss of freedoms engendered by the events of 9/11. Let’s just say that the movie is good at stirring a strong emotional reaction, no matter what your politics may be.

There are elements of the movie that will make people uncomfortable. It addresses a considerable number of sensitive topics and I have no doubt that some people are offended by the coverage. For example, it portrays gay and lesbian lovers in a relatively open way.

I don’t actually go to the movies to decide my political ideals and motivations, but any review of this movie has to necessarily include some information on that content. The biggest question is whether the movie is still entertaining, despite the message it tries to present (successfully or not depends on you). There are definite science fiction elements of the apocalyptic genre. You’ll also see strong emotional elements (other than the politics). In some respects, the movie is a hard core love story between V and Evey (no, you won’t see scenes of heavy breathing, but the tension between the two becomes obvious as the movie progresses). The movie draws most people in and you find yourself caring for the main characters quite quickly.

The surprising aspect of this movie is that there is also a mystery element. Chief Inspector Finch (Stephen Rea) spends considerable time trying to track V down. However, the chase leads Finch in unexpected directions. Telling you too much about them would ruin the surprises, but it really does make for a good mystery. While V tells you about the price of freedom and Evey tells you about the price of love, Finch reveals the story behind both.

If you’re looking for dramatic graphics and special effects, this movie does have some of both, but tastefully keeps them under control because it has such as strong story to tell. You may be disappointed if you truly expect to see an overwhelming assortment of chases, escapes, and pyrotechnics, but I think the makers of this movie made great choices in their selection of visual elements.

I’d love to say that this movie is pure entertainment, but you’d have to work hard to ignore the messages it presents. Despite your best efforts, it will likely cause you to think about things that you may not have otherwise thought about. The entertainment aspect really is top notch, but the strong story elements make this movie so much more than simple entertainment. Be prepared to have some aspect of your current viewpoints challenged because this movie seems to pick on a wide range of popular notions. V for Vendetta is an amazing movie.

 

Exploring the TimeCheck Application (Part 11)

The focus of this post is frmConfigure, which you created in Exploring the TimeCheck Application (Part 3). In Exploring the TimeCheck Application (Part 10) you saw that this form has several lists that need to be maintained. This post begins the process of making the controls on this form functional. To begin with, there are two distinct lists for this application. The first contains projects that the user works on, while the second contains tasks that the user can perform with those projects. Each list requires that the administrator be able to add, edit, and delete entries, so there is a total of six buttons. In addition, any changes to these two lists necessarily modifies the user’s default selections. We’ll talk about the underpinnings for these six buttons today.

There are three essential tasks to consider: deleting, adding, and editing. Deleting an entry is a matter of removing it from the list and then re-displaying the list on screen. Adding and editing entries requires user input, which means you need another form, frmProjectTask, to the application using the same techniques you used earlier. The new form looks like this:

TimeCheck1101

You use the following settings to create this dialog box:

Control

Property

Value

Form1

(Name)

frmProjectTask

AcceptButton

btnAdd

CancelButton

btnCancel

FormBorderStyle

FixedDialog

Size

290, 110

Text

Add a Project

ToolTip1

(Name)

toolTip1

Button1

(Name)

btnAdd

AccessibleDescription

Add the new project to the list.

DialogResult

OK

Location

197, 12

Size

75, 23

TabIndex

1

Text

&Add

ToolTip on toolTip1

Add the new project to the list.

Button2

(Name)

btnCancel

AccessibleDescription

Exit without making a change.

DialogResult

Cancel

Location

197, 41

Size

75, 23

TabIndex

2

Text

&Cancel

ToolTip on toolTip1

Exit without making a change.

Label1

(Name)

lblProject

Location

12, 9

Size

40, 13

TabIndex

3

Text

&Project

TextBox1

(Name)

txtProject

AccessibleDescription

Contains the project text.

Location

12, 25

Modifiers

Public

Size

179, 20

TabIndex

0

ToolTip on toolTip1

Contains the project text.

In order to make frmProjectTask usable in the application, you need to define a number of constructors for it. These constructors make it possible to use the same basic form for all four needs:

  • Add a project
  • Edit a project
  • Add a task
  • Edit a task


In each case, you interact with the form in a slightly different way. The default setup lets you add a project to the list. In order to edit a project, you must supply the current project text, along with changing the dialog box title and the add button to appropriate values. The following code shows the four constructors used for the purpose.

public partial class frmProjectTask : Form
{
   // Add a project constructor.
   public frmProjectTask()
   {
      // Perform the default task.
      InitializeComponent();
   }
 
   // Edit a project constructor.
   public frmProjectTask(String Title, String Value, String ButtonText)
   {
      // Perform the default task.
      InitializeComponent();
 
      // Set the dialog box title.
      this.Text = Title;
 
      // Set the Accept button title.
      btnAdd.Text = ButtonText;
 
      // Provide a value for the textbox.
      txtProject.Text = Value;
  }
 
   // Add a task constructor.
   public frmProjectTask(String Title, String ValueName)
   {
      // Perform the default task.
      InitializeComponent();
 
      // Set the dialog box title.
      this.Text = Title;
 
      // Set the value label title.
      lblProject.Text = ValueName;
   }
    
   // Edit a task constructor.
   public frmProjectTask(String Title, String ValueName,
      String Value, String ButtonText)
   {
      // Perform the default task.
      InitializeComponent();
 
      // Set the dialog box title.
      this.Text = Title;
 
      // Set the value label title.
      lblProject.Text = ValueName;
 
      // Set the Accept button title.
      btnAdd.Text = ButtonText;
 
      // Provide a value for the textbox.
      txtProject.Text = Value;
   }
}

It’s actually possible to use the same constructor for all four tasks, but this approach makes it easier for the developer interacting with the form to create the form needed. Of course, it’s also nice to get by with a little less typing whenever possible.

Now that you have a form to use to get data from the user, it’s time to get back to frmConfigure. The previous post discussed a special method for filling the lists, FillLists(). It turns out that there is also a generic need for a method to clear the lists before filling them, so the application also has a ClearLists() method as shown here.

private void ClearLists()
{
   // Clear all of the lists on the dialog box.
   cbProjectName.Items.Clear();
   cbWorkType.Items.Clear();
   lstStandardProjects.Items.Clear();
   lstStandardTasks.Items.Clear();
 
   // Verify that the user's default selections are
   // still valid.
   if (!GroupData.ProjectList.Contains(new Project(UserData.DefaultProject)))
      UserData.DefaultProject = "None";
   if (!GroupData.TaskList.Contains(new Task(UserData.DefaultTask)))
      UserData.DefaultTask = "None";
 
   // Save the data to disk.
   UserSettings.SetUserSettings(UserData);
}

I’m sure some readers are wondering why I didn’t include this functionality with FillLists(), but there are genuinely times when you only need to fill an empty list. In addition, using two separate methods makes the purpose of each task clear and simple. Methods should focus on one task whenever possible to keep things simple. When you start making methods too complicated, debugging becomes a problem and it’s much harder for other developers to understand your code.

This part of the example starts out by clearing the lists. However, in clearing the lists you may actually end up clearing the user’s default selections as well. If the administrator has removed those default selections, the user will need a new default selection or the combo boxes will appear blank. The application sets the default value to “None” when the user’s original choice is no longer available.

Notice the use of the Contains() method to determine whether the default selection is still available. The Contains() method requires that you provide an object of the type that you want to use for comparison purposes. Our original version of the Project and Task classes doesn’t include a constructor that makes creating an object of this type easy, so this example adds it (more about this addition in a few moments).

The documentation doesn’t make it very clear that the Contains() method always returns false unless you implement it in the supporting class. However, you don’t implement it directly. What you do instead is provide a means for the List base class to make the determination based on an equality method, Equals(), that you provide. If you remember from Exploring the TimeCheck Application (Part 8) I created simple forms of the Project and Task classes for the sake of discussion. It wasn’t necessary to know about the Contains() method at the time and would have only confused matters. In order to make the Contains() method usable, you must add the IEquatable interface and the Equals() method. Here is the code used for the updated version of the Project class.

// Contains a single standard project name.
[Serializable()]
public class Project : IEquatable<Project>
{
   // Default a default constructor.
   public Project()
   {
   }
 
   // Define a constructor that accepts a project name.
   public Project(String ProjectName)
   {
      this.Name = ProjectName;
   }
 
   // Define a method for checking equality.
   public Boolean Equals(Project OtherProject)
   {
      // Verify the Name property values are equal.
      if (this.Name == OtherProject.Name)
         return true;
      else
         return false;
   }
 
   // Define the project property.
   public String Name { get; set; }
}

As you can see, the updated Project class contains a new constructor that accepts as project name as input. It then returns an object that includes the object name. The class also now includes an Equals() method that accepts a Project object as input and returns true or false based on the equality of the two project Name property values. However, the application won’t even use the Equals() method unless you also include the IEquatable<Project> entry. Even though this looks simple, a lot of developers encounter problems with it because the documentation doesn’t make the required implementation clear.

The Task class requires similar additions. You need to add the constructor, the interface reference, and the Equals() method as shown here.

// Contains a single standard task name.
[Serializable()]
public class Task : IEquatable<Task>
{
   // Create a default task constructor.
   public Task()
   {
   }
 
   // Create a task construtor that accepts a string.
   public Task(String TaskName)
   {
      this.Name = TaskName;
   }
 
   // Define a method for checking equality.
   public Boolean Equals(Task OtherTask)
   {
      // Verify the Name property values are equal.
      if (this.Name == OtherTask.Name)
         return true;
      else
         return false;
   }
 
   // Define the task property.
   public String Name { get; set; }
}

That’s it for this week. Next week we’ll start discussing the button event handlers. In the meantime, let me know if you have any questions about these important code additions or want to know why I covered them as I did in these posts (sometimes it’s important to know why something is done in a certain order). Let me know about your questions and concerns at John@JohnMuellerBooks.com. You can see the next post in this series at Exploring the TimeCheck Application (Part 12).

Choosing the Right Express Edition Version

A lot of my readers rely on the Visual Studio Express Edition products to follow the examples in my book with good reason—the product is a free download. Books like Start Here! Learn Microsoft Visual C# 2010 Programming are actually designed from the ground up to use Visual Studio Express Edition. Even though I wrote Professional Windows 7 Development Guide with the purchased product in mind, most of the examples work just fine with the Express Edition as well. It makes sense to me that you’d want to try to learn as much as possible without making a huge commitment in software, so I welcome hearing about your Express Edition experiences.

The latest issue I’m encountering with readers is that Microsoft has changed how the Express Edition downloads work for Visual Studio 2012. There are now several versions of the Express Edition and you have to be sure you download the correct version to ensure that the IDE works with your operating system and my books. Make sure you download Express for Windows Desktop, not Express for Windows 8 (which doesn’t install on anything but Windows 8). The Express for Windows Desktop works with the following operating systems.

 

  • Windows 7 SP1 (x86 and x64)
  • Windows 8 (x86 and x64)
  • Windows Server 2008 R2 SP1 (x64)
  • Windows Server 2012 (x64)

 

This version of the Express Edition will let you create a number of application types. For example, you can create these sorts of applications:

 

  • Windows Presentation Foundation (WPF)
  • Windows Forms (WinForms)
  • Win32


Notice that there is no Metro support included with this version. None of my books currently support Metro either. However, if you decide you want to create a Metro application, then you need to download the Express for Windows 8 version and you must install it on a Windows 8 system to use it. Even though the downloads may look confusing, the differences between them are really straightforward.

Make sure you meet all of the requirements for install Visual Studio 2012 on your machine. The Express for Windows Desktop version has these requirements:

 

  • 1.6 GHz or faster processor
  • 1 GB of RAM (or 1.5 GB when running on a virtual machine)
  • 5 GB of available hard disk space
  • 100 MB of available hard disk space
  • 5400 RPM hard disk drive
  • DirectX 9-capable video card running at 1024 x 768 or higher display resolution


Don’t get the idea that my books require Visual Studio 2012. All of my existing books work just fine with the Visual Studio 2010 Express Edition. This version works on older versions of Windows and has smaller system requirements. Of course, Microsoft will remove this product from its site at some point, so if you want to use this older version, make sure you download it now.

Let me know if you encounter any additional difficulties using the Visual Studio 2012 Express for Windows Desktop with my books at John@JohnMuellerBooks.com. In the meantime, happy coding!

 

Making Dehydrated Chips

Rebecca dehydrates several kinds of chips for us to eat during the winter months. I talked about the technique used to create zucchini chips in the Making Use of Those Oversized Zucchinis post. The techniques in that post also work well for vegetables such as eggplant, which has a slight peppery taste when dehydrated. We have found that the American (globe) and Italian eggplants work best for the purpose—the thinner varieties, such as the Japanese eggplant, tend to get tough. There are a lot of different kinds of eggplants, so make sure you choose a variety that will dehydrate well.

Along with eggplant, Rebecca has made dehydrated potato chips for us and I’m sure will try other vegetables as time permits. The same technique used for zucchinis works just find for any globular vegetable that has a moderate level of moisture. You want to be sure that the chips are crispy dry when finished to ensure they have the maximum storage time and have a satisfying crisp feel when chewed. Try to get the chips as evenly sliced as possible. Rebecca used a mandoline for the purpose. I particularly like the Kitchenaid model that she has because it includes a guard to keep her fingers safe and some attachments for additional cutting methods, such as julienne.

It’s also possible to make fruit chips. For example, if you use an apple peeler, you can create spiral cut apples. Cut through the spiral (top to bottom) and you end up with individual apple slices that you can dry as chips. The basic technique for drying apples is the same as zucchini, but there are a few things to consider.

Rebecca dehydrates apples using two flavorings. Of course, the sugar cinnamon combination is a must have selection. Last year she tried using cheese powder on some apples and we liked it so much that it has become the second favorite. The cheese powder makes the apple chips taste like an apple pie with a slice of cheddar on it. In both cases, you must alter the zucchini technique a little to obtain usable results.

The first difference is that you absolutely can’t use a dehydrator with the motor on the bottom. The fruit chips will produce copious amounts of liquid that will get into the motor and cause the premature death of your dehydrator. When drying apples and other fruit, use only a dehydrator with a top mounted motor so that the liquid won’t cause problems. In fact, we highly recommend placing the entire dehydrator on a tray, just to make sure that any liquid that leaks out doesn’t make a mess.

The second difference is that you don’t dip the chips as you might do with vegetable chips. Dust the top of the fruit with the flavoring of your choice. Using this approach makes the resulting product more enjoyable because it isn’t overly sweet (or sometimes bitter). It also reduces the amount of liquid the chips produce as they dry. You get just as much flavor by lightly dusting the top as you would by dipping the fruit, but at a significantly reduced cost. When the fruit produces copious liquid, the extra flavoring you used ends up in the tray anyway, so there is no point in overindulging.

The third difference is that fruit chips tend to a be little flexible when completely dry. They won’t dry crispy like vegetable chips will. Think more along the lines of dried fruit or a fruit leather. So far we haven’t noticed any difference in longevity. The fruit chips will most definitely last a year when kept in an appropriate container.

A number of people have asked how we store our chips to keep them fresh. We use five-gallon-food-grade-buckets with tear tab lids. Make absolutely certain you use food grade buckets because buckets made with other sorts of plastic could contaminate your food. These are the same buckets used by your local restaurant for everything from pickles to potato salad. In order to get the lids off, you must have a bucket lid wrench. Trying to get the lid off otherwise will be difficult to say the least. Even with the wrench, you must work carefully around the lid top to get it off. These buckets seal extremely tight and they provide great storage even in a basement or other less than ideal setting.

Dehydrated food in the form of chips makes for ready, delicious, and nutritious snacks. None of our chips has the slightest amount of oil or preservatives in them. We’ve tested this technique for up to two years with great results. The two biggest considerations are that you must make absolutely certain that the chips are completely dry and that you seal them in an airtight container, such as the five-gallon-buckets we use. Using this approach is also good for the planet because you don’t use any electricity to keep the food usable. Once the food is dehydrated, you simply open the bucket, grab what you want, and eat.

What sorts of vegetables and fruits do you think you might try to store using this approach? Is this an approach that you find appealing? Let me know your thoughts at John@JohnMuellerBooks.com.

 

Potatoes, Buried Treasure

Arr matey! ‘Tis potato season and time to seek buried treasure! Potatoes really are a kind of buried treasure. For one thing, the dried stalk you see above ground only gives you a clue as to the location of the potatoes underneath—not a precise location. The potatoes might be all to one side or another of that stalk, or they might be centered beneath it. I use a garden fork to dig potatoes to reduce the risk of making one unusable. I usually start digging about a foot or a foot and a half from the stalk and move inward.

Unlike many people, we mulch our potatoes instead of creating hills for them. I’ve discussed the benefits of mulching in the Mulching Your Garden post. Using a little heavier mulch makes it possible to plant the potatoes and then basically forget them for the entire growing season. To harvest the potatoes, you simply move the mulch away in the fall and dig the thin layer of dirt from around each of the potatoes. Using the mulching technique seems to produce larger potatoes (or at least, larger quantities of potatoes) with less work and no watering. However, potatoes don’t create set amounts of output. There is an uncertainty factor that gives the potato the feel of buried treasure. One plant may produce a few large potatoes and another copious amounts of smaller (salad) potatoes.

Potatoes and tomatoes are both part of the nightshade family. This family contains a number of highly toxic plants. In fact, some varieties of potato are so odd that you’d hardly recognize them and a few varieties are eaten with clay because they’re not digestible otherwise. The varieties sold in the US are rather bland when compared with the unique diversity found in the Andes (amongst other places). The largest potato we’ve ever had weighed an impressive 1½ pounds, which is far below the 25 pound monster dug in Lebanon in 2008.

You can see the resemblance of potatoes and tomatoes in the leaves. In addition, potatoes will produce a tomato-like fruit. It really does look like a green cherry tomato, but the fruit is quite toxic and you should never eat it. The flowering spud looks pretty though and you should carefully look for the blossoms. They last, at most, two or three days. In other words, blink and you’ll miss the flowering completely.

Domestic potatoes are attacked in a number of ways. This year we lost a few to burrowing insects. The most devastating pests were millipedes who ate directly through the potato and left a rotting mess behind. Because of the drought this year, mice were a particular problem. They normally don’t bother the potatoes much, but this year they were looking for food and water—the potatoes provided both. Quackgrass was also a bit of a problem. We lost some potatoes when the quackgrass roots grew right through the tubers. Finally, some of the potatoes had scabs. The scab ruins the skin and makes it impossible to store the potato for any length of time (otherwise, the potato is perfectly edible as long as you cook it).

Our 20′ × 20′ patch produced two bushels of potatoes this year (about 120 pounds). That’s down from the 3½ bushels we received four years ago in the same patch (we rotate our potatoes between three areas). Between the effects of the drought, the extreme heat this summer, and abundance of pathogens, I think we still did quite well. We managed to get a few really nice sized potatoes with a maximum size of 1 pound this year. Buried treasure indeed!

Do you grow potatoes? If so, how did your potatoes do this year? Do you ever encounter any special problems with them? Let me know at John@JohnMuellerBooks.com.

 

Talking Technical with Non-technical Audiences

Communication has always been key to any sort of technical activity, but the need to communicate efficiently is greater today than ever before. The fact that early developers were successful despite having limited communication skills is more due to the fact that early users were also technical (so they shared the same frame of reference), rather than the superiority of the application environment at the time. In fact, applications are a form of communication specific to computers, but until recently, most developers didn’t view them in that light.

The days of the solo developer working in a darkened room and subsisting on a diet of pizza and soda are gone. Applications today have to appeal to a broad range of people—most of whom have no technical skills and have no desire whatsoever to develop such skills. The complex application environment means that developers must possess the means to articulate abstract coding issues in a concrete and understandable manner to people who view their computers as appliances. In addition, developers now commonly work as part of a team that includes non-developer members such as graphics designers. In short, if you don’t know how to tell others about your ideas and the means you plan to use to implement them, your ideas are likely going to end up on the junk heap. That’s why I wrote, “10 Reasons Development Teams Don’t Communicate” for SmartBear Blog.

The problems that developers experience today have more to do with limited communication skills, than technical ability. It’s quite possible to write amazing applications without developing the skills to communicate the concepts and techniques demonstrated in the applications to others. In fact, the stereotype of the geek is funny, in part, because it has a basis in fact. Schools don’t spend much time teaching those with technical skills how to communicate effectively and the graduates often struggle to understand the basis for miscommunication, even amongst peers. Schools will eventually catch up and begin teaching developers (and other technical disciplines) strong communication skills, but in the meantime, developers and other members of the technical professions will need to rely on articles such as mine to obtain the information needed to communicate clearly.

A successful developer now needs to listen to others actively—to be able to repeat the goals others have for an application in terms that the listener understands. In addition, the developer needs to know how to communicate well in both written and oral forms. The transition between the abstract world of code and the concrete world of the typical user is something that a developer needs to practice because there are no books that adequately address the topic today. To keep costs to a minimum, developers must accomplish communication tasks within a limited time frame and without error. In short, there is a significant burden on the developer today to create an environment in which users, administrators, management, devops, and other interested parties can communicate both needs (required application features) and wants (nice-to-have application features) in a way that the developer can interpret and turn into a functioning application.

What sorts of communication issues have you faced as a developer or other technical specialist? Do you often find that people look at you quizzically and then proceed as if they understand (but you can tell they don’t)? Let me know your thoughts about communication issues at John@JohnMuellerBooks.com.