Friday, December 16, 2011

Parsing file paths

Since I can't seem to remember these functions that work on a full path with filename:

System.IO.Path.GetFileName - extracts the filename part with extensions and loses the leading path
System.IO.Path.GetDirectoryName - extracts the leading path and loses the filename with extension
System.IO.Path.GetExtension - extracts just the extension from the path

Tuesday, December 13, 2011

Handling autonumber/key fields in a dataset

Problem: If you want to use a dataset and dataadapter exclusively for managing the updates to a table, and the table was designed with an autonumber field as as the primary key, you have to fill in the primary key after the record is inserted.

Solution: The insert statement of the data adapter can't contain the primary key column. You let the underlying data provider fill in the key value. I have taken two solution routes, but they do the same thing. After inserting the row, I updated the row in the mainline code with the new key value in the datagridview and the datatable. My second, more elegant solution, was to attach a row updated event handler to the data adapter. I then fill in the primary key value in the data row. The datagridview picked up the update automatically.


 Private Sub Add_Autonumber(s As Object, e As System.Data.OleDb.OleDbRowUpdatedEventArgs) Handles TViewAdapter.RowUpdated
        If e.StatementType = StatementType.Insert Then
            Dim NewID As Integer
            Dim idCMD As New OleDbCommand("SELECT @@IDENTITY", e.Command.Connection)
            NewID = idCMD.ExecuteScalar
            e.Row("ID") = NewID
        End If
    End Sub

SELECT @@IDENTITY is specific to the oledbconnection for Access databases. SQL has a similar statement. You must do this on the connection that generated the autonumber, hence the command references the rowupdated argument's connection that was passed in

Thursday, December 8, 2011

Opening documents in a browser on a form

It was handy to have a preview version of a document on a form.
This is easy for pictures, but not so easy for things like word or PDF

By invoking the webbrowser control, I was able to do that for a PDF file pretty simply
It handles the basic PDF navigation

For Word, its opened up word from the browser pane
To suppress that, I had to change the registry entries for the document class

BrowserFlags 0x8 or 0x9 indicates that a particular app should open in its own window when its associated file is clicked (as opposed to opening within IE. For eg: MS Office docs). 0x10 indicates that when a link is clicked, the existing window should be reused instead of opening a new window. (0x22 in windows explorer - when you open a folder, it opens in an existing window instead of opening a new one). 0x24 or 0x00 indicates that the viewer should be embedded in the browser. 


EditFlags indicates what explorer should do with a particular filetype and/or defines what class it is.
00 01 00 00 turns off the "Confirm open after download" box in IE.
00 00 00 means no special attributes have been defined for that class.
02 00 00 00 is used for the mailto: protocol for mail clients.


The following settings work for the various MS apps


[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Word.Document.8] "BrowserFlags"=dword:80000024 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Word.RTF.8] "BrowserFlags"=dword:80000024 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Word.Document.12] "BrowserFlags"=dword:80000024 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Word.DocumentMacroEnabled.12] "BrowserFlags"=dword:80000024 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Excel.Sheet.8] "BrowserFlags"=dword:80000A00 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Excel.Sheet.12] "BrowserFlags"=dword:80000A00 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Excel.SheetMacroEnabled.12] "BrowserFlags"=dword:80000A00 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Excel.SheetBinaryMacroEnabled.12] "BrowserFlags"=dword:80000A00 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PowerPoint.Show.8] "BrowserFlags"=dword:800000A0 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PowerPoint.Show.12] "BrowserFlags"=dword:800000A0 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PowerPoint.ShowMacroEnabled.12] "BrowserFlags"=dword:800000A0 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PowerPoint.SlideShow.8] "BrowserFlags"=dword:800000A0 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PowerPoint.SlideShow.12] "BrowserFlags"=dword:800000A0 [HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PowerPoint.SlideShowMacroEnabled.12] "BrowserFlags"=dword:800000A0

Monday, November 28, 2011

Enumerators in datagridviews - careful

Wrote some code that was doing some copying of rows in datagridviews based on what the user had selected.
I should have seen this one coming, but the selected rows changes out from under you if you write code like this:

For each SelectedRow as DataGridViewRow in dgvSource.SelectedRows
  dgvSource.Rows.Add(NewRowBasedOnSelectedRow)
Next

As soon as you add the row, the selected rows property gets reset.
I actually trapped the selection changing. It goes from what is was, to 0, to 1.

The workaround was simple - build a second list of rows to process before I start adding to the source
The annoying this is if you do this kind of thing with a list, you get an exception thrown because the enumerator fails. The datagridview must be trapping the exception.


Getting autonumber/identity fields after row add oledb

Adding a row to a table where autonumber is set on the field means you don't know the autonumber field contents until after the row has actually been added. This is problematic when you're doing some referential integrity in oledb.

To determine the autonumber field contents, execute the following just after the row is added

Dim cmdNewID As New OleDbCommand("SELECT @@IDENTITY", TheOledbDataConnection)

Dim NewTakeoffId as Integer = cmdNewID.ExecuteScalar

Friday, November 18, 2011

Finding absolute position of a control on a windows form

I wanted to overlay a datagridview with a dropdown depending on certain conditions, so using a datagridview combo box which does it always didnt work

So I had the bright idea of creating a combobox on the fly, and I wanted it to land right on the cell.
The trick was the cell is in a datagrid, and the datagrid is nested in some panels

So I had to find out where I was from the base of the form.
This code does that

Private Function GetPositionInForm(ByVal ctrl As Control) As Point
        Dim P As Point = ctrl.Location
        Dim Parent As Control = ctrl.Parent
        While Parent.Name <> ctrl.FindForm.Name
            P.Offset(Parent.Location.X, Parent.Location.Y)
            Parent = Parent.Parent
        End While
        Return P
    End Function

When using it in a grid, you need the final touch of the row and cell position

Dim NewPosition As Point = GetPositionInForm(dgvSourceTakeoff)
Dim CellRectangle As Rectangle = grid.GetCellDisplayRectangle(col,row,True)
NewPosition.X += CellRectangle.Location.X
NewPosition.Y += CellRectangle.Location.Y
cboSelector.Location = NewPosition

First post

So I keep learning all sorts of technical lessons that I don't want to lose

I finally had the bright idea of blogging them.

That way I won't lose them, and maybe someone else will find them useful

And away we go (I miss you Ed and Johnny)