Wednesday, November 11, 2009

Designing Applications for the Occasionally Connected Scenario – NUFW Presentation

The presentation slides from my presentation at NUFW last night are below. It’s not much value without the demo’s and audio except for the links which I used to research and debug while creating the demo application. I have the presentation audio and may turn it into a webcast at some point in the future.

Wednesday, October 28, 2009

Using Local Database Cache for Occasionally Connected Data Synchronizing

After getting everything setup using the Visual Studio template and configuration wizards, I found that the server table was not being updated during the synchronization. Using SQL Server Profiler, I could see the SELECT queries that were interrogating the server instance to see if there were changes on the server, but I saw no indication of UPDATE or INSERT statements. I ran across a helpful blog post http://videoworld-rong.blogspot.com/2009/10/adonet-sync-services.html that indicated the default behavior of the Sync process is DownloadOnly where changes to the central database are downloaded to the local cached database. A simple change to OnInitialized event in the code-behind file of the .sync file resolved that issue easily.

   1: Private Sub OnInitialized()
   2:  ' ProductionHistoryDetail is
   3:  ' the name of the cached table
   4:  Me.ProductionHistoryDetail.SyncDirection = _
   5:     Microsoft.Synchronization.Data.SyncDirection.Bidirectional
   6:  
   7: End Sub

There were two other issues to overcome:



  1. While testing what would happen if the database was taken offline between synchronization, I found that the .Net SQLClient Data Provider connection that the sync framework provider was using would block the process where the command was issued to set the database offline (ALTER DATABASE <databasename> SET OFFLINE).
  2. Once the database went offline, the application would throw an exception when it attempted to connect to the server database to synchronize with the local SQL CE 3.5 database.

Solution:



  1. ?? Still investigating.
  2. Wrap the call to syncAgent.Synchronize() in a try/catch block. Surely there are methods to determine ability to connect to the db more efficiently than catching an exception.

Tuesday, October 27, 2009

Local Database Cache – Cached Table Add Button Grayed Out

I was experimenting with adding a Local Database Cache to a WPF client app I was working on when I ran into a situation where I could not configure the Cached table. There are a number of tutorials for how to set up the local database cache so I won’t go into much about those details except a brief introduction and where my experience differed.

The local database cache uses the Microsoft Synchronization Framework to synchronize tables between a local SQL Compact Edition .sdf file with a standard SQL Server database which is a really powerful feature for those occasionally connected scenarios. Visual Studio 2008 has a project template to make the process painless. See the photo below.

local database cache VS template

The step in the process that slowed me down was the point where you set connection to the client and server databases, then select the tables you want to keep synchronized. On my screen, the “Add” button below the Cached Tables list box was grayed out as in the following illustration.

local database cache table selection screen

After considerable searching and retries, I found a that I had neglected to set the primary key in the table I wanted to synchronize. I configured it as an Identity column, but forgot the click the key button in the SSMS table designer on the “Id” field. After correcting that, the “Add” button was no longer disabled on the table selection.

local-data-cache1

Monday, October 26, 2009

Code-behind Number Format Reference

This post is to save me some time looking up the format reference for some of the things I find myself looking up every once in a while.

Formatting numbers for display like minutes and seconds to have the preceding zero when the number is less than ten (10) as you would see on a digital clock or stopwatch display.

example: [3:07:10]

   1: ' format integers to have preceding zero if 
   2: ' integer is less than 10 (as in a digital
   3: ' clock or stopwatch display)
   4: ' tsElapsed is a TimeSpan
   5: ' lblElapsedTime is a WPF Label
   6: lblElapsedTime.Content = _
   7:     String.Format("{0}:{1}:{2}", _
   8:     tsElapsed.Hours, _
   9:     tsElapsed.Minutes.ToString("0#"), _
  10:     tsElapsed.Seconds.ToString("0#"))

Tuesday, October 20, 2009

NullReferenceException on String.IsNullOrEmpty in WPF

I really like the power of what can be done in WPF, but every time I turn around there is some trivial thing that gets in my way of being productive. This time it is a NullReferenceException being thrown when I do a String.IsNullOrEmpty check on the Label text (Content) in a button click event.

   1: If PlayButtonText = "Play" Then
   2:    SetValue(PlayButtonTextProperty, "Pause")
   3:    ' NullReferenceException thrown on following line
   4:    If String.IsNullOrEmpty(lblStartTime.Content.ToString) Then
   5:       lblStartTime.Content = DateTime.Now
   6:    End If
   7:    myTimer.Start()
   8:  
   9: Else
  10:    SetValue(PlayButtonTextProperty, "Play")
  11:    myTimer.Stop()
  12: End If

A similar bug was first reported in 2006 .Net 2.0 when used in a loop in a console app with an empty construct, and was subsequently fixed. It seems odd that I would experience a similar bug (or feature, if that is what it would be classified as) that has yet to be fixed as of .Net 3.5 SP1 in Visual Studio 2008. My usage above does not seem to be that uncommon.


Workaround


Replace the Label control with a TextBlock control, obviously replacing the lblStartTime.Content property with lblStartTime.Text property since there is no Content property on the TextBlock control.


Josh Smith wrote a good blog post explaining the differences between a WPF Label control vs. a TextBlock control.

WPF Binding app.config settings in XAML

I tried several different syntaxes for exposing an app.config MySettings property (VB.Net, not C#) for databinding in the XAML. I was met with several compile and/or designer load errors like:

  1. could not create an instance of type StaticExtension
  2. ‘MemberReferenceSerializer’ ValueSerializer cannot convert from ‘System.String’
  3. A TwoWay or OneWayToSource binding cannot work on the read-only property of ‘TargetShiftCount’ of type PacingChart.MySettings

The databinding syntax that worked was:

   1: <Window x:Class="Window1"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:p="clr-namespace:PacingChart"       
   5:     Name="window1"
   6:     Title="Pacer" Height="300" Width="300">
   7:     <Grid>
   8:         <TextBox Text="{Binding Source={x:Static p:MySettings.Default}, Path=TargetShiftCount, Mode=OneWay}" Name="txtShiftTarget" Margin="126,111,32,128"   />
   9:     </Grid>
  10: </Window>

On code snippet line 3, note the clr-namespace:<project root namespace> where <project root namespace> is PacingChart in this example. It did not work in my project with clr-namespace:PacingChart.Properties as some examples suggested. Those examples also indicated that the binding source should be "{Binding Source={x:Static p:Settings.Default}, Path=TargetShiftCount}". Using p:Settings.Default, not the p:MySettings.Default which worked in my example. Also note the lack of the Mode=OneWay attribute which caused the third error message listed above.


Most of the examples I attempted to follow were from people who asked the question about the correct VB.Net syntax, but the people responding were documenting the C# syntax. The Properties.Settings (in C#) and My.Settings (in Visual Basic) are helper classes. It is important to understand the syntax differences. In the VB.Net codebehind, you would access the settings using the syntax My.Settings.TargetShiftCount where in the XAML, you would use the MySettings class.


For completeness, I created the app.config property settings by double-clicking the “My Project” entry in the Solution Explorer and switching to the “Settings” tab, which created the following snippet in the app.config file.



   1: <applicationSettings>
   2:     <PacingChart.MySettings>
   3:         <setting name="TargetShiftCount" serializeAs="String">
   4:             <value>200</value>
   5:         </setting>
   6:     </PacingChart.MySettings>
   7: </applicationSettings>

Wednesday, September 30, 2009

Easily Add External I/O to Custom Software – Keyboard Encoder Modules

Arcade Game photo by Robin Norman - Stock Exchange user: otto_taroEver have the need/desire to be able to have your software  interact with a hardware input device other than a mouse or keyboard? Using a Keyboard Encoder Module and a little creativity you can take the input of something like an industrial switch, button, or Programmable Logic Controller (PLC) output and read it in your program as if it were a keystroke from a keyboard. This technique has been in use for a long time by arcade game manufacturers (think joystick and buttons). The devices are relatively reliable, but even if they fail, they are inexpensive and easy to replace.
I used the KE24 Keyboard Encoder Module from Hagstrom Electronics, but due to the declining availability of PS/2 style miniDIN connectors in PC’s, the KE-USB24 would probably be an acceptable choice.
Quick VB.Net code for a Windows Form to check which keystroke was pressed:
   1: ' a constant representing the keystroke value 
   2: ' mapped to a button press. In this example, the F5 key

   3: Dim keyActCounterIncrement as String = "116" 
   4:  
   5: Protected Overrides Function ProcessCmdKey( _
   6:              ByRef msg As System.Windows.Forms.Message, _
   7:              ByVal keyData As System.Windows.Forms.Keys) _
   8:              As Boolean
   9:  
  10:         ' get the key map data
  11:         Dim strKeyData As String = CStr(keyData)
  12:         
  13:         ' The key was pressed to increment a piece part counter.
  14:         If keyData = keyActCounterIncrement Then
  15:             DoSomethingLikeIncrementACounter()
  16:             Return True
  17:         End If
  18: End Function

Here’s a good key translation chart for reference.

[updated 10/19/2009 to add WPF code snippet]
XAML:

   1: <Window x:Class="Window1"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     Title="Pacer" Height="300" Width="300">
   5:     <Grid>
   6:         <TextBox Height="23" Margin="126,74,32,0" Name="txtActCounter" VerticalAlignment="Top" />
   7:         <TextBlock Height="21" Margin="51,77,0,0" Name="lblActCounter" VerticalAlignment="Top" Text="Actual Count" HorizontalAlignment="Left" Width="77" />
   8:     </Grid>
   9: </Window>


   1: Class Window1 
   2:     Private intActCounter As Integer = 0
   3:     Private Sub Window1_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded
   4:         ' register an event handler to intercept the keyboard input
   5:         EventManager.RegisterClassHandler(GetType(Window), _
   6:             Keyboard.KeyUpEvent, New KeyEventHandler(AddressOf KeyUpCapture), True)
   7:         ' set a textbox counter to zero
   8:         txtActCounter.Text = intActCounter.ToString
   9:     End Sub
  10:     Private Sub KeyUpCapture(ByVal sender As Object, ByVal e As KeyEventArgs)
  11:         ' if keypress is F5
  12:         '   do something
  13:         If e.Key = Key.F5 Then
  14:             ' increment counter
  15:             intActCounter += 1
  16:             ' update textbox to counter value
  17:             txtActCounter.Text = intActCounter.ToString
  18:  
  19:         End If
  20:  
  21:     End Sub
  22: End Class
There are a few considerations to using this method:
  • It is a low voltage, low current “dry contact” device, but you still might want to consider soliciting the help of an electrician/controls engineer to wire it up to make sure you don’t fry your new “toy”, your PC, yourself, or another unsuspecting bystander
  • It is a low voltage device so the wiring between the keyboard encoder module and the input device needs to be located in close proximity (i.e. minimal wire length). If you need more distance, I recommend wiring the field device to an industrial dry contact relay bank and locating the relay bank in close proximity to the keyboard encoder module.
  • You probably want to map the inputs to keys, or combinations of keys that are not typically used in normal typing, like the tilde (~), so as not to inadvertently register text actually typed from the keyboard as inputs from the keyboard encoder module.

Thursday, August 20, 2009

Unlink height and width scaling in Expression Design

Sometimes the simplest things can be the most aggravating. I wanted to change the width of an object without changing the height, but I wanted to do it by the numbers not the drag handles. Every time I typed in the new width, the height changed proportionately. It took me a while to notice the “unlink” icon in the bottom toolbar between the height and width setter textboxes. Like magic clicking the icon allows independent adjustment of height and width of the selected entity.

Unlink height and width settings

Monday, July 27, 2009

WPF controls not showing a state change

I created a dependency property in the code behind to enable/disable a button during processing.wpf code-behind

In the XAML, I bound the IsEnabled property to the dependency property. XAML button binding

The button wasn’t showing the state change. Don’t forget to add the Name property to the window or the property won’t show the state change. XAML window name

Thursday, July 16, 2009

Encoding Media with Expression Blend and Encoder 2 SDK

This week I presented for the Fort Wayne .Net Users Group (NUFW). There were about ten people in attendance and the presentation lasted about one and a half hours with an Encoder GUI walkthrough and two demos. The Power Point presentation and source code can be downloaded here. The theme of the main Demo was ZooTube a simple WPF app to encode media with an Intro and an in-video watermark (screenshot of app is below the video). The code was based on the VB sample code that is included in the Encoder 2 SDK download. The finished video is shown below.
zootube wpf app screenshot

Wednesday, July 8, 2009

LINQ Query Samples in VB

Sometimes what you are looking for is right in front of you. There are a lot more samples of LINQ query syntax in C# than VB.Net and the syntax is enough different that it often requires a sample snippet to get it right in all but the simplest queries. I rarely use the Visual Studio snippets when programming so I didn’t even think to look there for LINQ snippets, but they are there. Just right click in the source window, “Insert Snippet”, “Data – LINQ, XML, Designer, ADO.Net”, “LINQ Queries”.

Wednesday, May 27, 2009

Smiling and Profiling – Potpourri of Profiler Utility

Last night I presented for the Fort Wayne chapter of PASS (Professional Association for SQL Server). You can download the presentation titled Smiling and Profiling - A Potpourri of Profiler Utility. The meeting was held in downtown Fort Wayne at the Pint and Slice in their spacious upstairs meeting area. It was a small group, but that always promotes great conversation.

Thursday, April 16, 2009

Open IIS hosted Visual Studio project on a box without IIS

I recently experienced an occasion to open a project created in Visual Studio 2008 SP1 configured to use IIS on a different box that did not have IIS installed. The project would not open and a message box indicated it was because IIS was not installed on the machine. The problem was easy to solve, but it required making a manual edit to the vbproject file.

The quick fix was to create a new Web Application project on the workstation without IIS, open the <project_name>.vbproj file in Wordpad or another editor and copy the XML between the <WebProjectProperties> tags.

   1: <WebProjectProperties> 
   2:           <UseIIS>False</UseIIS> 
   3:           <AutoAssignPort>True</AutoAssignPort> 
   4:           <DevelopmentServerPort>1159</DevelopmentServerPort> 
   5:           <DevelopmentServerVPath>/</DevelopmentServerVPath> 
   6:  
   7:  
   8:           <IISUrl> 
   9:           </IISUrl> 
  10:           <NTLMAuthentication>False</NTLMAuthentication> 
  11:           <UseCustomServer>False</UseCustomServer> 
  12:           <CustomServerUrl> 
  13:           </CustomServerUrl> 
  14:           <SaveServerSettingsInUserFile>False</SaveServerSettingsInUserFile> 
  15:         </WebProjectProperties>
  16:  

Open the <project_name>.vbproj file of the project that would not open without IIS and paste the copied XML into the appropriate place in the file. Voila! The project can now be opened on the PC without IIS installed.



Technorati Tags:

Wednesday, February 4, 2009

Application Deployment – Ask the Right Questions

Not too long ago we deployed a web-based application using SQL Server to one of our clients. Initially the users were disappointed by the seemingly terrible performance. The database was a SQL Server 2000 database because that was a corporate standard at the time of deployment. All the testing in the development environment, production test environment, and Virtual PC test environments exhibited acceptable performance.

Appropriate Indexing strategies were used on the database tables. Queries were evaluated and tuned. We had other applications we created that were deployed to their servers with architectural similarities and no performance related concerns. We had no direct access to their servers to do more sophisticated performance testing and profiling which would have made the troubleshooting effort more efficient.

After making a slight change to a few similar queries to further improve the dismal performance, a slight indication surfaced that something was wrong. The query returned different results on the customer’s server than all of the test instances. Why? Was it old data that was cached in the web-browser? Was there a version control issue with other tables, views, or stored procedures? Nope.

I asked the Sys Admin to check the SQL Server Edition and It was the RTM edition. Since MSSQL 2000 RTM edition there were 4+ Service Packs released that were not applied. I loaded up the RTM version on a Virtual PC and sure enough, I got the same incorrect results. The Sys Admin updated to SP4 and the performance immediately improved by orders of magnitude.

The moral of the story, sometimes some of the things we take for granted, like Service Pack updates, should be included on the pre-deployment or pre-development checklist.