Extending the glass section for our wizard
[More]
Been a while since I've had one of these but here we go...
public DataObject MethodX(Guid requestGuid, bool returnError)
{
Thread.Sleep(1000); // <Person who has left>: Temporary Fix for this build as discussed
return MethodXList(requestGuid, returnError);
}
My favourite part, I now know he's discussed this with somebody else. So its prefectly valid to go round the entire dev team and ask if this code makes any sense to anyone.
In a “QI” format this time. Spot the problem in the following code.
1 point for the correct problem. -5 points for going for the obvious mistake.
2 points for the correct solution.
P.S. No its not my code
[Flags()]
public enum EntityComparisonMode
{
/// <summary>
/// All values are converted to System.String and tested using [StringComparison.Ordinal]
/// </summary>
CaseSensative = 1,
/// <summary>
/// All values are converted to System.String and tested using [StringComparison.OrdinalIgnoreCase]
/// </summary>
CaseInsensative = CaseSensative << 1,
/// <summary>
/// NULL and String.Empty values will be equal.
/// </summary>
IgnoreNull = CaseInsensative << 1
}
Use the following
SELECT Doc.value('data((/OrganisationAccountOpeningForm/KYCCustomer/EntryDate)[1])','datetime')
or syntactically
SELECT <XML Column Name>.value('data((/<XPATH>)[<1-based index into possible values returned>])','<Format to convert the XML value into>')
See also http://msdn.microsoft.com/en-us/library/ms345117(SQL.90).aspx
One of the reasons I’ve been avoiding using WPF is for its difficulties in matching the look and feel of an application to the OS. When WPF first came out I opened up a Window, added some text and then tried to get it display in Tahoma, 8.25pt. After a couple of hours of hair pulling I realised that it just wasn’t going to work, so I closed that solution and haven’t touched WPF again for a few years.
Coming back to it now I find that the experience is much improved. In fact since I am running at 125% or 120dpi it actually seems to match the OS better now.
Here for example is a WinForms Form with three labels in it. At fist this looks file the simpler option, you only need to detect what OS you are running on and apply the correct font. However this is an unfair test as it uses auto-sizing controls, and while all controls resize to the contents in WPF only the label does in WinForms. Textboxes for example, require an explicit height (23px at 96dpi) and while the auto scaling options works quite well, it fails quite spectacularly if you change the font size of the form (to inherit a consistent font across all of your controls).
Here is a simple WPF window with a textblock. Notice how the text in the window looks lighter than that in the title.
<Window x:Class="ControlPanelMock.Window1"
xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<StackPanel>
<TextBlock Text="Window1" />
</StackPanel>
</Window>
I’m going to try some simple tests to see how bad my eyes are, but first I need a baseline. Lets take a second to examine the control panel home page.
According to the Microsoft User Experience Interaction Guidelines that text at the top “Adjust your computer’s settings” should be Segoe UI, 12pt. In fact we can quickly duplicate the font section of UI Guidelines with the following XAML.
<Window x:Class="ControlPanelMock.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="347" Width="400">
<StackPanel Margin="25">
<TextBlock Text="Window1 Default Text" />
<TextBlock Text="Title Bar Text - Segoe UI, 9pt" FontFamily="Segoe UI" FontSize="9pt"/>
<TextBlock Text="Main Instructions - Segoe UI, 12pt, #003399 " FontFamily="Segoe UI" FontSize="12pt" Foreground="#003399"/>
<TextBlock Text="Secondary instructions - Segoe UI, 9pt" FontFamily="Segoe UI" FontSize="9pt"/>
<TextBlock Text="Normal - Segoe UI, 9pt" FontFamily="Segoe UI" FontSize="9pt"/>
<TextBlock Text="Emphasised Text - Segoe UI, 9pt, Bold" FontFamily="Segoe UI" FontSize="9pt" FontWeight="Bold" />
<Border><TextBlock Text="Editable Text - Segoe UI, 9pt" FontFamily="Segoe UI" FontSize="9pt"/></Border>
<TextBlock Text="Disabled Text - Segoe UI, 9pt, #323232" FontFamily="Segoe UI" FontSize="9pt" Foreground="#323232" />
<TextBlock Text="Link - Segoe UI, 9pt, #323232" FontFamily="Segoe UI" FontSize="9pt" Foreground="#323232" />
<TextBlock Text="Disabled Text - Segoe UI, 9pt, #0066cc" FontFamily="Segoe UI" FontSize="9pt" Foreground="#0066cc" />
<TextBlock Text="Links (Hover) - Segoe UI, 9pt, #3399ff" FontFamily="Segoe UI" FontSize="9pt" Foreground="#3399ff" />
<TextBlock Text="Adjust your computer's settings " FontFamily="Segoe UI" FontSize="12pt" Foreground="#003399"/>
<TextBlock Text="System and Security " FontFamily="Segoe UI" FontSize="12pt" Foreground="#006e12"/>
<TextBlock Text="Appearance and personalisation " FontFamily="Segoe UI" FontSize="12pt" Foreground="#00ae1d"/>
</StackPanel>
</Window>
Now the last three lines of the above are special, and entered to directly replicate the look of the control panel as before, so lets compare
Control Panel
WPF
The first thing I note is that the OS cleartype seems to be a using a different algorithm to the WPF. Note how the colours are truer with the OS rendering. In fact if you examine the vertical stick of the ‘d’ in ‘Adjust’ on WPF you note that while the centre pixel is #003399 on the OS rendering, it is #0033a2 on the WPF, although if you examine pixels in a horizontal run such as the top of the ‘o’ or ‘s’ then WPF does manage to generate most of them with the correct colour.
One of the most annoying parts of Font rendering is that setting either SnapsToDevicePixels="False" or SnapsToDevicePixels="True" has NO effect.
Summary
On the whole WPF’s UI layout engine is much more capable of rendering UIs that correctly scale to match the system DPI, unfortunately it seems let down by its cleartype engine, which isn’t pixel perfect. Is this likely to be an issue?
UPDATE
Looks like its going to be fixed properly in WPF 4.0 http://blogs.msdn.com/text/archive/2010/03/05/additional-wpf-text-clarity-improvements.aspx
I've just seen some of the worst code of my life... fortunately it was from an AutoGenerated application. Lets start with this pValue = Utility.GetParam("issue_id");Response_issue_id.Value = pValue;
if(Session["UserID"]!=null)
pValue = Session["UserID"].ToString();
else
pValue="";Response_user_id.Value = pValue;
pValue = Utility.GetParam("assigned_to");
Notice that after the else, you will see that there are two statements on one line. Due to the fact that there is no bracket, the 2nd statement will also be executed when the condition was met as well.
After that we see loads of
pValue = Utility.GetParam("assigned_to");
try
{
Response_assigned_to.SelectedIndex=Response_assigned_to.Items
.IndexOf(Response_assigned_to.Items.FindByValue(pValue));
}
catch{}
pValue = Utility.GetParam("priority_id");
try
{
Response_priority_id.SelectedIndex=Response_priority_id.Items
.IndexOf(Response_priority_id.Items.FindByValue(pValue));
}
catch{}
Where this pattern is repeated for about a dozen fields. Don't run this code with "Break when an exception is thrown" switched on.
However my personal favourite is
Decimal.Parse(CCUtility.GetFormattedNumeric(mydec,CCUtility.defaultReturnedNumeric.BlankString ));
The point here is that CCUtility.GetFormattedNumeric attempts to parse a string into a numeric (again with a try catch around a Decimal.Parse) and then returns ToString("0.#####"). If the string isn't a number then it returns the 2nd argument, which is CCUtility.defaultReturnedNumeric.BlankString but of course that fails the Decimal.Parse. Shame they didn't use the alternative value CCUtility.defaultReturnedNumeric.Zero and saved two exceptions being thrown.
One of the really nice things about LinqToSQL is how simple it makes it to produce a new database. It fact it's so easy you can produce a real DB with less effort than a Mock'd one.
I'm sure this has to be bad in some way, but I've no idea what that is yet. I'll need to try it out on a decent environment with a Build Server (like at home).
public const string UnitTestConnection = "Data Source=.;Initial Catalog=UnitTest;Integrated Security=True";
...
MyDataContext context = new MyDataContext(UnitTestConnection);
if (context.DatabaseExists())
{
context.DeleteDatabase();
}
context.CreateDatabase();
context.SubmitChanges();
I’ve just put a new system live, that I’ve been developing over the past few weeks. Basically its a document approval system. One set of users fill in a form, more users approve or reject it, finally one team signs it off and takes the document to the next system. Very simple.
I started well and designed a framework that I thought was nicely extensible. I wanted to avoid having to create the backend ever again, and simply plug UI and workflow approval definitions on top.
I decided that the UI would be pointless to test (initially) and so created unit tests for the backend. By using Linq to SQL I discovered that I could create a blank empty database every time I ran the tests as part of an Assembly level setup method, which considerably reduced my mocking needs. Okay it removed them. I built a complete set of unit Tests to cover the interaction as I saw them going through an entire lifecycle of every process I could think of.
Given such a good start, I have to admit that my final result is not impressive. As I moved into the UI layer I stopped running the tests (we don’t use CruiseControl). We discovered that there wasn’t just one big document, but it actually made more sense as two. This required quite a big change to the Engine and Database layers to handle this but unfortunately the unit tests stayed off.
As the application was small it was incredibly easy to test that the new design worked as planned without using the tests. I am used to an automated build / test runner, so I just carried on. Now as I come to run them again I find I can't remember what the tests were supposed to do
Enter Behaviour Driven Design or BDD. BD seems to be TDD with a new name and a better way of constructing your tests to make them readable. It follows a grammar that allows business types to get involved.
As a <role> I want to <goal> so that <motivation>.
Given <assumption> when <action> then <test>
At this point I've only read about it but Scott Bellware's article seems to be the best. There also tool support but none of it seems to go from specification to code.
Update: Dan North's article is better http://dannorth.net/introducing-bdd
Craig Murphy dropped a little coding challenge on his blog the other day. This prompted me to write the responses as below. I’ve tried to target each one towards using a particular technology as the framework has developed. Have a look and tell me which is your preferred answer, or propose a new one (but again try to target a language feature). I’d love to know who you why you choose that language feature over another. Option 1. With Linq private const string alphabet = "abcdefghijklmnopqrstuvwxyz";
static void Main(string[] args)
{
char c = Console.ReadKey().KeyChar;
var myChars = from character in alphabet
where character <= c
select character;
var fullRow = myChars.Skip(1).Reverse().Concat(myChars);
var myRows = (from character in myChars
select ConvertToSpaces(character, fullRow));
var reverseRows = myRows.Reverse().Skip(1);
myRows = myRows.Concat(reverseRows);
Console.WriteLine(Environment.NewLine);//Skip the ReadKey line
foreach (string line in myRows)
Console.WriteLine(line);
Console.ReadKey();
}
private static string ConvertToSpaces(char wanted, IEnumerable<char> characters)
{
return new string(
(from character in characters
select character == wanted ? character : ' ').ToArray());
}
Option 2. With Generics
class Program
{
private const string alphabet = "abcdefghijklmnopqrstuvwxyz";
static void Main(string[] args)
{
char c = Console.ReadKey().KeyChar;
List<char> myChars = new List<char>();
foreach (char character in alphabet)
{
if (character <= c)
myChars.Add(character);
}
List<char> temp = new List<char>(Reverse<char>(AllButFirst<char>(myChars)));
temp.AddRange(myChars);
string fullRow = new string(temp.ToArray());
List<string> myRows = new List<string>();
foreach (char character in myChars)
{
myRows.Add(ConvertToSpaces(character, fullRow));
}
IEnumerable<string> reverseRows = AllButFirst<string>(Reverse<string>(myRows));
myRows.AddRange(reverseRows);
Console.WriteLine(Environment.NewLine);//Skip the ReadKey line
foreach (string line in myRows)
Console.WriteLine(line);
Console.ReadKey();
}
private static IEnumerable<T> Reverse<T>(IEnumerable<T> myChars)
{
Stack<T> reverse = new Stack<T>();
foreach (T character in myChars)
{
reverse.Push(character);
}
while (reverse.Count > 0)
{
yield return reverse.Pop();
}
}
private static IEnumerable<T> AllButFirst<T>(IEnumerable<T> myChars)
{
bool first = true;
foreach (T character in myChars)
{
if (first)
first = false;
else
yield return character;
}
}
private static string ConvertToSpaces(char wanted, IEnumerable<char> characters)
{
StringBuilder result = new StringBuilder();
foreach (char character in characters)
{
result.Append(character == wanted ? character : ' ');
}
return result.ToString();
}
}
Option 3. Using IEnumerable
class ProgramDNv2
{
private const string alphabet = "abcdefghijklmnopqrstuvwxyz";
static void Main(string[] args)
{
DiamondChars diamond = new DiamondChars();
diamond.chars = GetChars( Console.ReadKey().KeyChar);
foreach (string line in diamond)
{
Console.WriteLine(line);
}
Console.ReadKey();
}
private static string GetChars(char MidChar)
{
string chars = alphabet.Substring(0, alphabet.IndexOf(MidChar) + 1);
return chars;
}
private class DiamondChars : IEnumerable<String>
{
public string chars;
#region IEnumerable<string> Members
public IEnumerator<string> GetEnumerator()
{
int index = 0;
foreach (char character in chars)
{
yield return MakeLine(character, index);
index++;
}
index--;
foreach (char character in chars.Reverse())
{
if (index < chars.Length - 1)
{
yield return MakeLine(character, index);
}
index--;
}
}
#endregion
private string MakeLine(char character, int index)
{
string line = new string(chars[index], 1).PadLeft(chars.Length - index);
if (index > 0)
return line + new string(chars[index], 1).PadLeft(index * 2);
else
return line;
}
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
}
Option 4. Simple recursion
class ProgramDNv1
{
static void Main(string[] args)
{
string input = "abcde";
StringBuilder result = new StringBuilder();
BuildDiamond(0, input, result);
Console.WriteLine(result);
}
private static void BuildDiamond(int index, string input, StringBuilder result)
{
string line = new string(input[index], 1).PadLeft(input.Length - index);
string line2 = new string(input[index], 1).PadLeft(index * 2);
result.Append(line);
if (index > 0)
result.Append(line2);
result.Append(Environment.NewLine);
if (index < input.Length - 1)
{
BuildDiamond(index + 1, input, result);
result.Append(line);
if (index > 0)
result.Append(line2);
result.Append(Environment.NewLine);
}
}
}
Now add a quick comment below telling you preferred implementation and briefly why. Thanks.
I'm trying to query an ActiveDirectory but at my current client site, I have a problem. There's a few. The client has previously migrated their DC from XPERT to EUROPE, and now they've bought a division of another company and added that in as well. As a result the default DC only supplies half of the staffs email addresses.
Fortunately you can override the default DC by the use of,
DirectoryEntry root = new DirectoryEntry("LDAP://DC=SUBDOMAIN,DC=DOMAIN,DC=com");
Just update DOMAIN and SUBDOMAIN to where you are. More details on http://msdn.microsoft.com/en-us/library/system.directoryservices.directorysearcher.searchroot.aspx