Friday, December 19, 2008

Coding WPF styles in C#

WPF styles let you specify the look of your controls consistently across your application.  Today I needed to create menu items in a different part of the application based on the currently focused element.
I got the menu creation code to work, and then wanted to apply my WPF style instead of typing a bunch of header names in and then maybe having to change them later.

Here is the WPF style:
<Button.ContextMenu>
   
<ContextMenu>
       
<ContextMenu.Resources>
           
<Style x:Key="{x:Type MenuItem}" TargetType="{x:Type MenuItem}" BasedOn="{StaticResource {x:Type MenuItem}}">
               
<Setter Property="Header" Value="{Binding Command.Name, RelativeSource={RelativeSource Self}}"/>
           
</Style>
       
</ContextMenu.Resources>
   
<MenuItem Command="ApplicationCommands.Cut"/>
</Button.ContextMenu>

Here is the C# equivalent:

new returnValue = ContextMenu();
//base our style on the current MenuItem Style. No need for null check.
var headerStyle = new Style(typeof(MenuItem), TryFindResource(typeof(MenuItem)) as Style);
var commandNameBinding = new Binding("Command.Name");
commandNameBinding.RelativeSource =
RelativeSource.Self;
headerStyle.Setters.Add( new Setter(HeaderedItemsControl.HeaderProperty, commandNameBinding));
returnValue.Resources.Add(typeof(MenuItem), headerStyle);
returnValue.Items.Add(new MenuItem() { Command = ApplicationCommands.Cut });

Thursday, November 27, 2008

XAML factoring


We are using the Infragistics Ribbon component in our application.  Our application has the same Ribbon Group content specified in multiple tabs.  I was looking for a way to share the group content so it wasn't copied and pasted in both locations.

I searched online and found a forum where one of their staff said it was not a feature.

This is not a problem as WPF allows you to share UI elements for compiled resource dictionaries.

When we compile XAML we get BAML stored inside the assembly as a resource.  This allows the x:Shared keyword to enable special functionality not available from C#.   Why not IL?  BAML is more compact than IL, can be localized after compilation, and is less of a security threat.

Specifying x:Shared in a resource dictionary means the content will be fetched new each time it is requested allowing the same user interface elements to be added in multiple places.

Here is an example:
    <Window.Resources>
        <StackPanel x:Key="moreContent" x:Shared="false">
            <TextBlock Text="local" />
        </StackPanel>
    </Window.Resources>
    <StackPanel>
        <StaticResourceExtension ResourceKey="moreContent" />
        <StaticResourceExtension ResourceKey="moreContent" />
    </StackPanel>
One may also put the shared content in another XAML file to share the resource with other XAML files in your application:
Window1.xaml

    <Window.Resources>
        <ResourceDictionary >
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Ribbon.xaml" />
            </ResourceDictionary.MergedDictionaries>
            <StackPanel x:Key="moreContent" x:Shared="false">
                <TextBlock Text="local" />
            </StackPanel>
        </ResourceDictionary>
    </Window.Resources>
    <StackPanel>
        <StaticResourceExtension ResourceKey="moreContent" />
        <StaticResourceExtension ResourceKey="content" />
        <StaticResourceExtension ResourceKey="moreContent" />
    </StackPanel>

Ribbon.xaml:
    <StackPanel x:Key="content" x:Shared="false">
        <TextBlock Text="From Ribbon" />
    </StackPanel>
</ResourceDictionary>

Thursday, November 20, 2008

Clarity of intent and newing up structs

Sometimes it is useful to see if a struct hasn't been set.  Of course this can get you into trouble if the unset value is a legal value, but sometimes it's not, like when dividing an int 0 will throw.

Previously I had been using code like if (divisor != new int() ) to check the value prior to calling my function.

This struck me as very odd to be newing up a struct.

Then I recalled the default keyword, which I'd only used for generics before.  It turns out default works the same and declares intent better.

if (divisor != default(int) )
{

}

Of course in this contrived example it makes more sense to do != 0, but when more complex structs are involved the syntax works quite nicely.

Tuesday, November 11, 2008

Visual Studio Post-Build Events.

I haven't been a fan of Visual Studio Post-build command line events.

Problem:
We need to copy app.config during the build process and it needs to be mstest.exe.config in the test out directory.  During our Unit Testing process on the build server we've been referencing a static class to provide all of our configurations.  Now we are switching over to a real file.  This makes all the unit tests referencing our configurations fail because System.Configuration.ConfigurationManager.GetSection returns null.  The problem is our unit tests are being executed by MS test.  Ideally we would maintain a configuration class reading from a file and a configuration class for testing which uses test values.  Unfortunately due to time pressures that is not an option.

Solution:
By going into Visual Studio, project properties, Build Events Tab, Post-build event command line and typing copy "$(ProjectDir)app.config" "$(TargetDir)mstest.exe.config" /y
MSDN describes the $(ProjectDir) and $(TargetDir) variables
In our testrunconfig file we have a Deployment section and then a DeploymentItem with filename set to mstest.exe.config.  My frist thought was to do the file copy on our build server after getting the source files and then have our testrunconfig file copy the mstest.exe.config using a DeploymentItem.  Thinking about it for a minute I realized this would cause differences when we are building in Visual Studio and when we are building on the server which would easily cause confusion in the future.

Not to happy we are relying on the filesystem for our test, but happy that the build behaves the same on desktops and servers and anyone can figure out what is going on.

Wednesday, October 29, 2008

Freeing space on your computer by customizing Visual Studio

My computer has been running slowly lately which really bothers me.  I went to defrag my hard drive and didn't have 10% free space disk defragmentor recommends.

I use a utility called TreeSize which presents a navigable tree view of how much space each folder is consuming.

Previously I took for granted the fact that Visual Studio 2005 consumes 2,730 MB and Visual Studio 2008 eats up 2,562 MB.  This time I decided to look at why the are such hogs.  It turns out in my Visual Studio 2005 installation c:\program Files\Microsoft Visual Studio 8 there is a sub folder VC taking up 1,574MB.  This is for Visual C++ 2005 which I never plan to use.  Using Add / Remove Programs and clicking Change/Remove on Microsoft Visual Studio 2005 Team Suite - ENU allowed me to easily remove Visual C++ 2005.

I'm keeping Visual C++ 2008 because I hope to play with it in the next six months or so.

During this exercise I also noticed OneNote sucking up 2,616 MB.  1,646 of it for backup files.  Our notebooks are on a network location so I don't need to be backing these up.  I turned it off by opening OneNote going to Tools, Options, Backup and unchecking "Automatically Backup".

Wednesday, October 22, 2008

Books I've read this past year

These are the books I've read this past year in roughly the order I read them.

Programming .NET Components, 2nd Edition - Covers many advanced topics on application maintainability, extensibility, and reusability.  Some of the greatness was lost on me at the time because I didn't see the applications of the ideas.  I recommend reading this book after having a thorough understanding of .NET and programming.  I forgot how great this book was and I'll probably be re-reading it.

MCTS Self-Paced Training Kit (Exam 70-536): Microsoft .NET Framework 2.0 Application Development Foundation - Good introductory book about the .NET framework.  Skip it if you are already comfortable with framework classes.

Extreme Programming Adventures in C# - A fun quick read.  It makes some interesting points about extreme programming.  The book discusses a small project developed by one and a half developers.  I would be more interested in a book discussing a larger team to see how the process scales.

Code Complete: A Practical Handbook of Software Construction - Should be read by all programmers.  It goes into great depth discussing seemingly mundane topics and explains why they aren't trivial.

Software Project Survival Guide - Another great book by Steve McConnell.  It is thought provoking and may enlighten you to aspects of your development process you can improve.

The Pragmatic Programmer: From Journeyman to Master - Seemed to be Code Complete light to me.  It covered a lot of the same issues in less depth.  If you read Code Complete you can skip this book or read it first to whet your appetite.

The Mythical Man-Month: Essays on Software Engineering, Anniversary Edition (2nd Edition) - Discusses large scale software construction and team scalability challenges.  People often summarize it by saying you can't make a baby in nine months.  I don't think this summary does justice to the book and recommend you read it.

Windows Presentation Foundation Unleashed (WPF) (Unleashed) - This was a good introduction and overview of WPF.  You should read this book or something like it before professionally programming in WPF.

Programming WPF - This book deep dives into WPF.  After you've been professionally programming WPF for a couple weeks this book should help increase your understanding of the technology.

The Build Master: Microsoft's Software Configuration Management Best Practices - Short guide to building and deploying software.  Good read for developers who've been appointed the build master for their project.  If you find yourself in this situation consider using Windows Installer XML (WiX).  It allows you to build your install files via XML and fits perfectly with MSBuild.

Thursday, May 1, 2008

Extreme Programming Adentures in C# (book review)

At the Central Ohio Day of .NET last week I won Extreme Programming Adventures in C# (DV-Microsoft Professional) by Ron Jeffries. The book is a case study about using XP programming on a small scale project and team. It is well written and immediately sucked me in. I have been experimenting at work by trying the simplest thing that works and using test driven development.

Wednesday, April 23, 2008

Central Ohio Day of .NET 2008 Synopsis

I rode down to the Central Day of Central Ohio Day of .NET 2008 with Rich Hamilton and Joe Kunk on Saturday.



I attended these session:


  1. A Linq to Everything (Leon Gersing)

  2. User Interface Design for Programmers (Chris Poteet)

  3. Happy Marriage of Agile and TFS (Alexei Govorine)

  4. Test Driven Development (Phil Japikse)

  5. Well, Isn't that Spatial... (Jason Follas)

I had heard of recording users running an application but have never done it before. Chris's presentation had some recorded user sessions. It was interesting to watch the sessions and listen to his commentary about the design changes viewing the user interaction caused.


After the conference Jeff Blankenburg held a poker tournament back in his hotel room. It was a lot of fun to hang out with like minded individuals in a casual atmosphere. This was my favorite part of the conference.

Tuesday, April 22, 2008

00 Querying Named instance Linked SQL Server

This is how you query against a linked named instance of sql server.


sp_addlinkedserver 'servername\instanceName' --create the link.

select * from [servername\instanceName].databaseName.dbo.TableName --execute the query.

Wednesday, April 16, 2008

Search for Detroit Software Developer Community

I ran across an interesting group this morning in my search for the Detroit Software Developer Community: the detroit software engineers' grotto. The group's goal is interesting for anyone to read. They are trying to rent a space for software engineers to work instead of their office. The space will have comfortable couches, chairs, and like minded individuals. It is modeled on a Writer's Grotto founded in San Francisco.

Unfortunately for me it states Windows is a legacy operating system, Web 2.0 is dead, and Mac OS X is the wave of the future. Interesting ideas.

I'm looking to get involved in the Detroit software developer community. We have companies with lots of developers here: Compuware, Electronic Data Systems (EDS), Accenture, and Deloitte come to mind right off the top of my head.

The Great Lakes .net Users Group, but as that is in Southfield I have to battle traffic to get out there. I came from the Lansing area which has a great developer community especially for the relatively low population of the area. Being involved in the Greater Lansing User Group .net continues to positively impact my life.

This morning I went looking for the Detroit developer community. My assumption is that it must exist given the larger population and I'm just not connected. Yet :)

Tuesday, April 1, 2008

Clustered Index slows down BCP signiificantly

Our 19 hour job was reduced to about 30 minutes using this technique.

We had to import 110 million rows into a SQL Server table containing 5 ints during 4 import sessions. There was a clustered index over 4 of those ints.

We used the System.Data.SqlClient.SqlBulkCopy class to do the import (class mirroring the sql server bcp utility). The initial import took ~19 hours. On a new table we removed the clustered index and inserted all the rows again. This took about 12 minutes. Applying the clustered index took about 20 minutes.

Monday, March 24, 2008

Programmatically Executing SQL Scripts

I didn't realize GO is not a SQL keyword. When I was trying to execute a script that worked in SQL Server Management Studio I was getting SQLException Incorrect syntax near 'Go'. The solution is to split the input script on GOs and execute those scripts.

const char splitChar = '☻'; //this character should never appear in command files
if (createDatabaseScript.Contains(splitChar.ToString()) == true)
throw new Exception("Aborting. Splitting this file may break the script because the script contains the split character");
using (dbConnnection)
{
dbConnnection.Open();
SqlCommand createDbCommand = new SqlCommand(string.Empty, dbConnnection);

//split the input script into multiple scripts based on GOs
foreach (string command in createDatabaseScript.Replace("GO", splitChar.ToString()).Split(new Char[] { splitChar }))
{
try
{
createDbCommand.CommandText = command;
createDbCommand.ExecuteNonQuery();
}
catch (Exception ex)
{
//log the error for later review.
results += ex.Message + Environment.NewLine;
}
}
}
Console.Write(results);

Monday, March 17, 2008

FxCop bug - CA1709 & CA 1707

CA 1707 IdentifiersShouldNotContainUnderscores
CA 1709 IdentifiersShouldBeCasedCorrectly

I ran into a surprise last week. FxCop is throwing warnings for properties on 2 out of 5 interfaces in a particular project. Interface A implements interface B.

I'm assuming the bug described in this article is causing it: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2344375&SiteID=1 and that it will be fixed in Visual Studio 2008 Service Pack 1.

Monday, March 10, 2008

Unit Testing Graphics Operations

We decided to verify our graphic operations here by doing a binary comparison.
Here is a simple implementation using Linq.

Setting up the expected value:

Bitmap aBitmap = new Bitmap(181,46); //exact size of the bitmap to reduce the number of bits
Graphics aGraphic = Graphics.FromImage(aBitmap);
target.DrawGrid(aGraphic); //the operation you want to verify
MemoryStream actual = new MemoryStream();
aBitmap.Save(actual,ImageFormat.Bmp);
string aBunch = string.Join(",", actual.ToArray().Select(b => b.ToString()).ToArray());

Copy the string aBunch. We will use this to create the expected byte array.
create the byte array like this but use your pasted values instead of my values
byte[] expected = new byte[] {66,77,78... };

Finishing the unit test:

Bitmap aBitmap = new Bitmap(181,46);
Graphics aGraphic = Graphics.FromImage(aBitmap);
target.DrawGrid(aGraphic);
MemoryStream actual = new MemoryStream();
aBitmap.Save(actual,ImageFormat.Bmp); // get our actual result.
byte[] expected = getExpected("DrawGridTest");

Assert.IsTrue(actual.ToArray().SequenceEqual(expected),"Binary comparison failed.");

This method is getting expected from a function because Visual Studio responds slowly when there are long lines of text. I created a partial class containing the instantiation of expected (I'm using a switch statement). I thought about putting the results in a resource or a file, but I'm preferring code for now.

Friday, February 29, 2008

Speeding up Unit Testing in Visual Studio 2008

I've been doing unit testing in Visual Studio 2008. I noticed it takes a while for the tests to execute after I start the test run.

Initially I thought it was copying data into the TestResults directory. Some of our unit tests rely on files and our test run copies ~30 MB of data into the TestResults directory.

I found out it was the code coverage instrumentation process slowing it down. On my machine it seems to take about a second to instrument an assembly for code coverage. Our project has 8 assemblies which adds ~8 seconds to every run. While it is important for our server build to have all the assemblies instrumented, when I'm creating unit tests I just need to have my assembly instrumented. Going into the GeneralRun.testrunconfig --> Code Coverage and instrumenting only the assembly I'm working on reduces the run speed by about 7 seconds.

If you do this, ensure you don't accidentally check this change into Team Foundation Server or you won't get complete code coverage results.

Skipping the deployment of the 30MB of data had no noticeable effect on the test run times.

Monday, February 25, 2008

Creating a metafile in .NET

Metafiles are a way to save scalable vectory graphics. This blog creates a simple image containing a diagonal line. It also shows the proper way to save the metafile, as the class method saves it as a png file.

MSDN article on MetaFiles: http://msdn2.microsoft.com/en-us/library/ms536391.aspx



using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;




MemoryStream metafileStream = new MemoryStream();


Graphics offScreenDC = Graphics.FromHwndInternal(IntPtr.Zero);


IntPtr myImagePointer = offScreenDC.GetHdc();


Metafile meta =
//new Metafile(myImagePointer, EmfType.EmfOnly); //unable to do memoryStreamSave
new Metafile(metafileStream, myImagePointer, EmfType.EmfOnly); //able to do memoryStreamSave


Graphics aGraphic = Graphics.FromImage(meta);


aGraphic.DrawLine(new Pen(Brushes.Black), new Point(0, 0), new Point(29, 29));


aGraphic.Dispose(); //Dispose must be called to flush the drawing instructions.


offScreenDC.ReleaseHdc();
meta.Save(@"c:\metaSave.wmf"); //saves as a png file.


FileStream aWrite = new FileStream(@"c:\StreamSave.wmf",FileMode.Create); //saves as a wmf file


metafileStream.WriteTo(aWrite);