Sunday, August 31, 2014

Entity Framework - Do Not Delete LocalDb !

Entity Framework and LocalDb go together like bread and butter when developing a new application.  However, if you have you ever had a problem with your LocalDb instance manually deleting the .mdf file is probably not the way to go.  

I deleted one of my .mdf files the other day and thought it was strange that I could no longer create a new instance of the database using the default EF conventions.  A brief web search set me straight. This blog tells the whole story.  

The short version is SQL Server maintains a reference to the .mdb files it has created, when you manually delete the file, SQL Server doesn't know the file is gone.  So, don't manually delete the file.  

If you like me have already deleted LocalDb, you may want to still use your Db name, so your looking for the fix.  The fix is in the reference blog post, however for completeness I'll repeat what it says.  Go download the SqlCmd Utility.  Run the following command...

C:\>sqlcmd -S (localdb)\v11.0 -E -d master -Q "DROP DATABASE [myApp]"

You will be presented with an error like the following

Msg 5120, Level 16, State 101, Server User1-PC\LOCALDB#5725A8FF, Line 1
Unable to open the physical file "C:\Users\User1\myApp.mdf". Operating
system error 2: "2(The system cannot find the file specified.)".
File activation failure. The physical file name "C:\Users\User1\myApp_log.ldf"
may be incorrect.


The LocalDb database file will now be correctly unregistered.  If in the future you want to delete your database, use this method instead of a hard delete.  

Friday, August 29, 2014

Issue using WPF DataGrid ColumnHeader with a DataTemplate & ClipboardCopyMode="IncludeHeader"

While working on a project recently, I ran into a small hitch with the WPF data grid.  The software I spend most of my time working on relies heavily on units of measure.  A common requirement is to have units of measure displayed in the data grid column headers.  Something like this...


However, you can't directly bind to the Header property of the data grid in XAML.  There are probably several ways this could be worked around, but a common solution is to use a HeaderTemplate.  The XAML to create a data template for the data grid column header would look like this.

 <UserControl.Resources>  
     <DataTemplate x:Key="FlowRate" DataType="DataGridColumnHeader">  
       <TextBlock Text="{Binding Source={x:Static units:UnitsContext.CurrentSymbols}, Path=FlowUnit, StringFormat=Flow-Rate ({0})}" />  
     </DataTemplate>  
     <DataTemplate x:Key="Pressure" DataType="DataGridColumnHeader">  
       <TextBlock Text="{Binding Source={x:Static units:UnitsContext.CurrentSymbols}, Path=PressureUnit, StringFormat=Pressure ({0})}" />  
     </DataTemplate>  
   </UserControl.Resources>  

All is well and good until the next requirement comes along.  Users need to be able to copy the data from the data grid into Excel, including the column headers.  The data grid has a clipboard copying setting, ClipboardCopyMode="IncludeHeader", if the column uses a HeaderTemplate, it will show as an empty header in Excel.  A HeaderTemplate could include almost anything, and it isn't guaranteed to be text.  Therefore, I had to admit to myself that, while annoying, this data grid issue does make sense.

I arrived at a simple fix by using an attached property to move the the text from the header template, into the data grids header.

  /// <summary>  
   /// WPF Data grid does not know what is in a header template, so it can't copy it to the clipboard when using ClipboardCopyMode="IncludeHeader".  
   /// This attached property works with a header template that includes one TextBlock. Text content from the templates TextBlock is copied to the  
   /// column header for the clipboard to pick up.  
   /// </summary>  
   public static class TemplatedDataGridHeaderText  
   {  
     private static readonly Type OwnerType = typeof(TemplatedDataGridHeaderText);  
     public static readonly DependencyProperty UseTextFromTemplateProperty = DependencyProperty.RegisterAttached("UseTextFromTemplate", typeof(bool), OwnerType, new PropertyMetadata(false, OnHeaderTextChanged));  
     public static bool GetUseTextFromTemplate(DependencyObject obj)  
     {  
       return (bool)obj.GetValue(UseTextFromTemplateProperty);  
     }  
     public static void SetUseTextFromTemplate(DependencyObject obj, bool value)  
     {  
       obj.SetValue(UseTextFromTemplateProperty, value);  
     }  
     private static void OnHeaderTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)  
     {  
       var textColumn = d as DataGridTextColumn;  
       if (textColumn == null) return;  
       if (textColumn.HeaderTemplate == null) return;  
       var headerTemplateTexblockText = textColumn.HeaderTemplate.LoadContent().GetValue(TextBlock.TextProperty).ToString();  
       textColumn.Header = headerTemplateTexblockText;  
     }  
   }  

An alternative approach might be to directly set the header text through an attached property...

  /// <summary>  
   /// Allows binding a property to the header text. Works with the clipboard copy mode - IncludeHeaders.  
   /// </summary>  
   public static class DataGridHeaderTextAttachedProperty  
   {  
     private static readonly Type OwnerType = typeof(DataGridHeaderTextAttachedProperty);  
     public static readonly DependencyProperty HeaderTextProperty = DependencyProperty.RegisterAttached("HeaderText", typeof(string), OwnerType, new PropertyMetadata(OnHeaderTextChanged));  
     public static string GetHeaderText(DependencyObject obj)  
     {  
       return (string)obj.GetValue(HeaderTextProperty);  
     }  
     public static void SetHeaderText(DependencyObject obj, string value)  
     {  
       obj.SetValue(HeaderTextProperty, value);  
     }  
     private static void OnHeaderTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)  
     {  
       var textColumn = d as DataGridTextColumn;  
       if (textColumn == null) return;  
       textColumn.Header = GetHeaderText(textColumn);  
     }  
   }  

In XAML, the attached property can be used on each data grid column...

 <DataGrid ItemsSource="{Binding }" AutoGenerateColumns="False" IsReadOnly="True" VerticalScrollBarVisibility="Auto" VerticalAlignment="Stretch">  
     <DataGrid.Columns>  
       <DataGridTextColumn Binding="{Binding FlowRate.UserValue, StringFormat=N3}" HeaderTemplate="{StaticResource FlowRate}"  
                 attachedProperties:TemplatedDataGridHeaderText.UseTextFromTemplate="True"/>  
       <DataGridTextColumn Binding="{Binding Pressure.UserValue, StringFormat=N3}" HeaderTemplate="{StaticResource Pressure}"  
                 attachedProperties:TemplatedDataGridHeaderText.UseTextFromTemplate="True"/>  
     </DataGrid.Columns>  
   </DataGrid>  

Thus far, this has proved to be a simple solution for this particular data grid issue :)




Thursday, August 14, 2014

.NET Rocks!

This past year the .Net Rocks! Road Trip stopped in Houston, and I took the opportunity to go to the event and watch Carl & Richard do a live show.  Speaking with several developers at the event, I was surprised to learn that it was the first time they'd heard .NET Rocks!  Keeping technical content entertaining and enlightening is not an easy task, so kudos to these guys for a great show.

With over 1000 shows and counting there is plenty of content.  On my daily commute I listen to the podcast, and often find myself diving deeper into stuff I hear about on the show.

If you haven't had opportunity to listen, check out .NET Rocks!  it's an entertaining way to stay up to date on all that's going on in the fast paced world of programming.