Saturday 22 December 2012

WPF Validation Adorners in Tab Control Disappear when Tabs Changed

I found recently than the Validation Error Adorners on my WPF Project when used within a Tab Control, would disappear if I changed tabs.

After a little searching, I found this helpful post;

http://karlshifflett.wordpress.com/2008/02/19/wpf-validation-errors-disappear-inside-tabcontrol-when-switching-tabitems/

You basically need to wrap your Tab Control Tab Content within a Adorner Decorator as follows;

<Border>      
    <AdornerDecorator>            
        <StackPanel>                  
            ...           
        </StackPanel>      
    </AdornerDecorator>
</Border>

This “bug” is due to the fact that the Error Adorners are painted on the Adorner Layer, which is discarded when changing tabs. The code above preserves this layer, preventing the Adorners from being lost.

Friday 21 December 2012

Reactivate Windows Embedded 7 180 Day Trial

Recently the 180 Day trial of my development Windows 7 Embedded install expired. This necessitated that I attempt to reset the Grace Period.
The following seems to work;
  • Open Command Prompt under Elevated Privileges
  • Enter “slmgr.vbs /rearm” and press Enter
  • Wait for the command to complete, and ok the dialog box
  • Restart your system
  • Windows should prompt that it is not genuine
  • Open Command Prompt under Elevated Privileges again
  • Enter “slmgr.vbs –atp” and press Enter
  • Ok the Dialog Box
  • Restart Windows
  • Goto your System Properties
  • The machine should now have 180 days once more

Sunday 16 December 2012

Obtaining the Maximum value in a list or Collection using Linq

In order to retrieve the highest value of a column in a list of collection, Linq offers a handy method to achieve this;

Dim maxUnitsInStock = Aggregate prod In db.Products _
                      Into Max(prod.UnitsInStock)

Simple!

Tuesday 4 December 2012

Enabling MVVM INotifiyPropertyChanged in EF 5 POCO Entities created using the EF 5.x DbContext Generator

While combining EF5 with WPF MVVM, I noticed that changes to individual properties within my bound DataContext weren’t updating the UI.

This was of course because the the actual DataContext itself isn’t changing, but only the POCO Properties housed within in. However, each of the POCO Properties don’t individually raise an INotifyPropertyChanged event.

In order to implement this, one must modify the T4 Template provided as part of the EF 5.x DbContext Generator, to insert the extra lines which add the relevant code to Implement the Interface, and raise the INotifiyPropertyChanged Event.

This is performed by making the following modifications to the T4 Template;

(Note, I work in vb.net here, the code will be different for a c'# implementation!)

  1. Open you’re .tt file
  2. Find the Section which loops through all of the Complex Types in your model, which begins with the line “For Each loopComplex As ComplexType…”.
  3. Below the Line saying “Partial <#=Accessibility.ForType(complex)#> Class <#=code.Escape(complex)#>”, add the following two lines of code;

    Implements INotifyPropertyChanged
    Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged

    This Implements the INotifiyPropertyChanged Interface, and adds the Public Events to each of the POCO’s for your Complex Types.

  4. Find the Write Header Sub, which starts with “Public Sub WriteHeader(ByVal fileManager As EntityFrameworkTemplateFileManager)”
  5. Below the “<#” and the line saying “fileManager.StartHeader()”, add the following line of code;



    Imports System.ComponentModel

    This adds a reference to “System.ComponentModel” , which is where INotifiyPropertyChanged lives.
  6. Find the AnyProperty Function, which starts with “Public Function AnyProperty(accessibility As String, type As String….
  7. Replace the whole function with the following code;



    Public Function AnyProperty(accessibility As String, type As String, name As String, getterAccessibility As String, setterAccessibility As String, defaultValue As String)
            Return String.Format( _
                    CultureInfo.InvariantCulture, _
                    "{6}    Private _{0} As {1}{2}{6}" & _
                    "    {3} Property {0} As {1}{6}" & _
                    "        {4}Get{6}" & _
                    "            Return _{0}{6}" & _
                    "        End Get{6}" & _
                    "        {5}Set(ByVal value As {1}){6}" & _
                    "            _{0} = value{6}" & _
                    "            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(""{0}"")){6}" & _
                    "        End Set{6}" & _
                    "    End Property",  _
                    name, _
                    type, _
                    defaultValue, _
                    accessibility, _
                    getterAccessibility, _
                    setterAccessibility, _
                    Environment.NewLine)
        End Function

    This enforces that all Properties are created with their full Getter’s and Setter’s, and adds the code to raise the PropertyChanged Event<

  8. Find the “EntityClassOpening” Function, which starts with the Line “Public Function EntityClassOpening(entity As EntityType) As String
  9. Replace the entire Function with the following Code;



    Public Function EntityClassOpening(entity As EntityType) As String
            Return String.Format( _
                CultureInfo.InvariantCulture, _
                "Partial {0} {1}Class {2}{3}{4}{5}{4}{6}", _
                Accessibility.ForType(entity), _
                _code.SpaceAfter(_code.MustInheritOption(entity)), _
                _code.Escape(entity), _
                _code.StringBefore(Environment.NewLine & "         Inherits ", _typeMapper.GetTypeName(entity.BaseType)), _
                Environment.NewLine, _
                "Implements INotifyPropertyChanged", _
                "Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged")
        End Function

    This adds the Implementation and Public Event for the INotifyPropertyChanged Interface

  10. Save your template, you may need to open your Model and save this also. Finall build your project, and you should have some fully declared Properties along with the INotifiyPropertyChanged code!


I hope this helps!

Tuesday 20 November 2012

Using Reflection to retrieve Entity Framework Data using a Column Name String

If you ever need to retrieve data from EF using the name of a column, rather than the built in Intellisense, then the following vb.net code snippet may help.

GetType(TypeOfEntity).GetProperty(NameOfColumn).GetValue(ActualEntity, Nothing)


  • TypeOfEntity is the name of the Entity from which you wish to retrieve data.
  • NameOfColumn is obviously the Name of the Column from which you wish to retrieve data.
  • ActualEntity is a reference to the Entity itself, from which the data is to be retrieved.

The above can help if you need to retrieve data based on a column name which is defined by another function. Such as in the following example;

You have a table called Users with columns called Screen1Edit and Screen2Edit.

You can then retrieve the values in Screen1Edit or Screen2Edit depending upon which you require, supplied in a variable called strScreenName;


GetType(Users).GetProperty(strScreenName).GetValue(Users, Nothing)

Obviously you must be careful to supply the exact name of the column into the Column Name!

Note: For c# replace GetType with TypeOf.

SQL Server 2008 R2 Management Studio (SSMS) Open File Dialog slow

A quick tip if your SSMS is slow when using the Open File or Save File Dialog Boxes…. Disconnect any Network Shares which are unreachable.

Wednesday 7 November 2012

Enabling Word Wrap in the WPF DataGrid Column Headers

To enable Word Wrapping in the WPF Data Grid Column Header, simply add the following code snippet to your Application.xaml file;

<Style TargetType="{x:Type primitives:DataGridColumnHeader}">
    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <TextBlock TextWrapping="Wrap" Text="{Binding}"></TextBlock>
            </DataTemplate>
        </Setter.Value>
    </Setter>
</Style>

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!

Tuesday 25 September 2012

Command Line Parameter trailing backlash problem

I am currently working on a small console application which takes in a path name via the Command Line Parameters, parses the given path, and produces an XML file listing each folder and file.

I am running the application as a Post Build event in Visual Studio, passing in the $(TargetDir) macro as;

"c:\Program Files\CreateUpdateXML\CreateUpdateXML.exe" "$(TargetDir)\"

You’ll notice the extra trailing backslash after the Macro.

“Visual studio already adds a trailing backslash though!”

Yes… You’re right… However, a trailing backslash followed by quotation marks is converted to an Escape by Windows.

To work around this issue, you must escape the backslash, forcing windows to use it. This is achieved by simply adding another backslash to the path.

Sunday 23 September 2012

WPF MVVM DataGrid Column Collection Binding

In my efforts to “MVVM-ify” my WPF application as much as possible, I ran into the need to Data Bind the Columns Collection of a DataGrid.

After some searching on StackOverflow, I found a neat solution by David Osborn;

http://stackoverflow.com/questions/3065758/wpf-mvvm-datagrid-dynamic-columns

This solution was in C#, so I converted it to VB;

 Imports System.Collections.ObjectModel  
Imports System.Collections.Specialized
Namespace Controls
Public NotInheritable Class DataGridExtension
Private Sub New()
End Sub
Public Shared Function GetColumns(obj As DependencyObject) As ObservableCollection(Of DataGridColumn)
Return DirectCast(obj.GetValue(ColumnsProperty), ObservableCollection(Of DataGridColumn))
End Function
Public Shared Sub SetColumns(obj As DependencyObject, value As ObservableCollection(Of DataGridColumn))
obj.SetValue(ColumnsProperty, value)
End Sub
Public Shared ReadOnly ColumnsProperty As DependencyProperty = DependencyProperty.RegisterAttached("Columns", _
GetType(ObservableCollection(Of DataGridColumn)), _
GetType(DataGridExtension), _
New UIPropertyMetadata(New ObservableCollection(Of DataGridColumn)(), AddressOf OnDataGridColumnsPropertyChanged))
Private Shared Sub OnDataGridColumnsPropertyChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
If d.GetType = GetType(DataGrid) Then
Dim myGrid As DataGrid = TryCast(d, DataGrid)
Dim Columns As ObservableCollection(Of DataGridColumn) = DirectCast(e.NewValue, ObservableCollection(Of DataGridColumn))
If Columns IsNot Nothing Then
myGrid.Columns.Clear()
If Columns IsNot Nothing AndAlso Columns.Count > 0 Then
For Each dataGridColumn As DataGridColumn In Columns
myGrid.Columns.Add(dataGridColumn)
Next
End If
AddHandler Columns.CollectionChanged, Sub(sender As Object, args As NotifyCollectionChangedEventArgs)
If args.NewItems IsNot Nothing Then
For Each column As DataGridColumn In args.NewItems.Cast(Of DataGridColumn)()
myGrid.Columns.Add(column)
Next
End If
If args.OldItems IsNot Nothing Then
For Each column As DataGridColumn In args.OldItems.Cast(Of DataGridColumn)()
myGrid.Columns.Remove(column)
Next
End If
End Sub
End If
End If
End Sub
End Class
End Namespace

Then, in order to use the above, make sure you include the namespace in your XAML resources, for instance;


 xmlns:w="clr-namespace:MyApplication1.Controls"  


Then add the following to your DataGrid;


 w:DataGridExtension.Columns="{Binding Path=DataContext.DataGridColumns, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"  


Also, make sure you set AutoGenerateColumns to False.


Then go ahead and add you property in your View Model;

     ''' <summary>  
''' The DataGrid Columns
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Property DataGridColumns As ObservableCollection(Of DataGridColumn) Implements Interfaces.iMasterDetailsViewModel(Of T).DataGridColumns
Get
Return _DataGridColumns
End Get
Set(value As ObservableCollection(Of DataGridColumn))
If value.Equals(_DataGridColumns) = False Then
_DataGridColumns = value
OnPropertyChanged("DataGridColumns")
End If
End Set
End Property

You can then add a bunch of columns as follows;

 Dim cols As New ObservableCollection(Of DataGridColumn)  
Dim col As New DataGridTextColumn
cols.Add(New DataGridTextColumn With {.Binding = New System.Windows.Data.Binding("Customer_Code"), .Header = "Customer Code", .Width = 100})
cols.Add(New DataGridTextColumn With {.Binding = New System.Windows.Data.Binding("Name"), .Header = "Name", .Width = 250})
DataGridColumns = cols

Seems like quite a nice neat solution.


However, do bear in mind that, as Rakshit Bakshi points out in the answer;



“The above code will do the work in general case. However, it will fail when you hide the datagrid and make it visible again. Because the columns property will show that there are 0 columns when they are hidden and as the columns property is changed, the callback will be fired and it will try to add the columns again, but physically columns does exist in the datagrid so the code will fail with an exception saying can't add duplicate columns.”

Friday 21 September 2012

MVVM: Binding a Linq Query result to a DataGrids’ ItemSource doesn’t update the UI

While creating Desktop Applications using WPF, I always employ the MVVM model if I can. This model is not only great at developing testable n-tier applications, but of course is also highly recommended by Microsoft.

However, as with most software development, there are nearly always specific methods to employ for certain processes and functions.

One of these is while Binding Linq Queries, through a bound property in your ViewModel.

Linq queries as standard return an IEnumerable type. This is fine for the most part, and fits nicely with MVVM, allowing Where statements etc.

However, if you then bind this IEnumerable or List type to a DataGrid, through a property in your ViewModel, and try adding and removing items using the .Add and .Remove extension methods, it becomes apparent that the UI isn’t updating.

This is because the Dot Net Framework has performed certain optimisations, which unfortunately cause it to miss the Add and Remove changes when dealing with IEnumerable and List type objects.

One way around this is to completely break the MVVM model and call the Items.Refresh method on the UI DataGrid. However, this is very very bad practise, and circumnavigates the entire purpose for using MVVM in the first place.

The correct solution is to replace the IEnumerable(of T) or List(of T) with an ObservableCollection(of T).

The Observable collection will automatically notify the UI through the ViewModel, whenever an Add or Remove is called on the collection.

Do remember to import the System.Collections.ObjectModel namespace of course!

Tuesday 31 July 2012

Setting up the Zoom 4501 3G Router with an o2 Huawei E173 Dongle

I recently worked on a project required network access where no Network Connection was available on site.

I opted for the Zoom 4501 3G router…

Zoom Model 4501 Image

http://www.zoomtel.com/products/4501.html

I paired this with an O2 Huawei E173 Dongle, using a 2GB allowance Pay as you go SIM.

O2 Dongle

http://www.o2.co.uk/broadband/mobile-broadband/o2-dongle

The Zoom 4501 supports a wide range of Mobile Broadband Dongles, including the O2 E173 I chose;

http://www.zoomtel.com/products/4501-4506_device-comp.html

For some reason, my Dongle and Router wouldn’t automatically setup, so I needed to discover the correct settings.

After some trial and error, and referring to the PC Huawei Connection Manager, I was able to find some settings which worked;

APN: m-bb.o2.co.uk
PIN Code: Leave Empty
Dialed Number: *99#
Username: o2bb
Password: password
Authentication: Auto
Primary DNS: 193.113.200.200
Secondary DNS: 193.113.200.201

Step by Step Instructions:

Setting the router up with the above settings can be achieved as follows;

  1. Connect the Router to the mains using the Supplied PSU
  2. Connect the Router to your network socket using the supplied Network Cable
  3. Connect the Dongle to the Routers’ USB Socket which is found on the rear of the Router between the “POWER” and “LAN” Sockets
  4. Once the Router has powered up, open your browser and head for
    http://192.168.1.1
  5. At this point  will be shown one of two screens, depending upon whether your Router has automatically setup the Dongle or not. It’s worthwhile waiting for at least 30secs to a minute at this screen, as it takes the router a little while to set the Dongle up if it’s going to.

    Figure 1: Router Attempting / Failed to Setup Dongle:

    Zoom 3G router   O2 E173 Dongle Setup 1

    Figure 2: Dongle Setup successfully;

    Zoom 3G router   O2 E173 Dongle Setup 1a
  6. If you see the screen as shown in Figure 2, then everything has been setup automatically, and you should be able to browse the internet!

    However, If the screen continues to show Connecting, as shown in Figure 1, for over a minute, it’s safe to assume that the Router has given up and we need to manually configure the Router.
  7. Where the Interface is prompting for the System Password, enter “admin” and hit the “Logon” button
  8. You will be presented with the choice to either use the “Wizard”, or go with an “Advanced Setup”;

    Figure 3: Wizard / Advanced Setup Choice

    Zoom 3G router   O2 E173 Dongle Setup 2
  9. We will be using the “Wizard” option, so you can simply press the “Enter” button to continue
  10. The Wizard will give you a run down of the Steps which will be taken to set the Router up;

    Figure 4: Wizard Steps

    Zoom 3G router   O2 E173 Dongle Setup 3
  11. Hit next to proceed to the Password Setup step. Here you can feel free to setup your own admin password, or simply leave it all blank to stick with the default “admin” password;

    Figure 5: Password Setup

    Zoom 3G router   O2 E173 Dongle Setup 4
  12. Once your happy, hit next to move onto the Time Setup step. Select your timezone and press next;

    Figure 6: Time Zone Setup

    Zoom 3G router   O2 E173 Dongle Setup 5
  13. Once again, press Next to move onto the WAN Setup. For the purpose I purchased the router and Dongle for, I will be using the last option “You want to use your cellular modem to connect to the internet”;

    Figure 7: WAN Setup

    Zoom 3G router   O2 E173 Dongle Setup 6
  14. Pressing Next will now present you with the 3G/4G setup screen. This is where we will enter our settings to get the Dongle up and running. Enter the settings as follows;

    LAN IP Address: 192.168.1.1 (Should default to this)
    APN: m-bb.o2.co.uk
    PIN Code: Leave Empty
    Dialed Number: *99#
    Account: o2bb
    Password: password

    Your screen should now look like the following;

    Figure 8: 3G / 4G Setup

    Zoom 3G router   O2 E173 Dongle Setup 7

    Note: Where entering o2 Make sure you enter the letter ‘o’ rather than the number ‘0’.
  15. Pressing Next will show the Wireless Settings step. Feel free to set your wireless network up anyway you wish. For the purposes of my requirements, I have disabled the Wireless Network;

    Figure 9: WIFI Setup

    Zoom 3G router   O2 E173 Dongle Setup 8
  16. Pressing Next again will show the Summary screen. Here you can confirm that you have entered everything correctly. Once your happy, you should tick the “Do you want to proceed with the network testing?” and “The Ethernet Port will be used as LAN Port after saving. Confirm?” Checkboxes;

    Figure 10: Confirm Settings

    Zoom 3G router   O2 E173 Dongle Setup 9
  17. Pressing next will cause begin a connection test. Here the modem is waiting for the Dongle to connect and for a connection to the internet to be available.

    Figure 11: Connection Test

    Zoom 3G router   O2 E173 Dongle Setup 10
  18. If everything has worked you will be shown the following success screen;

    Figure 12: Connection Success

    Zoom 3G router   O2 E173 Dongle Setup 11

    However if the connection has failed, which happenned to me the first time, then you may see the Connection Failed Screen;

    Figure 13: Connection Failed

    Zoom 3G router   O2 E173 Dongle Setup 11a
  19. At this point you may need to enter some further settings which are hidden away in the Advanced Section of the Router. So, press the “Advanced” link in the menu bar towards the top of the screen to access the Advanced Settings screen;

    Figure 14: Advanced Settings

    Zoom 3G router   O2 E173 Dongle Setup 12
  20. The Settings we need to modify / add can be found in the “Basic Setup” screen, which can be accessed using the Menu on the left of the screen;

    Figure 15: Basic Setup

    Zoom 3G router   O2 E173 Dongle Setup 13
  21. Enter the settings exactly as below and press Save;

    APN: m-bb.o2.co.uk
    PIN Code: Leave Empty
    Dialed Number: *99#
    Username: o2bb
    Password: password
    Authentication: Auto
    Primary DNS: 193.113.200.200
    Secondary DNS: 193.113.200.201
  22. You will now be prompted that the “change doesn’t take effect until router is rebooted”. So we must reset the router for the changes we made to take effect. To reset the router we must use the “Toolbox” screen, which can be accessed by pressing the last link on the right, shown near the top of the screen;

    Figure 16: ToolBox

    Zoom 3G router   O2 E173 Dongle Setup 15
  23. Press the “Reboot” link in the menu on the left of the screen, and ok the message box to confirm. The router will now begin to reset;

    Figure 17: Rebooting

    Zoom 3G router   O2 E173 Dongle Setup 16
  24. Once the reboot is complete after upto 30 seconds, and all being well, you should now be connected. This is obvious if you look at the LED on the 3G dongle, which should now be a steady Greenish Blue colour, rather than a slowly flashing blue;

    Figure 18: All Connected!

    Zoom 3G router   O2 E173 Dongle Setup 17
  25. If for some reason you aren’t connected, then double check all the settings you entered above, and repeat the procedure.


Hopefully this proves useful to someone else out there!