Automatically Increment Minimum Required Version in a ClickOnce Application

Introduction

ClickOnce deployments make publishing .NET applications simple and easy. One nice feature is forcing the user to update to the latest available version. This can be very important on sensitive applications that require any potential fixes or patches to be immediately sent to the users.

One way to do this is to set the minimum required version on the publish page to the current version. ClickOnce then knows to automatically download the latest version whenever a user goes to run the application. The problem with this can be that you have to remember to increment the value every time you do a publish. This post will make life easier by automating the increase of the minimum required version every time you preform a publish.

We’ll do so by adding an MSBuild event to the project. This post assumes you don’t have any experience with MS build and will introduce you to the relevant concepts; if you’re already familiar with that, feel free to jump ahead to Step 6 and copy and paste the code into your .proj file.

Introduction to Project Editor

1) First, in solution explorer, right click on your project and select unload project

2) Once the project has become unavailable, right click again and select edit [project_name].csproj

  • Note: This unlocks full set of IntelliSense of all the MSBuild features

Introduction to MS Build

3) MS Build notation uses properties with key/value pairs to extract information. We’ll use the notation $(key) in the implementation section to reference the .proj elements in Step 4.

  • ex. Using the property name as an alias, you can use $(OutputPath) to obtain the value for the element <OutputPath>.\bin</OutputPath>. So in this case $(OutputPath) = .\bin

4) We’ll use the following properties generated for a ClickOnce deployment

<MinimumRequiredVersion>1.0.0.6</MinimumRequiredVersion>  
<ApplicationRevision>7</ApplicationRevision>  
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>  
  • The ApplicationVersion element specifies the build number. The last value of %2a is set by Visual Studio when the option to “Automatically increment revision with each publish” is checked on. In that case, it substitutes the %2a placeholder with whatever value is in the ApplicationRevision element
  • The MinimumRequiredVersion element is what we’d like to set with each publish so that it automatically increments as well.

5) MSBuild Tasks can be specified in the .proj file and invoked during a build event.

  • FormatVersion is a built-in task for .NET 4.0 and later that formats the ApplicationVersion and ApplicationRevision into a single version number

Implementation

6) Copy and Paste the following code into the opened project file as a child element to the root <Project> element:

<Target Name="AutoSetMinimumRequiredVersion"
        BeforeTargets="GenerateDeploymentManifest">
  <FormatVersion Version="$(ApplicationVersion)" 
                 Revision="$(ApplicationRevision)">
    <Output PropertyName="MinimumRequiredVersion" 
            TaskParameter="OutputVersion"  />
  </FormatVersion>
  <FormatVersion Version="$(ApplicationVersion)" 
                 Revision="$(ApplicationRevision)">
    <Output PropertyName="_DeploymentBuiltMinimumRequiredVersion"
            TaskParameter="OutputVersion"  />
  </FormatVersion>
</Target>
  • This code will take ApplicationVersion and ApplicationRevision as parameters in the Format Version task and will save the output by overwriting the MinimumRequiredVersion with the full publish version

7) Save and reload your project. Every ClickOnce deployment will now automatically update without a prompt with the ability to skip.

Making Sure Outlook Calendar Reminders Actually Pop-up in Windows 7

Introduction

In Windows 7, MS Outlook seems to be horribly bad at popping up calendar reminders when outlook doesn’t have focus. This can cause a series of problems from minor annoyances to missed meetings. As discussed in this StackExchange question, there are some relatively easy work arounds to this issue that I’ll elaborate on here. If you’ve never used Outlook’s VBA editor to extend it’s capabilities before, this article will take you through how to set up everything you’ll need to do, start to finish. If you’re already familiar with using VBA in Outlook, then you can just skip to Step 5 and paste in the code and you’ll be all set.

Step By Step

  • 1) Hit the Windows Key and type “certificate”
  • 2) Select Digital Certificate for VBA Projects and type in a name for your certificate and hit OK
  • 3) Open Outlook 2010 and Hit Alt + F11 to start the VBA editor
  • 4) In the Project Pane on the left, Expand Project1 > Microsoft Outlook Objects > and double click on ThisOutlookSession
  • 5) Paste in the following code exactly:
'ensures all reminder notices receive focus
Private Sub Application_Reminder(ByVal Item As Object)
    If TypeOf Item Is AppointmentItem Then
        Application.ActiveWindow.Activate
    End If
End Sub

Edit: Added New Better Code Below:

'Declare Functions From User32 Library  
Private Declare PtrSafe Function FindWindowA Lib "user32" _  
        (ByVal lpClassName As String, _  
         ByVal lpWindowName As String) As Long  
Private Declare PtrSafe Function SetWindowPos Lib "user32" _  
        (ByVal hwnd As Long, _  
         ByVal hWndInsertAfter As Long, _  
         ByVal X As Long, _  
         ByVal Y As Long, _  
         ByVal cx As Long, _  
         ByVal cy As Long, _  
         ByVal wFlags As Long) As Long  

'Declare Constants  
Private Const SWP_NOSIZE = &H1  
Private Const SWP_NOMOVE = &H2  
Private Const FLAGS As Long = SWP_NOMOVE Or SWP_NOSIZE  
Private Const HWND_TOPMOST = -1  

'Only show the message the first time  
Private messageAlreadyShown As Boolean  

'Finds Reminder Window and Brings to TopMost position  
Private Sub Application_Reminder(ByVal Item As Object)  
    On Error Resume Next  

    'show message box for first reminder  
    If Not messageAlreadyShown Then  
        MsgBox "First Reminder", vbSystemModal, ""  
        messageAlreadyShown = True  
    End If  

    'find reminder window  
    ReminderWindow = FindWindowA(vbNullString, "1 Reminder")  
    'bring reminder window to front  
    SetWindowPos ReminderWindow, HWND_TOPMOST, 0, 0, 0, 0, FLAGS  
End Sub 
  • 6) Sign the Macro by going to Tools > Digital Signature and clicking Choose
  • 7) Select the certificate you created earlier and hit OK
  • 8) Select OK again, hit Ctrl + S to save and exit the VBA window
  • 9) To Enable Macros, Go to File > Options and select Trust Center from the left window
  • 10) Run the Trust center by clicking the Trust Center Settings button on the right.
  • 11) From the Trust Center, select Macro Settings, and select “Notifications for digitally signed macros, all other macros disabled” and hit OK
  • 12) Exit Outlook - It will ask you if you want to save the project, click Yes
  • 13) Start Outlook - It will give you a security notice. Select “Trust all documents from this publisher” (You can first confirm that you are the publisher by selecting “Show Signature Details”)
  • 14) That’s it! You’re all set. You never have to touch any of that code again or miss another meeting (unintentionally)

UPDATE!

I’ve update the code to use ActiveWindow instead of ActiveExplorer, which returns nothing “if no explorer is active.” Thanks to CW for the impetus to update my code.

Mutually Exclusive Checkboxes with JQuery

The Problem

Let’s say you want to have a set of mutually exclusive check boxes and want to implement that logic on the client so that the user can get immediate, responsive feedback about their selection choices. Normally, mutual exclusivity would be enforced with radio buttons ensuring user familiarity with the interface selections. However, in this specific case, let’s suppose that within a specific sub category, a user can select as many options as they want, but cannot select options from more than one subcategory. Imagine setting contact preferences as either No or some type of Yes. Or perhaps there is a Online food order form where certain topping choices are mutually exclusive between categories.

Solution

You can bind JQuery to the click event of your checkboxes and use that event to ensure that checkboxes in any other groups are set to checked=false.
First group each distinct set of checkboxes inside a set of <div></div> tags:

<div id="opt1">  
  <input id="a" type="checkbox">  
  <input id="b" type="checkbox">  
</div>  

We can monitor for clicks to any of the child items inside of the div tag, by using it’s ID as our initial selector $('#opt1') and looking for a Click event on that div. This will fire when any element inside of that div tag is clicked.

Next, we’ll check if the event that fired the event has a checked property set to true, by chekcing if (event.target.checked). This will prevent clicks on the label from processing our code or de-selections in a particular category from running un-neccessary code.

Finally, we’ll want to go through all check box categories and remove any check marks from any checkboxes that they contain. To do this, we’ll first start by selecting the ID from an alternate div tag. Then we’ll call find('input') to find all child items of type Input. To each of these items, we’ll call removeAttr('checked') to remove the checked attribute from each one.

$('#yes').click(function (event) {  
  if (event.target.checked) {  
    $('#no').find('input').removeAttr('checked');  
  }  
}); 

Source Code

Handle Text Change In Selected Index Changed Event

The Problem

You may have noticed that .NET won’t let you change the Text value of a ComboBox during the SelectedIndexChanged event. This can be quite frustrating and difficult to work-around if you have want to update the ComboBox text during a when the user makes a selection. For example, you might want to back out of a bad user selection or bind each selection item with different formatting when selected. Let’s clear up a couple things that will help us understand why .NET prevents us from doing what seems like a reasonable default functionality, and then we’ll show one way to workaround this limitation.

Understanding the System.Windows.Forms.ComboBox

When you select an item from a combo box, the SelectedIndex property of the ComboBox changes to the index location of the item you selected. The ComboBox Text property is automatically updated to the display value of the item at the specified index. This is the only update to the ComboBox Text that is allowed by default. To understand this, let’s look at another out-of-the-box ComboBox behavior.

If you have a ComboBox populated with the following items:

  1. Red
  2. Blue
  3. Green

Let’s say the current SelectedIndex value is -1 and the current Text value is Select a color...

If in our code we change the value of the Text to blue:

ComboBox1.Text = "Blue"

Then .NET will automatically recognize that this matches an item in our collection and change the SelectedIndex value to 2, thereby also firing the SelectedIndexChanged event. The reason .NET won’t let you change the Text property during a SelectedIndexChanged event is because they are worried about creating an endless loop by firing another SlectedIndexChanged event.

The Solution

We can resolve this relatively easily by invoking a delegate during the selection changed event that will eventually change the text property. We’ll load a generic WinForms window by adding two items to a ComboBox, one of which we want to reset the form when selected. This item represents a selection that may or may not be invalid, but is expensive to figure out, so we don’t want to necessarily evaluate it early and remove it from the list before the user has a chance to select it.

We’ll start by declaring a Delegate Sub within our class. The only important thing about a Delegate is the method signature that you are passing in. Since we want to call the ResetComboBox method which contains on parameters, our Delegate will not contain any arguments as well.

On the SelectedIndexChanged event, we’ll call BeginInvoke and specify that when it invokes, it should look to a method at the AddressOf ResetComoboBox.

'Declares a delegate sub that takes no parameters  
Delegate Sub ComboDelegate()  

'Loads form and controls  
Private Sub LoadForm(sender As System.Object, e As EventArgs) _  
 Handles MyBase.Load  
 ComboBox1.Items.Add("This is okay")  
 ComboBox1.Items.Add("This is NOT okay")  
 ResetComboBox()  
End Sub  

'Handles Selected Index Changed Event for combo Box  
Private Sub ComboBoxSelectionChanged(sender As System.Object, e As EventArgs) _  
 Handles ComboBox1.SelectedIndexChanged  
 'if option 2 selected, reset control back to original  
 If ComboBox1.SelectedIndex = 1 Then  
  BeginInvoke(New ComboDelegate(AddressOf ResetComboBox))  
 End If  

End Sub  

'Exits out of ComboBox selection and displays prompt text   
Private Sub ResetComboBox()  
 With ComboBox1  
  .SelectedIndex = -1  
  .Text = "Select an option"  
  .Focus()  
 End With  
End Sub  

You’ll notice that when ResetComboBox is eventually called by the delegate, it will also fire the SelectionChanged event when we change the SlectedIndex to -1. If there’s a chance that you’re handling anything in the change event that could cause a repetitive loop, you can include a private cancelAction boolean property in your class, defaulted to False. Then when you start the ResetComboBox method, set cancelAction to True and reset it to False at the end of method. In the selection changed event, exit the sub if cancel action will set and you will never accidentally execute code when you’re resetting controls

If cancelAction Then Exit Sub

Source Code

You can find the source code for this application from SkyDrive. Please comment with any suggestions or questions

Firing The DataGridView CellValueChanged Event Immediately

Intro

Let’s say you have a list of things displayed in a DataGridView and you want a user to be able to select among them on a DataGridViewCheckBoxColumn. Further, let’s say that you’d like to know as soon as the user has made a change to their selection. You might want to handle this for a number of reasons: to enable a save button, to change the appearance of selected items, to display a pop-up window, or to check for consistency against other choices. It turns out that this is trickier than it might seem and doesn’t work great out of the box from .NET, but, not to fear, there are several easy work-arounds that will get the trick done.

The Problem

'This won't fire until the cell has lost focus
Private Sub DataGridCellValueChanged(sender As DataGridView, 
                                     e As DataGridViewCellEventArgs) _ 
        Handles DataGridView1.CellValueChanged
 IsDirty = True
End Sub

When you click a CheckBox in a DataGridViewCheckBoxColumn, the check marker will update immediately, but CellValueChanged event on the DataGridView will not fire until the user happens to click elsewhere and the cell has lost focus. Why? Well, the DataGridView thinks it’s a little preemptive to go declaring that the cell value has changed while you are still selected on it. This makes more sense when we think about a TextBox column. We would not want the CellValueChanged event firing every single time a letter was added to a person’s last name. Still, it doesn’t make much sense when we think about the way CheckBox’s work, in that, they can only ever be On or Off, and that once you have made your selection, you’re probably pretty confident that you want to change the value. Any solution is going to involve using an event that definitely will fire to stop the DataGridView from thinking it’s in edit mode.

The Solution

This problem was also raised in a StackOverflow Question which seemed to advocate for handling the MouseUp event on the DataGridView and then call the EndEdit method, thereby ensuring that the grid would evaluate whether or not the Cell’s value had, indeed, changed and fire the corresponding event appropriately I must admit, this works, but feels like more of a work around than a solution. What if someone is able to make a selection without a click event? There seems to be a non-zero percent chance that this might fire incorrectly in some unforeseen situation. I’d rather code to do exactly what it says it’s doing.

We could also handle the DataGrid’s CellContentClick event. This has the added bonus of not firing when you have clicked outside of the checkbox area, but still falls perhaps under the same category of not being entirely clear to someone unfamiliar with this issue why this particular event should force the grid to exit edit mode.

After looking into the problem at some length, MSDN actually seems to offer the best solution right on their CellContentClick event page. Here’s a cleaned up version:

'Ends Edit Mode So CellValueChanged Event Can Fire
Private Sub EndEditMode(sender As System.Object, 
                        e As EventArgs) _
            Handles DataGridView1.CurrentCellDirtyStateChanged
    'if current cell of grid is dirty, commits edit
    If DataGridView1.IsCurrentCellDirty Then
        DataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit)
    End If
End Sub

'Executes when Cell Value on a DataGridView changes
Private Sub DataGridCellValueChanged(sender As DataGridView, 
                                     e As DataGridViewCellEventArgs) _
            Handles DataGridView1.CellValueChanged
    'check that row isn't -1, i.e. creating datagrid header
    If e.RowIndex = -1 Then Exit Sub

    'mark as dirty
    IsDirty = True
End Sub

In the code sample above, we monitor the CurrentCellDirtyStateChanged event. I like that it tells us very specifically what has happened to the grid at the point in time when the event is raised and handled. It’s important to note that this event will get called twice, once on changing the state of the cell to dirty (before committing changes) and once when changing the cell state back to ‘clean’ (after the changes have been committed). For this reason, before preforming any action, it checks to see when the current cell is dirty or not. If it is, it’ll call the CommittEdit method and pass in the DataGridViewDataErrorContexts enumerator type of Commit

Sample / Source Code

I worked up what I hope to be an interesting sample of the different methods by which we can get the CellValueChanged event to eventually fire.

The form loads by default to only handle the CellValueChanged event itself, which means we will immediately notice the problem at hand. Changing the active status for a given person will not fire the event until some other object on the form is clicked and receives focus. Anytime a grid event is handled, a notification will pop-up and fade out. This helps identify when, and in what order, events are being handled without explicitly having to set breakpoints and wait for the code to catch each event.

In the options group box, you can choose to include event handlers notifications or not. Also, the drop down list will add / remove handlers so you can easily test out which handlers do what without having to specifically comment out lines of code.

You can download the mini application and the source code for this demo on SkyDrive or by clicking the icons below: