Category Archives: CSharp

C# coding language

Localizable Balloon Tooltip Control

I wanted to create a tooltip in the style of the balloons used in Windows Phone apps like Messaging. Almost immediately, I realized it needed to be localizable, which would mean adjustable in width to accomodate text lengths in different languages.

In the past I’ve bound XAML elements, such as WPF menus to the ActualWidth of another element, e.g:

Width="{Binding ActualWidth, ElementName=window, Mode=Oneway}"

However, in this case I couldn’t get the desired result, which is to have a bit of padding on either side of the text. What documentation I read suggested that ActualWidth would take into account Margin settings. But I had to resort to a hack in the code-behind, adding a line to the constructor:


public MessageBoxControl()
 {
 InitializeComponent();

TextGrid.Width = MsgText.ActualWidth + 16;
 }

Here’s the XAML:


<UserControl x:Class="Controls.MessageBoxControl"
 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 mc:Ignorable="d"
 FontFamily="{StaticResource PhoneFontFamilyNormal}"
 FontSize="{StaticResource PhoneFontSizeNormal}"
 Foreground="{StaticResource PhoneForegroundBrush}"
 d:DesignHeight="56" d:DesignWidth="440">

<Grid x:Name="LayoutRoot" Background="Transparent" IsHitTestVisible="False" Height="56"
 Width="{Binding ActualWidth, ElementName=TextGrid, Mode=OneWay}" MaxWidth="440">

<Grid.RowDefinitions>
 <RowDefinition Height="32" />
 <RowDefinition Height="24" />
 </Grid.RowDefinitions>

<Grid Name="TextGrid" Background="#FFD68B" Grid.Row="0" MinWidth="200" MaxWidth="440">
 <TextBlock Name="MsgText" Foreground="#2368B0" FontSize="24" Height="32" MaxWidth="424"
 HorizontalAlignment="Center" TextTrimming="WordEllipsis"
 Text="{Binding Path=LocalizedResources.ResetMessage, Source={StaticResource LocalizedStrings}}"/>
 </Grid>

<Grid Grid.Row="1">
 <Path Name="Tail" Fill="#FFD68B" Data="M-1,-1,24,24,24,-1,-1,-1"
 HorizontalAlignment="Left" Width="24" Height="24" Margin="24 0" />
 </Grid>

 </Grid>
</UserControl>

Note that a MaxWidth is assigned to Grid and Text elements. Also, the TextTrimming attribute is set. This is meant to safeguard against exceeding the width of the display in Portrait mode. 

And a sample screen shot of a (hopefully accurate) French translation of “Hold to reset to 0:00”:

balloon_example

Coming around to MVVM

This is a copy-and-paste from an email to a friend, but has a few observations worth sharing publicly

A couple discussions on knockout.js, angular.js and backbone.js:

http://stackoverflow.com/questions/11083316/angular-js-or-knockout-js-integration-with-other-ui-libraries

http://stackoverflow.com/questions/5112899/knockout-js-vs-backbone-js?rq=1

Previously, I didn’t pay much attention to any of these. But am changing my tune. Why? I finally found a way to use the MVVM pattern that really makes sense and plan to follow that when it makes sense with web programming too. Props to Microsoft evangelist Jerry Nixon for his walkthrough video: http://blog.jerrynixon.com/2012/08/most-people-are-doing-mvvm-all-wrong.html, which in particular had some binding tips for Visual Studio I didn’t even know existed and a nice DelegateCommand class.

My initial experience with MVVM was miserable. For one thing, it is incorrectly named…should be MVMV (as in Model – View Model – View). But then, so is MVC, which should be Model – Controller – View. Because in both cases, the View Model or Controller is the code that sits between a UI View and the task-related code, e.g. a method that grabs a bunch of image URLs based on a search term. The MVVM framework I chose to use was complicated and couldn’t handle everything. Lots of hacks went into Ballistica. So, ironically, the promise of better maintainability was so broken that I’ve never found the time to update the app.

I also found that there is a lot of strict adherence to one model per view model. Really a model is just a class file. So if, for example, you need one class that handles status messages and another that build outlines there’s no reason why a single View Model can’t talk to them both. Now that I have that straight and have learned how to use my IDE more effectively, it has made much more sense. My current project has 111 lines of XAML in the main Window (including whitespace), but just 12 lines in its code-behind C# file (including whitespace and curly brackets)…and all it does is launch the window:

using System.Windows;

namespace HorizontalBuilder2
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}

All the controlling logic resides either in the View Model class file or in the model classes.

Here’s an example of XAML that helps explain why Microsoft saw fit to not use SVG:

<MenuItem Command="{Binding BuildOutlinesCommand, Mode=OneWay}" Header="_Build Outlines" InputGestureText="CTRL+B" IsEnabled="{Binding Done, Mode=OneWay}">

<MenuItem.Icon>

<icons:IconGeom />

</MenuItem.Icon>

</MenuItem>

First of all, they could create things like application menus. Then bind various attributes to logical code. In this example, for instance, selecting “Build Outlines” from the menu triggers the BuildOutlinesCommand method. The underscore in front of the Header text allows the user to use ALT-key shortcuts, although I’ve never enjoyed that bit of Windows UI. It’s always just seemed easier to remember something like CTRL-B, which cuts out at least one step, so that’s included. The command is enabled depending on various states of the application. While you can name an item and refer to it in code, e.g. myMenuItem.Enabled = true, one advantage of this way is the menu item is now just a “subscriber” to the Done value. If I had, say, another item on screen like a big “Start” button it to could just use the same snippet. The alternative would be to have to keep track in code of all the items that need to be enabled or not. Also, the programmer can look at the XAML and know where to look in code for what effects the change.

Soon I’ll be posting a nice example of an MVVM app using async Tasks with real-time UI updating…and no freezing the rest of the UI.

Kinda like Regex

So I’ve got this auto-incrementing C# TimeSpan that I need to format to just show single minutes and seconds, e.g. 3:48.

var timeSpan = new TimeSpan(0, 0, 0, secondsElapsed++);

Bugger took a while to figure out because I kept trying things like “m:ss” in my string formatter, not catching on that, just as in a Regex expression, I need to escape the colon. That can be done either by:

var timeStr = String.Format("{0:m\:ss}", timeSpan);

or:

var timeStr1 = String.Format(@"{0:m:ss}", timeSpan);

I find that things like this take longer to figure out not because I don’t know how to do them, but because I have these preconceived notions of how they’re supposed to be done. Ordinarily, a string formatter is very forgiving of input so I expected it to “just work” in a certain way.

On another note, displaying a timer looks much better if you use a mono-spaced font. Otherwise, the number jump around as they change. Since this is being used in a Windows Phone app, I set the text block like this:

<TextBlock Name="TBlockTimerDisplay" TextAlignment="Right" FontSize="36" FontFamily="Segoe UI Mono"/>

THere are a couple other typefaces, such as Courier New, included with Windows Phone, but Segoe UI Mono would be my first choice, since it matches the default typeface for the OS.

Lovin’ Me Some Cheap Libraries

In my MT State Library days, we worked with double metaphone in conjunction with the GNIS placenames data we had. It was remarkably accurate. I see now that the author of that algorithm has a new version, which is available as a C#, C++ or Java library for $40…quite reasonable for what it does. One of the problems I’ve had with open source is that it sometimes precludes decent code from being propagated because the developer has no way to at least receive some modest compensation. On the other hand, I come across insane prices for code libraries all the time.

What I like is something such as this where it makes sense to purchase because it works and it is so cheap. Recently, I paid $35 for a DLL that does datum shifts (moving lat/lon coordinates from one geodetic model to another). The code was available (after much digging) in Java. But I would have spent 3-4X that amount converting and testing it.

No affiliation with this company: http://www.amorphics.com/

Using SMO to Create a Spatial Index

With the advent of ArcGIS 10.1, you can now direct-connect in a read-only fashion to spatial data on SQL Server. That has worked well and while the read-only aspect means no editing, it also means no locks on the data, which is a problem with File Geodatabases. I’ve found that I can programmatically refresh or rebuild a table in SQL Server and just by panning or zooming have ArcMap redraw it. I’d never be able to leave an FGDB open in ArcMap while trying to do the same.

However, I ran into one problem with really large datasets brought into ArcMap. They couldn’t be exported to FGDB or Shape format without a spatial index on the table in SQL Server. Understandable and really it’s better for performance if a spatial index exists. Since it’s an application that creates the tables and populates them, it fell to the application to also create a spatial index.

I could, of course, have used a parameterized SQL command to do this, but since I’m already using SMO to create a tabular index thought I’d try it for a spatial geometry column. Of course, as I soon realized, there’s a catch…one that almost makes it just as well to use parameterized SQL. But if you like being able to specify things like:

 SpatialIndexType = SpatialIndexType.GeometryAutoGrid 

as needed, then there is some case to be made for mixing SMO with SQL…and mix you have to. Because here’s the catch, you can’t create a spatial index if you don’t already know the bounding box (or envelope) coordinates. The only way I know to do this is via a SQL query to the server first. So here’s a code sample:


var serverConn = new ServerConnection("servername");

serverConn.ConnectTimeout = 180;

// provide appropriate login credentials here

var srv = new Server(serverConn);

Database db = srv.Databases["tablename"];
var tb = db.Tables["tableName"];
try
{
 if (db != null)
 {
 // Perform spatial query to get the bounding box
 var sql = String.Format(@"SELECT
 geometry::EnvelopeAggregate(GEOM).STPointN(1).STX AS MinX,
 geometry::EnvelopeAggregate(GEOM).STPointN(1).STY AS MinY,
 geometry::EnvelopeAggregate(GEOM).STPointN(3).STX AS MaxX,
 geometry::EnvelopeAggregate(GEOM).STPointN(3).STY AS MaxY
FROM {0}", "tableName");

var dataSet = db.ExecuteWithResults(sql);

if ((dataSet != null) && (dataSet.Tables.Count > 0) && (dataSet.Tables[0].Rows.Count > 0))
 {
 var boundingBoxXMin = (Double)dataSet.Tables[0].Rows[0]["MinX"];
 var boundingBoxYMin = (Double)dataSet.Tables[0].Rows[0]["MinY"];
 var boundingBoxXMax = (Double)dataSet.Tables[0].Rows[0]["MaxX"];
 var boundingBoxYMax = (Double)dataSet.Tables[0].Rows[0]["MaxY"];
 //spatial index
 var spatialIndex = new Index(tb, "Spatial" + tableName)
 {
 SpatialIndexType = SpatialIndexType.GeometryAutoGrid,
 BoundingBoxXMax = boundingBoxXMax,
 BoundingBoxXMin = boundingBoxXMin,
 BoundingBoxYMax = boundingBoxYMax,
 BoundingBoxYMin = boundingBoxYMin,
 CellsPerObject = 16,
 PadIndex = false,
 CompactLargeObjects = false,
 DisallowPageLocks = false,
 SortInTempdb = false,
 OnlineIndexOperation = false,
 DisallowRowLocks = false
 };

spatialIndex.IndexedColumns.Add(new IndexedColumn(spatialIndex, "GEOM"));

spatialIndex.Create();

return true;
 }
 }
}
catch (Exception err)
{

Debug.WriteLine(err.message)
}

Tripped up by relying on too little data

I was basically copying algorithms over from one project to another, but found I wasn’t getting results. The problem was a number of significant changes were made to the data. So I was looking at some daunting debugging. But then it turned out to be a case of fixing one line of code:


//var coordPattern = new Regex(@"[0-9]+.[0-9]+,[0-9]+.[0-9]+");

var coordPattern = new Regex(@"[-0-9.]+,[-0-9.]+");

The old regex illustrated the pitfalls of working with one particular dataset, in this case spatial coordinates in a UTM projection. Then I switched to Web Mercator. Using that projection, the coordinates now include negative values, such as -10539358.2537, 3394430.3346999986 (space added for ease of reading). I also found that some values don’t include any decimal places. So the new pattern is looser, but still specific enough given what it will be fed.

Using .NET 4.5 Task Async and Await with WPF and SQL Server

Most of the examples I’ve seen of  using the new async, await and Task methods in .NET 4.5 have been aimed at Windows 8 (Metro or “UI Style”) apps. This is understandable, given Microsoft’s push towards both a new OS and to populate the Windows 8 Store. But for some (many?) developers there is also a need to support both Windows 7 and Windows 8 Desktop. Notably missing from the WinRT scenario is the ability to directly connect to SQL Server. I (mostly) get the reasons for that, although it seems against Microsoft’s interests to cede that space to SQLite instead of a sandboxed, light version of SQL Server.

Anyway, I put together a sample WPF application (download below) that supports asynchronous connections to SQL Server. You can cancel or restart the demo query, which populates a ListView with data from the AdventureWorks DB Production.WorkOrder table, which had a decent number of records for testing. I really wanted to simulate some real world conditions, such as server-side delays, so that’s included too. One of my beefs with many of the samples I come across is that they never include decent error handling, especially to accomodate network latency or timeouts. This sample also includes the Microsoft.Data.ConnectionUI SQL Server connection dialog box.

One advantage of making a WPF app asynchronous is it no longer locks up while running a process. Try dragging the window around while the ListView is being populated with data. Yay, no UI-thread blocking!

Clicking the Start button triggers the StartTest method. Notice that in the query, I’ve embedded an artificial server-side delay of 3 seconds – WAITFOR DELAY ’00:00:03′; – which will simulate a slow server return. Also, a queryTimeout has been set to 120 seconds. If you set the WAITFOR delay longer than that, you will see an error occurs and is handled. I did my best to include specific SQL Server error handling so we get actual error details, rather than just “some crap happened and that’s all we know.”


private async void StartTest(object sender, RoutedEventArgs e)
{
try
{
 if (_connectionString == String.Empty)
 {
 var scsb = new SqlConnectionStringBuilder(Settings.Default.DBConnString);

_connectionString = scsb.ConnectionString;

if (_connectionString == String.Empty)
 {
 throw new Exception("Please use Change DB to first select a server and database.");
 }
 }

if (DbInfo.DbName == String.Empty)
 {
 throw new Exception("Please use Change DB to first select a database from the server.");
 }

// Note: If the start test button was disabled, this would be unnecessary
 _cts.Cancel();

// Re-initialize this. Otherwise, StartTest won't work.
 _cts = new CancellationTokenSource();

DataItemsList.Clear();

// Note the simulated delay, which will happen on the DB server. You can vary this to see its effect.
 // Try dragging the window around after hitting the start test button.
 const string query =
 @"WAITFOR DELAY '00:00:03'; SELECT * FROM [Production].[WorkOrder];";

// Note that setting the WAITFOR delay to exceed this, eg. 00:02:01, will trigger an exception
 int queryTimeout = 120;

RequestStatus = "started";

await ProcessQueryCancelleable(_connectionString, query, queryTimeout, _cts.Token);
}
catch (Exception ex)
{
 MessageBox.Show(ex.Message + " (from StartTest)");

Debug.WriteLine(ex.Message);
}
}

The ProcessQueryCancelleable method. Note the use of the CancellationToken…’cause users might actually want to cancel a long-running query. Inside this method is another simulated delay (await Task.Delay(TimeSpan.FromMilliseconds(1));):

/// <summary>
/// Runs a cancelleable query
/// </summary>
/// <param name="connectionString">SQL Server connection string</param>
/// <param name="query">SQL query</param>
/// <param name="timeout">SqlDataReader timeout (maximum time in seconds allowed to run query). Note: Try varying this in conjunction
/// with the WAITFOR DELAY in the SQL query, e.g. make it shorter than the WAITFOR or maybe a second longer</param>
/// <param name="cancellationToken">Allows cancellation of this operation</param>
/// <returns></returns>
private async Task ProcessQueryCancelleable(string connectionString, string query, int timeout,
 CancellationToken cancellationToken)
{
 // await Task.Delay(TimeSpan.FromSeconds(5));

try
 {
 // Keep sqlConnection wrapped in using statement so disposal is handled automatically
 using (var sqlConnection = new SqlConnection(connectionString))
 {
 await sqlConnection.OpenAsync(cancellationToken);

using (SqlCommand cmd = sqlConnection.CreateCommand())
 {
 cmd.CommandTimeout = timeout;

cmd.CommandText = query;

using (SqlDataReader dataReader = await cmd.ExecuteReaderAsync(cancellationToken))
 {
 while (!dataReader.IsClosed)
 {
 // While the dataReader has not reached its end keep adding rows to the DataItemsList
 while (await dataReader.ReadAsync(cancellationToken))
 {
 // Process dataReader row
 WorkOrder workOrder = GetWorkOrderFromReader(dataReader);

DataItemsList.Add(workOrder);

// Another simulated delay...this one internal
 await Task.Delay(TimeSpan.FromMilliseconds(1));
 }

if (!dataReader.NextResult())
 {
 dataReader.Close();
 }
 }

Debug.WriteLine("done with reader");

RequestStatus = "finished";
 }
 }
 }
 }
 catch (SqlException sqlEx)
 {
 Debug.WriteLine(sqlEx.Message);
 }
}

Download C# Project (an MDF with just the WorkOrders table is included)