Monday 22 October 2012

WPF DataGrid CheckBox Column requires two clicks to change state

While using a WPF DataGrid and a CheckBox column I realised that it was taking two Mouse clicks to change the state of the CheckBox.

I found a good post by Mike Borozdin which explains how to work around this ‘issue’;

http://www.mikeborozdin.com/post/WPF-DataGrid-CheckBox-Single-Click-CheckingUnchecking.aspx

Basically, if instead of adding a CheckBox column, you add a TemplateColumn, and enclose a CheckBox within the DataTemplate, this works around the ‘issue’;

<DataGrid Name="dgProducts" AutoGenerateColumns="False" CurrentCellChanged="dgProducts_CurrentCellChanged">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Name" Binding="{Binding Path=Name}"/>
        <DataGridTextColumn Header="Price" Binding="{Binding Path=Price}"/>
        <DataGridTemplateColumn Header="In Stock">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding Path=IsInStock, UpdateSourceTrigger=PropertyChanged}">
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

Wednesday 17 October 2012

Windows Forms App with Splash Screen Throws–“Invoke or BeginInvoke cannot be called on a control until the window handle has been created.” Exception

I’ve come across a bug in the .Net Framework when developing a Windows Forms app, which has a Splash Screen.

On some users machines, the application threw a “Invoke or BeginInvoke cannot be called on a control until the window handle has been created.” exception at startup.

This is seemingly to do with code executing before the splash screen has fully loaded. It appears that the exception happens just after startup and on slow or busy machines.

Microsoft have a workaround for this issue, which I found on the MSDN forums;

http://social.msdn.microsoft.com/Forums/en/winforms/thread/bdc00055-338d-4a4a-a881-14b242b83b83


Create a Boolean user setting “LoadFinished” and set it to be false.

In the Splash Screen load event add this to the start;

My.Settings.LoadFinished = False

and at the end of the event;


My.Settings.LoadFinished = True

In ApplicationEvents file add this;


Private Sub MyApplication_Startup(sender As Object, e _
As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs)_
Handles Me.Startup
 
            Try
                If Not Me.SplashScreen Is Nothing Then
                    While My.Settings.LoadFinished = False
                        System.Threading.Thread.Sleep(50)
                    End While
                End If
                My.Settings.LoadFinished = False
            Catch ex As Exception
                EmailError(ex)
            End Try
 
End Sub

In my solution, I also needed to enclose the above with the correct namespace and partial class construct;


Namespace My
    Partial Friend Class MyApplication
 
        Private Sub MyApplication_Startup(sender As Object, e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) Handles Me.Startup
            Try
                If Not Me.SplashScreen Is Nothing Then
                    While My.Settings.LoadFinished = False
                        System.Threading.Thread.Sleep(50)
                    End While
                End If
                My.Settings.LoadFinished = False
            Catch ex As Exception
 
            End Try
        End Sub
    End Class
    
End Namespace



Hope this helps somebody!