February 16, 2009, 6:52 pm
I have long had an issue with Visual Studio where it takes a ridiculous amount of time to delete a file. Sometimes it takes over a minute and the IDE is completely unusable while it is loading. I finally came across a this post by Matt Hinze that gives a solution. Apparently when you delete a file it scans your recycle bin which can take a long time if there are lot of files in there. All you have to do is empty your recycle bin and you should be able to delete files with no noticeable delay.
February 12, 2009, 8:26 pm
By default, validation is not enforced on a binding until after the value has been changed once. Consider this situation: A form has a text box whose contents should not be empty, but its starting value is the empty string. The text box will not show an error when the form is loaded. Instead, it will only show its error style after the user types in some text and then deletes it. Some people would call this a feature, but I prefer to have the validation checked right away so that I immediately know what the required fields are, and which starting values are invalid.
A quick hack
One way to tackle this is to hook a loaded event to the control and then call UpdateSource() from code:
Private Sub myTextBox_Loaded(ByVal sender As System.Object, _
ByVal e As System.Windows.RoutedEventArgs) Handles myTextBox.Loaded
BindingOperations.GetBindingExpression(myTextBox, _
TextBox.TextProperty).UpdateSource()
End Sub
Unfortunately, this really isn’t a desirable solution because it requires some pretty ugly code-behind (not that there’s any other kind) and needs to be done over again for every binding. What we really want is for this functionality to be a part of the binding markup extension.
Creating a wrapper around the binding markup extension
At first I thought it would be easy to just inherit from the Binding class and override ProvideValue, but of course, it is marked as NotOverridable (sealed in C#). Instead, I create a class called ValidationBinding that inherits directly from MarkupExtension and has the new class manage an instance of Binding. The code looks like this:
Imports System.Windows.Markup
Public Class ValidationBinding
Inherits MarkupExtension
Private _binding As New Binding
Private _dependencyObject As DependencyObject
Private _dependencyProperty As DependencyProperty
Public Sub New()
_binding.ValidatesOnDataErrors = True
_binding.ValidatesOnExceptions = True
End Sub
Public Sub New(ByVal path As String)
Me.New()
_binding.Path = New PropertyPath(path)
End Sub
Public Overrides Function ProvideValue _
(ByVal serviceProvider As System.IServiceProvider) As Object
Dim valueTarget = _
DirectCast(serviceProvider.GetService(GetType(IProvideValueTarget)), _
IProvideValueTarget)
_dependencyObject = valueTarget.TargetObject
_dependencyProperty = valueTarget.TargetProperty
If TypeOf _dependencyObject Is FrameworkElement Then
Dim element = DirectCast(_dependencyObject, FrameworkElement)
If element.IsLoaded Then
ForceValidation()
Else
AddHandler element.Loaded, AddressOf ElementLoaded
End If
Else
ForceValidation()
End If
Return _binding.ProvideValue(serviceProvider)
End Function
Private Sub ForceValidation()
BindingOperations.GetBindingExpression(_dependencyObject, _
_dependencyProperty).UpdateSource()
End Sub
Private Sub ElementLoaded(ByVal sender As System.Object, _
ByVal e As System.Windows.RoutedEventArgs)
ForceValidation()
End Sub
Public Property Path() As PropertyPath
Get
Return _binding.Path
End Get
Set(ByVal value As PropertyPath)
_binding.Path = value
End Set
End Property
... the rest of the binding properties go here
End Class
The binding can then be used like this (where my is an imported namespace containing ValidationBinding):
<TextBox Margin="5" Text="{my:ValidationBinding Path=Text}" />
As an example, I have exposed the Binding’s Path property, but you actually have to do this for all of the public properties in Binding. A reference of all the properties that should be implemented can be found here.
ProvideValue returns the result of the Binding’s ProvideValue function, but first it checks whether the binding target has finished loading. If it has already finished loading then it forces validation by calling UpdateSource() on the target. In the much more likely scenario that the control has not yet loaded (this will be the case when you set your binding in XAML) it attaches a handler to the Loaded event so that the ForceValidation subroutine can be deferred until it is finished loading.
Also, notice that I set both ValidatesOnDataErrors and ValidatesOnExceptions to True in the constructor so that I didn’t need to specify it in the XAML. Chances are that whenever you use this markup extension you will want those enabled anyways.
It may seem like a lot of work, but it is a very reusable solution that gives you significantly more power.
February 11, 2009, 9:18 pm
There are a few problems with the data model code that is automatically generated in LINQ to SQL. The most obvious issues are that class names are not capitalized and that tables with two foreign keys to the same table will not have descriptive names. For example, if a table has columns firstUserID and secondUserID which are both foreign keys to the users table then you would probably hope to see the properties FirstUser and SecondUser on that class. Unfortunately, what you will actually get is User and User1 which is pretty much pointless because it is very difficult to tell which one is which. One way to tackle this is to simply change the code after it has been generated so that it looks like you want it to. But then as soon as you change the database and import the model again your changes are lost and have to be redone every time. Ideally, the automatically generated code would be formatted exactly as you want it.
The solution I came up with was to useĀ SqlMetal to generate XML output, then manipulate that output and feed it back into SqlMetal so that it can generate the code from the altered XML. As a naming heuristic, I specified that a foreign key column’s property would have a name derived from the column name without the “ID” suffix and a capitalized first letter. Depending on the extent of the changes you plan on making, you may want to make an XSLT file to translate the XML, or simply use some regular expressions.
One downside to this approach is that SqlMetal often cannot generate code for stored procedures because it is unable to determine the return type without actually running the procedure. To get around this I told SqlMetal not to generate any code for the stored procedures (just omit the /sprocs argument), then manually incorporated the XML for my stored procedures in the XSLT file so that it would be injected into the second input to SqlMetal that actually generates the code.
February 9, 2009, 8:50 pm
The LINQ to SQL DataContext provides excellent functionality for managing a set of local changes to a database that can be pushed to the server with a single call to SubmitChanges(). Inevitably there will be situations where you want to discard the changes you have made, effectively allowing you to continue using the DataContext as though those changes had never been made. Unfortunately, there is no DataContext.DiscardChanges() method.
A little research reveals that this is by design and that you should simply recreate the DataContext in these cases, but of course, nothing is that simple. Every object you have that came from the original DataContext now needs to be reset to use the new one to guarantee predictable behaviour. For example, the last line of this snippet will set objectsAreEqual to False:
' Create two data contexts
Dim dc1 As New UsersDataContext
Dim dc2 As New UsersDataContext
' Grab the same record out of both the data contexts
Dim user1 = dc1.Users.First
Dim user2 = dc2.Users.First
' False, because the otherwise identical records come from different contexts
Dim objectsAreEqual = user1 = user2
Basically, this shows that it does matter where your object came from. If you just want to discard a few little changes and you don’t want to have to recreate all your variables, you can instead undo all the changes that you have made so far and continue to use the same DataContext.
Undoing inserts and deletes is easy, because we can just do the opposite to revert the change. Luckily there is even a nice function on the DataContext that will show us what we need to do called GetChangeSet:
Public Sub DiscardInsertsAndDeletes(ByVal data As DataContext)
' Get the changes
Dim changes = data.GetChangeSet()
' Delete the insertions
For Each insertion In changes.Inserts
data.GetTable(insertion.GetType).DeleteOnSubmit(insertion)
Next
' Insert the deletions
For Each deletion In changes.Deletes
data.GetTable(deletion.GetType).InsertOnSubmit(deletion)
Next
End Sub
LINQ to SQL is smart enough to know that if a row is inserted and then deleted (or the other way around) nothing needs to be done. If you look at the ChangeSet after running this function, you will notice that the Inserts and Deletes collections are empty. Updates are a little more annoying. If you update a value, and then set it back to its original state then you will get the expected behaviour (ie: the ChangeSet will be empty because you reverted your change) but unless you write code to keep track of the original value yourself, there is no way to automatically put an object back into its start state without hitting the database. If hitting the database is acceptable, you can always use the Refresh function to get rid of the updates:
Public Sub DiscardUpdates(ByVal data As DataContext)
' Get the changes
Dim changes = data.GetChangeSet()
' Refresh the tables with updates
Dim updatedTables As New List(Of ITable)
For Each update In changes.Updates
Dim tbl = data.GetTable(update.GetType)
' Make sure not to refresh the same table twice
If updatedTables.Contains(tbl) Then
Continue For
Else
updatedTables.Add(tbl)
data.Refresh(RefreshMode.OverwriteCurrentValues, tbl)
End If
Next
End Sub