<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>TechKnowSolve Blog</title>
	<atom:link href="http://www.techknowsolve.com/blog/?feed=rss2" rel="self" type="application/rss+xml" />
	<link>http://www.techknowsolve.com/blog</link>
	<description>Technical Hints and Tips from TechKnowSolve.com</description>
	<lastBuildDate>Thu, 19 Apr 2012 20:37:23 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Make disabled DataGridView appear grayed out</title>
		<link>http://www.techknowsolve.com/blog/?p=116</link>
		<comments>http://www.techknowsolve.com/blog/?p=116#comments</comments>
		<pubDate>Tue, 18 Oct 2011 05:57:54 +0000</pubDate>
		<dc:creator>MaryD</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[VB.NET]]></category>

		<guid isPermaLink="false">http://www.techknowsolve.com/blog/?p=116</guid>
		<description><![CDATA[Usually, when you set a control&#8217;s Enabled property to False, the control will appear grayed out in the form.  However, a DataGridView control whose Enabled property is False looks the same as one whose Enabled property is True.  Once you try to click in to the DataGridView to edit or add something, you&#8217;ll find that [...]]]></description>
			<content:encoded><![CDATA[<p>Usually, when you set a control&#8217;s <a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.control.enabled.aspx" target="_blank">Enabled</a> property to False, the control will appear grayed out in the form.  However, a <a href="http://msdn.microsoft.com/en-us/library/e0ywh3cz.aspx" target="_blank">DataGridView</a> control whose Enabled property is False looks the same as one whose Enabled property is True.  Once you try to click in to the DataGridView to edit or add something, you&#8217;ll find that it is not enabled, but it doesn&#8217;t look any different &#8211; which can be confusing to users, especially if it is on a form with other disabled controls that <em>are</em> grayed out.</p>
<p>Here is a little utility function that will manually gray out the headers and cells of a DataGridView.  It doesn&#8217;t gray out check box columns, but then the checkboxes aren&#8217;t grayed out in a disabled <a href="http://msdn.microsoft.com/en-us/library/3ss05xx6.aspx" target="_blank">CheckedListBox</a>, either, so I figure this is close enough:</p>
<p>    <code>Private Sub DisableGrid(ByVal grid As DataGridView)<br />
        With grid<br />
            .Enabled = False<br />
            .ForeColor = Color.Gray<br />
            For Each col As DataGridViewColumn In .Columns<br />
                col.HeaderCell.Style.ForeColor = Color.Gray<br />
            Next<br />
        End With<br />
    End Sub</code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.techknowsolve.com/blog/?feed=rss2&amp;p=116</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>CellValueChanged event doesn&#8217;t fire when in DataGridView</title>
		<link>http://www.techknowsolve.com/blog/?p=98</link>
		<comments>http://www.techknowsolve.com/blog/?p=98#comments</comments>
		<pubDate>Fri, 14 Oct 2011 22:08:47 +0000</pubDate>
		<dc:creator>MaryD</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[VB.NET]]></category>

		<guid isPermaLink="false">http://www.techknowsolve.com/blog/?p=98</guid>
		<description><![CDATA[So here&#8217;s the scenario &#8211; you&#8217;ve got some kind of code that you want to run whenever the value of a cell changes in a DataGridView.  You write some code in the DataGridView&#8217;s CellValueChanged event, but you notice that it doesn&#8217;t fire if you are editing a cell and then you close the form without [...]]]></description>
			<content:encoded><![CDATA[<p>So here&#8217;s the scenario &#8211; you&#8217;ve got some kind of code that you want to run whenever the value of a cell changes in a <a href="http://msdn.microsoft.com/en-us/library/e0ywh3cz.aspx" target="_blank">DataGridView</a>.  You write some code in the DataGridView&#8217;s <code><a href="http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.cellvaluechanged.aspx" target="_blank">CellValueChanged</a></code> event, but you notice that it doesn&#8217;t fire if you are editing a cell and then you close the form without first tabbing/clicking out of the DataGridView (I noticed this when working on my <a href="http://www.techknowsolve.com/blog/?p=90">IsDirty</a> class, described in my last post).</p>
<p>There is a very quick and dirty solution to this problem &#8211; in the <code>FormClosing</code> event, set focus on another form element, like a textbox (for example, <code>txtFirstName.Focus()</code>).  This will cause the focus to leave the DataGridView, which will cause the <code>CellValueChanged</code> event to fire, which will cause your <code>CellValueChanged</code> code to run.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.techknowsolve.com/blog/?feed=rss2&amp;p=98</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IsDirty Change Tracker for WinForms</title>
		<link>http://www.techknowsolve.com/blog/?p=90</link>
		<comments>http://www.techknowsolve.com/blog/?p=90#comments</comments>
		<pubDate>Fri, 14 Oct 2011 19:17:31 +0000</pubDate>
		<dc:creator>MaryD</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[VB.NET]]></category>

		<guid isPermaLink="false">http://www.techknowsolve.com/blog/?p=90</guid>
		<description><![CDATA[Here is a ChangeTracker class I developed for use in WinForms scenarios &#8211; it is adapted from an article I found at The Code Project site.  In testing it, I also came across a problem and work-around for DataGridView controls &#8211; see the next blog post for details.
To use this class, download the class file and add it [...]]]></description>
			<content:encoded><![CDATA[<p>Here is a ChangeTracker class I developed for use in WinForms scenarios &#8211; it is adapted from an <a href="Namespace TKS" target="_blank">article</a> I found at <a href="http://www.codeproject.com/" target="_blank">The Code Project</a> site.  In testing it, I also came across a problem and work-around for <a href="http://msdn.microsoft.com/en-us/library/e0ywh3cz.aspx" target="_blank">DataGridView</a> controls &#8211; see the <a href="http://www.techknowsolve.com/blog/?p=98">next blog post</a> for details.</p>
<p>To use this class, <a href="http://www.fileden.com/files/2011/10/14/3209227//ChangeTracker.zip">download</a> the class file and add it to your project.  In the form in which you want to track changes, add a form level variable:</p>
<p><code>Private changeTracker As TKS.ChangeTracker</code></p>
<p>In the form&#8217;s <code>Load</code> event, put the following code:</p>
<p><code>'set up change tracking<br />
Me.changeTracker = New TKS.ChangeTracker(Me)</code></p>
<p>In the form&#8217;s <code>FormClosing</code> event, put the following code (you can see a clue as to the <a href="http://www.techknowsolve.com/blog/?p=98">next blog entry</a> in the first line):</p>
<p><code>'set focus on a textbox control, to make sure that datagrid CellChangeValue event fires if necessary<br />
Me.txtFirstName.Focus()</code></p>
<p><code>'check if form is dirty<br />
If Me.changeTracker.IsDirty Then<br />
      Dim result = MessageBox.Show("Would you like to save changes before exiting?", "Save Changes", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question)<br />
      Select Case result<br />
           Case Windows.Forms.DialogResult.Yes<br />
                Me.Save()<br />
                Me.changeTracker.SetAsClean()<br />
           Case Windows.Forms.DialogResult.No<br />
'no action needed, unless form is hidden instead of closed. Then, you might want to re-set the change tracker<br />
                Me.changeTracker.SetAsClean()<br />
           Case Windows.Forms.DialogResult.Cancel<br />
                e.Cancel = True<br />
      End Select<br />
End If</code></p>
<p>And here is the code for the class itself.  It is written to check TextBoxes, CheckBoxes, ComboBoxes, CheckedListBoxes and DataGridViews, but you can adapt it to check whatever you want. (You can also <a href="http://www.fileden.com/files/2011/10/14/3209227//ChangeTracker.zip">download</a> the code.):</p>
<p><code>Namespace TKS<br />
    Public Class ChangeTracker</code></p>
<p><code>#Region "Data Members"<br />
        Private _frmTracked As Form<br />
        Private _ctlData As Generic.Dictionary(Of String, TKS.ChangeTracker.ControlInfo)<br />
#End Region</code></p>
<p><code>#Region "Constructor"<br />
        Public Sub New(ByVal frm As Form)<br />
            'initialize data members<br />
            _frmTracked = frm<br />
            _ctlData = New Generic.Dictionary(Of String, TKS.ChangeTracker.ControlInfo)</code></p>
<p>            <code>'get initial control values, and hook up tracking events<br />
            Me.SetUpControlTracking(_frmTracked.Controls, isEventsAssigned:=False)<br />
        End Sub<br />
#End Region</code></p>
<p><code>#Region "Properties"<br />
        Public ReadOnly Property IsDirty As Boolean<br />
            Get<br />
                'loop through the change-tracker object for each control.  If any is dirty, exit loop and return true<br />
                For Each kvPair As KeyValuePair(Of String, ControlInfo) In _ctlData<br />
                    If kvPair.Value.IsDirty Then Return True<br />
                Next<br />
                'if we've gotten here, then nothing is dirty - return false<br />
                Return False<br />
            End Get<br />
        End Property<br />
#End Region</code></p>
<p><code>#Region "Methods"<br />
        Public Sub SetAsClean()<br />
            'clear previous data<br />
            _ctlData.Clear()<br />
            'get new control values - don't need to hook up events as they are already hooked up<br />
            Me.SetUpControlTracking(_frmTracked.Controls, isEventsAssigned:=True)<br />
        End Sub</code></p>
<p>        <code>Private Sub SetUpControlTracking(ByVal col As Control.ControlCollection, ByVal isEventsAssigned As Boolean)<br />
            'loop control collection, add control value to info collection, add event handler to designated controls if it hasn't been done already<br />
            For Each ctl As Control In col<br />
                If TypeOf ctl Is TextBox Then<br />
                    Dim txtbox = CType(ctl, TextBox)<br />
                    _ctlData.Add(txtbox.Name, New ControlInfo(txtbox.Text, False))<br />
                    If Not isEventsAssigned Then AddHandler txtbox.TextChanged, AddressOf TextBox_TextChanged</code></p>
<p>                <code>ElseIf TypeOf ctl Is CheckBox Then<br />
                    Dim chkbox = CType(ctl, CheckBox)<br />
                    _ctlData.Add(chkbox.Name, New ControlInfo(chkbox.Checked.ToString, False))<br />
                    If Not isEventsAssigned Then AddHandler chkbox.CheckedChanged, AddressOf CheckBox_CheckedChanged</code></p>
<p>                <code>ElseIf TypeOf ctl Is ComboBox Then<br />
                    Dim cbobox = CType(ctl, ComboBox)<br />
                    _ctlData.Add(cbobox.Name, New ControlInfo(cbobox.SelectedValue.ToString, False))<br />
                    If Not isEventsAssigned Then AddHandler cbobox.SelectedIndexChanged, AddressOf ComboBox_SelectedIndexChanged</code></p>
<p>                <code>ElseIf TypeOf ctl Is CheckedListBox Then<br />
                    Dim lstbox = CType(ctl, CheckedListBox)<br />
                    _ctlData.Add(lstbox.Name, New ControlInfo(Me.GetAllChecked(lstbox), False))<br />
                    If Not isEventsAssigned Then AddHandler lstbox.SelectedIndexChanged, AddressOf CheckedListBox_SelectedIndexChanged</code></p>
<p>                <code>ElseIf TypeOf ctl Is DataGridView Then<br />
                    Dim dg = CType(ctl, DataGridView)<br />
                    Dim key As String<br />
                    'will need to loop datagrid and get each cell value.  Concatenate grid name, row index, cell index to create unique key for each cell.  Skip rows with no values.<br />
                    For Each row As DataGridViewRow In dg.Rows<br />
                        If Not row.IsNewRow Then<br />
                            For Each cell As DataGridViewCell In row.Cells<br />
                                key = dg.Name &amp; row.Index.ToString &amp; cell.ColumnIndex.ToString<br />
                                _ctlData.Add(key, New ControlInfo(cell.Value.ToString, False))<br />
                            Next<br />
                        End If<br />
                    Next<br />
                    If Not isEventsAssigned Then AddHandler dg.CellValueChanged, AddressOf DataGridView_CellValueChanged<br />
                End If</code></p>
<p>                <code>'recursively get values from, add event handlers to, child controls<br />
                If ctl.HasChildren Then<br />
                    SetUpControlTracking(ctl.Controls, isEventsAssigned)<br />
                End If<br />
            Next<br />
        End Sub<br />
#End Region</code></p>
<p><code>#Region "Event Handlers"<br />
        'Event handlers will:<br />
        '  - get control's change-tracker object from collection<br />
        '  - get control's new value and pass to 'CheckIfDirty' method of change-tracker object<br />
        '  - if new value is different from saved value, 'CheckIfDirty' will mark control as dirty<br />
        '  - if new value restores saved value, 'CheckIfDirty' will change control back to clean<br />
        Private Sub TextBox_TextChanged(ByVal sender As Object, ByVal e As EventArgs)<br />
            Dim txtbox = CType(sender, TextBox)<br />
            If _ctlData.ContainsKey(txtbox.Name) Then<br />
                _ctlData(txtbox.Name).CheckIfDirty(txtbox.Text)<br />
            End If<br />
        End Sub</code></p>
<p>        <code>Private Sub CheckBox_CheckedChanged(ByVal sender As Object, ByVal e As EventArgs)<br />
            Dim chkbox = CType(sender, CheckBox)<br />
            If _ctlData.ContainsKey(chkbox.Name) Then<br />
                _ctlData(chkbox.Name).CheckIfDirty(chkbox.Checked.ToString)<br />
            End If<br />
        End Sub</code></p>
<p>        <code>Private Sub ComboBox_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)<br />
            Dim cbobox = CType(sender, ComboBox)<br />
            If _ctlData.ContainsKey(cbobox.Name) Then<br />
                _ctlData(cbobox.Name).CheckIfDirty(cbobox.SelectedValue.ToString)<br />
            End If<br />
        End Sub</code></p>
<p>        <code>Private Sub CheckedListBox_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs)<br />
            Dim lstbox = CType(sender, CheckedListBox)</code></p>
<p>            <code>If _ctlData.ContainsKey(lstbox.Name) Then<br />
                _ctlData(lstbox.Name).CheckIfDirty(Me.GetAllChecked(lstbox))<br />
            End If<br />
        End Sub</code></p>
<p>        <code>Private Sub DataGridView_CellValueChanged(ByVal sender As Object, ByVal e As DataGridViewCellEventArgs)<br />
            Dim dg = CType(sender, DataGridView)<br />
            Dim row = dg.Rows(e.RowIndex)<br />
            Dim cell = row.Cells(e.ColumnIndex)<br />
            Dim key As String = dg.Name &amp; e.RowIndex.ToString &amp; e.ColumnIndex.ToString</code></p>
<p>            <code>'if key exists, check against initial value<br />
            If _ctlData.ContainsKey(key) Then<br />
                _ctlData(key).CheckIfDirty(cell.Value.ToString)<br />
            Else<br />
                'if key doesn't exist, this is a new row - add cell, and set as dirty  (set value to something unlikely so control will always evaluate as dirty)<br />
                _ctlData.Add(key, New ControlInfo("-TKS", True))<br />
            End If<br />
        End Sub<br />
#End Region</code></p>
<p><code>#Region "Get All Selected Values in List"<br />
        Private Function GetAllChecked(ByVal lstBox As CheckedListBox) As String<br />
            'loop through 'CheckedIndices' collection and concatenate<br />
            Dim sb As New System.Text.StringBuilder<br />
            For Each i As Integer In lstBox.CheckedIndices<br />
                sb.Append(i.ToString)<br />
            Next<br />
            Return sb.ToString<br />
        End Function<br />
#End Region</code></p>
<p><code>#Region "ControlInfo Class"<br />
        'change-tracker object - stores control's initial value and evaluates new values<br />
        Private Class ControlInfo<br />
            Sub New(ByVal v As String, ByVal dirty As Boolean)<br />
                Value = v<br />
                IsDirty = dirty<br />
            End Sub</code></p>
<p>                <code>Public Property Value As String<br />
            Public Property IsDirty As Boolean</code></p>
<p>                <code>Public Sub CheckIfDirty(ByVal newValue As String)<br />
                If Me.Value.Equals(newValue) Then<br />
                    Me.IsDirty = False<br />
                Else<br />
                    Me.IsDirty = True<br />
                End If<br />
            End Sub<br />
        End Class<br />
#End Region</code></p>
<p>    <code>End Class<br />
End Namespace</code></p>
]]></content:encoded>
			<wfw:commentRss>http://www.techknowsolve.com/blog/?feed=rss2&amp;p=90</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>T-SQL functions to create comma separated list</title>
		<link>http://www.techknowsolve.com/blog/?p=76</link>
		<comments>http://www.techknowsolve.com/blog/?p=76#comments</comments>
		<pubDate>Wed, 29 Jun 2011 01:36:53 +0000</pubDate>
		<dc:creator>MaryD</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[SQL Server]]></category>

		<guid isPermaLink="false">http://www.techknowsolve.com/blog/?p=76</guid>
		<description><![CDATA[Here are a couple of ways to use T-SQL to create a comma separated list of column values in SQL Server.  The first uses FOR XML PATH, and returns a csv for each ID in the table &#8211; this could be used in a table function.
The second uses COALESCE, and returns a csv for a specified [...]]]></description>
			<content:encoded><![CDATA[<p>Here are a couple of ways to use T-SQL to create a comma separated list of column values in SQL Server.  The first uses <a href="http://msdn.microsoft.com/en-us/library/ms345137.aspx#forxml2k5_topic6" target="_blank">FOR XML PATH</a>, and returns a csv for each ID in the table &#8211; this could be used in a <a href="http://www.techrepublic.com/article/building-and-using-table-udfs-in-sql-server/6100403" target="_blank">table function</a>.</p>
<p>The second uses <a href="http://msdn.microsoft.com/en-us/library/ms190349.aspx" target="_blank">COALESCE</a>, and returns a csv for a specified ID &#8211; this could be used in a <a href="http://www.sqlteam.com/article/user-defined-functions" target="_blank">scalar function</a>.  Also, since FOR XML PATH is not available prior to SQL Server 2005, the COALESCE version can be used in SQL Server 2000.</p>
<p>First, let&#8217;s build a <a href="http://odetocode.com/code/365.aspx" target="_blank">table variable</a> to play with:</p>
<p>DECLARE @tblA TABLE(ID INT, Value INT)</p>
<p>INSERT INTO @tblA VALUES(1000,1)<br />
INSERT INTO @tblA VALUES(1000,2)<br />
INSERT INTO @tblA VALUES(1000,3)<br />
INSERT INTO @tblA VALUES(1001,2)<br />
INSERT INTO @tblA VALUES(1001,3)<br />
INSERT INTO @tblA VALUES(1001,4)<br />
INSERT INTO @tblA VALUES(1001,5)</p>
<p>Here&#8217;s the FOR XML PATH version:</p>
<p>SELECT ID,<br />
STUFF(<br />
 (<br />
 select &#8216;, &#8216;+ CAST(value AS VARCHAR)<br />
 from @tblA b<br />
 WHERE a.ID = b.ID<br />
 FOR XML PATH(&#8221;)<br />
 )<br />
,1,1,&#8221;) AS Value<br />
FROM @tblA a<br />
GROUP BY a.ID</p>
<p>Result of query:</p>
<p>ID          Value<br />
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
1000         1, 2, 3<br />
1001         2, 3, 4, 5</p>
<p>And here&#8217;s the COALESCE version:</p>
<p>declare @List varchar(500);<br />
select @List = COALESCE(@List + &#8216;, &#8216;, &#8221;) + cast(Value as varchar(5))<br />
from @tblA<br />
where ID = 1000;<br />
select @List;</p>
<p>Results of query:</p>
<p>Value<br />
&#8212;&#8212;-<br />
1, 2, 3</p>
]]></content:encoded>
			<wfw:commentRss>http://www.techknowsolve.com/blog/?feed=rss2&amp;p=76</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Add maxlength to textarea with jQuery</title>
		<link>http://www.techknowsolve.com/blog/?p=66</link>
		<comments>http://www.techknowsolve.com/blog/?p=66#comments</comments>
		<pubDate>Fri, 01 Apr 2011 18:42:58 +0000</pubDate>
		<dc:creator>MaryD</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[Javascript]]></category>

		<guid isPermaLink="false">http://www.techknowsolve.com/blog/?p=66</guid>
		<description><![CDATA[An html input field has a maxlength attribute to limit the number of characters that can be entered in the field, but an html textarea does not.  However, maxlength functionality can be easily added to textarea controls with a little bit of jQuery.
This snippet looks for textareas that have a maxlength attribute, and limits the number of [...]]]></description>
			<content:encoded><![CDATA[<p>An html <a title="input tag" href="http://www.w3schools.com/tags/tag_input.asp" target="_blank">input field</a> has a <a title="Maxlength property" href="http://www.w3schools.com/tags/att_input_maxlength.asp" target="_blank">maxlength</a> attribute to limit the number of characters that can be entered in the field, but an html <a title="Textarea" href="http://www.w3schools.com/tags/tag_textarea.asp" target="_blank">textarea</a> does not.  However, maxlength functionality can be easily added to textarea controls with a little bit of <a title="jQuery" href="http://jquery.com/" target="_blank">jQuery</a>.</p>
<p>This snippet looks for textareas that have a maxlength attribute, and limits the number of characters to the number in the attribute.  This could use a bit of validation code, perhaps &#8211; making sure that the maxlength value is numeric, for example.  But you get the idea&#8230;</p>
<p>$(document).ready(function(){</p>
<p>    $(&#8216;textarea[maxlength]&#8216;).keyup(function() {</p>
<p>        //get textarea text and maxlength attribute value<br />
        var t = $(this);<br />
        var text = t.val();<br />
        var limit = t.attr(&#8216;maxlength&#8217;);</p>
<p>        //if textarea text is greater than maxlength limit, truncate and re-set text<br />
        if (text.length &gt; limit) {<br />
            text = text.substring(0, limit);<br />
            t.val(text);<br />
        }<br />
    });</p>
<p>});</p>
]]></content:encoded>
			<wfw:commentRss>http://www.techknowsolve.com/blog/?feed=rss2&amp;p=66</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DELETE button not captured by KeyPress event</title>
		<link>http://www.techknowsolve.com/blog/?p=63</link>
		<comments>http://www.techknowsolve.com/blog/?p=63#comments</comments>
		<pubDate>Thu, 17 Jun 2010 17:33:05 +0000</pubDate>
		<dc:creator>MaryD</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[VB.NET]]></category>

		<guid isPermaLink="false">http://www.techknowsolve.com/blog/?p=63</guid>
		<description><![CDATA[A small but important thing &#8211; if you want to capture pressing the DELETE button in a WinForms project, you&#8217;ll need to do it in the KeyDown or KeyUp event, not the KeyPress event.  As the documentation (here and here) points out, KeyPress deals mostly with character keys, and non-character keys won&#8217;t raise it.
]]></description>
			<content:encoded><![CDATA[<p>A small but important thing &#8211; if you want to capture pressing the DELETE button in a WinForms project, you&#8217;ll need to do it in the KeyDown or KeyUp event, not the KeyPress event.  As the documentation (<a title="Control.KeyPressEvent" href="http://msdn.microsoft.com/en-us/library/system.windows.forms.control.keypress.aspx" target="_blank">here</a> and <a title="KeyPress Event (Office 12)" href="http://msdn.microsoft.com/en-us/library/ee414757(office.12).aspx" target="_blank">here</a>) points out, KeyPress deals mostly with character keys, and non-character keys won&#8217;t raise it.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.techknowsolve.com/blog/?feed=rss2&amp;p=63</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Remove items from Visual Studio Recent Projects list</title>
		<link>http://www.techknowsolve.com/blog/?p=59</link>
		<comments>http://www.techknowsolve.com/blog/?p=59#comments</comments>
		<pubDate>Wed, 19 May 2010 17:05:27 +0000</pubDate>
		<dc:creator>MaryD</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[VB.NET]]></category>

		<guid isPermaLink="false">http://www.techknowsolve.com/blog/?p=59</guid>
		<description><![CDATA[Here are a couple handy links describing how to remove items from the Recent Projects list on the Visual Studio start page.  Basically, in versions prior to VS2010, it&#8217;s a registry hack (I&#8217;ve read that VS2010 provides a way to do this within the IDE, but I haven&#8217;t played with 2010 yet so I can&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p>Here are a couple handy links describing how to remove items from the Recent Projects list on the Visual Studio start page.  Basically, in versions prior to VS2010, it&#8217;s a registry hack (I&#8217;ve read that VS2010 provides a way to do this within the IDE, but I haven&#8217;t played with 2010 yet so I can&#8217;t attest to that myself).</p>
<p><a href="http://aspnetcoe.wordpress.com/2007/02/06/how-to-remove-recent-projects-from-visual-studio-start-page/" target="_blank">http://aspnetcoe.wordpress.com/2007/02/06/how-to-remove-recent-projects-from-visual-studio-start-page/</a></p>
<p><a href="http://mvantzet.wordpress.com/2009/09/15/remove-recent-projects-from-visual-studio-2008/" target="_blank">http://mvantzet.wordpress.com/2009/09/15/remove-recent-projects-from-visual-studio-2008/</a></p>
<p>When I removed some items from my version of VS 2008, I found that I also needed to rename the remaining registry keys so that there were no gaps in the order (ie, File1, File2, etc with no gaps)</p>
]]></content:encoded>
			<wfw:commentRss>http://www.techknowsolve.com/blog/?feed=rss2&amp;p=59</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Working with winmm.dll to play audio files in .NET</title>
		<link>http://www.techknowsolve.com/blog/?p=55</link>
		<comments>http://www.techknowsolve.com/blog/?p=55#comments</comments>
		<pubDate>Fri, 30 Apr 2010 00:38:24 +0000</pubDate>
		<dc:creator>MaryD</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[VB.NET]]></category>

		<guid isPermaLink="false">http://www.techknowsolve.com/blog/?p=55</guid>
		<description><![CDATA[I&#8217;m working on a little utility application that will transfer audio files from a recorder to a computer drive.  Part of the functionality is to display the audio files, and let users listen to a little snippet of the audio file if they so desire.  A quick google search led me to this page containing [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m working on a little utility application that will transfer audio files from a recorder to a computer drive.  Part of the functionality is to display the audio files, and let users listen to a little snippet of the audio file if they so desire.  A quick google search led me to <a href="http://www.vbforfree.com/?p=219" target="_blank">this page </a>containing a good description of the process, with example code.  Using the examples, I came up with the utility class shown below.  And here&#8217;s how I&#8217;d use the class in a button event handler:</p>
<p>Private Sub LinkLabel1_LinkClicked(ByVal sender As System.Object, ByVal e As System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles LinkLabel1.LinkClicked<br />
    Using player As New PlayAudioFile(&#8220;C:\Misc\WS400001.WMA&#8221;)<br />
         player.PlaySnippet(5)<br />
    End Using<br />
End Sub</p>
<p>Public Class PlayAudioFile<br />
    Implements IDisposable</p>
<p>    &#8216;Private data member &#8211; file path<br />
    Private fileToPlay As String</p>
<p>    &#8216;Private function to send commands to the Windows OS MultiMedia API<br />
    Private Declare Function mciSendString Lib &#8220;winmm.dll&#8221; Alias &#8220;mciSendStringA&#8221; _<br />
    (ByVal lpstrCommand As String, ByVal lpstrReturnString As String, _<br />
    ByVal uReturnLength As Integer, ByVal hwndCallback As Integer) As Integer</p>
<p>    &#8216;Private wrapper method for API function<br />
    Private Sub SendCommand(ByVal command As String)<br />
        mciSendString(String.Format(&#8220;{0} {1}&#8221;, command, fileToPlay), Nothing, 0, 0)<br />
    End Sub</p>
<p>    &#8221;&#8217; &lt;summary&gt;<br />
    &#8221;&#8217; Class Constructor &#8211; accepts an audio file (must be MP3, WAV or WMA file)<br />
    &#8221;&#8217; &lt;/summary&gt;<br />
    &#8221;&#8217; &lt;param name=&#8221;soundFile&#8221;&gt;Full path of audio file to be played&lt;/param&gt;<br />
    Public Sub New(ByVal soundFile As String)<br />
        Dim ext As String = IO.Path.GetExtension(soundFile)<br />
        Select Case ext.ToLower<br />
            Case &#8220;.mp3&#8243;, &#8220;.wav&#8221;, &#8220;.wma&#8221;<br />
                fileToPlay = Chr(34) + soundFile + Chr(34)<br />
            Case Else<br />
                Throw New ArgumentException(&#8220;File must be an .MP3, .wav or .WMA file&#8221;)<br />
        End Select<br />
    End Sub</p>
<p>    &#8221;&#8217; &lt;summary&gt;<br />
    &#8221;&#8217; Play audio file<br />
    &#8221;&#8217; &lt;/summary&gt;<br />
    Public Sub Play()<br />
        Me.SendCommand(&#8220;open&#8221;)<br />
        Me.SendCommand(&#8220;play&#8221;)<br />
    End Sub</p>
<p>    &#8221;&#8217; &lt;summary&gt;<br />
    &#8221;&#8217; Stop audio file playback<br />
    &#8221;&#8217; &lt;/summary&gt;<br />
    Public Sub StopPlay()<br />
        Me.SendCommand(&#8220;stop&#8221;)<br />
    End Sub</p>
<p>    &#8221;&#8217; &lt;summary&gt;<br />
    &#8221;&#8217; Pause audio file playback<br />
    &#8221;&#8217; &lt;/summary&gt;<br />
    Public Sub PausePlay()<br />
        Me.SendCommand(&#8220;pause&#8221;)<br />
    End Sub</p>
<p>    &#8221;&#8217; &lt;summary&gt;<br />
    &#8221;&#8217; Resume playback of paused audio file<br />
    &#8221;&#8217; &lt;/summary&gt;<br />
    Public Sub ResumePlay()<br />
        Me.SendCommand(&#8220;resume&#8221;)<br />
    End Sub</p>
<p>    &#8221;&#8217; &lt;summary&gt;<br />
    &#8221;&#8217; Close audio file<br />
    &#8221;&#8217; &lt;/summary&gt;<br />
    Public Sub CloseFile()<br />
        Me.SendCommand(&#8220;close&#8221;)<br />
    End Sub</p>
<p>    &#8221;&#8217; &lt;summary&gt;<br />
    &#8221;&#8217; Play the first part of the sound file (default 15 seconds)<br />
    &#8221;&#8217; &lt;/summary&gt;<br />
    Public Sub PlaySnippet()<br />
        PlaySnippet(15)<br />
    End Sub</p>
<p>    &#8221;&#8217; &lt;summary&gt;<br />
    &#8221;&#8217; Play the first part of the sound file<br />
    &#8221;&#8217; &lt;/summary&gt;<br />
    &#8221;&#8217; &lt;param name=&#8221;snippetLength&#8221;&gt;Length of snippet (in seconds)&lt;/param&gt;<br />
    Public Sub PlaySnippet(ByVal snippetLength As Integer)<br />
        Me.Play()<br />
        System.Threading.Thread.Sleep(snippetLength * 1000)<br />
        Me.StopPlay()<br />
    End Sub</p>
<p>#Region &#8221; IDisposable Support &#8221;</p>
<p>    Private disposedValue As Boolean = False        &#8216; To detect redundant calls</p>
<p>    &#8216; IDisposable<br />
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)<br />
        If Not Me.disposedValue Then<br />
            If disposing Then<br />
                &#8216; TODO: free unmanaged resources when explicitly called<br />
                Me.CloseFile()<br />
            End If</p>
<p>            &#8216; TODO: free shared unmanaged resources<br />
            Me.CloseFile()<br />
        End If<br />
        Me.disposedValue = True<br />
    End Sub</p>
<p>    &#8216; This code added by Visual Basic to correctly implement the disposable pattern.<br />
    Public Sub Dispose() Implements IDisposable.Dispose<br />
        &#8216; Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.<br />
        Dispose(True)<br />
        GC.SuppressFinalize(Me)<br />
    End Sub<br />
#End Region</p>
<p>End Class</p>
<p>There should probably be more error handling in the class (for example, to make sure that the file is opened before calling ResumePlay, that sort of thing), but I thought this was a good start.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.techknowsolve.com/blog/?feed=rss2&amp;p=55</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DataGridViewComboBox Column Properties</title>
		<link>http://www.techknowsolve.com/blog/?p=45</link>
		<comments>http://www.techknowsolve.com/blog/?p=45#comments</comments>
		<pubDate>Mon, 26 Apr 2010 22:34:06 +0000</pubDate>
		<dc:creator>Lis</dc:creator>
				<category><![CDATA[All]]></category>
		<category><![CDATA[VB.NET]]></category>

		<guid isPermaLink="false">http://www.techknowsolve.com/blog/?p=45</guid>
		<description><![CDATA[I am copying this verbatim from a post I found by Kevin Spencer which is the clearest explanation I have seen of the main properties of a DataGridViewComboBox.  It&#8217;s here for my reference.  Yay if it helps you too!
The DataGridView itself has a DataSource property that determines what columns are in it. The [...]]]></description>
			<content:encoded><![CDATA[<p>I am copying this verbatim from a post I found by Kevin Spencer which is the clearest explanation I have seen of the main properties of a DataGridViewComboBox.  It&#8217;s here for my reference.  Yay if it helps you too!</p>
<p>The DataGridView itself has a DataSource property that determines what columns are in it. The DataGridViewComboBox column also has a DataSource property, but that isn&#8217;t the same as the DataSource of the DataGridView. It is the DataSource that is used to populate the ComboBox in each cell. The DataMember and ValueMember properties are the column names of the columns in the ComboBox&#8217;s DataSource that define what is displayed in the ComboBox, and the underlying value for that item. It is the DataPropertyName property of the DataGridViewComboBoxColumn that determines the column name in the DataGridView&#8217;s DataSource that the ataGridViewComboBoxColumn is associated with. The ValueMember determines the value that will be set for that column in the DataGridView&#8217;s DataSource.</p>
<p>Here&#8217;s the original <a href="http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework/topic43757.aspx" target="_blank"> link</a>.  Thanks, Kevin Spencer.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.techknowsolve.com/blog/?feed=rss2&amp;p=45</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>System.Data.OleDb.OleDbException: Unspecified error</title>
		<link>http://www.techknowsolve.com/blog/?p=16</link>
		<comments>http://www.techknowsolve.com/blog/?p=16#comments</comments>
		<pubDate>Wed, 17 Mar 2010 22:13:31 +0000</pubDate>
		<dc:creator>MaryD</dc:creator>
				<category><![CDATA[ASP.NET]]></category>
		<category><![CDATA[All]]></category>

		<guid isPermaLink="false">http://techknowsolve.com/blog/?p=16</guid>
		<description><![CDATA[I ran across this error in an ASP.NET project that was using ADO.NET to access the data in a .csv file (more info here). After much gnashing of teeth, I finally ran across this blog post, that explained the problem and provided a link to this MSDN article.
Basically, you need to make sure that the [...]]]></description>
			<content:encoded><![CDATA[<p>I ran across this error in an ASP.NET project that was using ADO.NET to access the data in a .csv file (more info <a href="http://weblogs.asp.net/fmarguerie/archive/2003/10/01/29964.aspx" target="_blank">here</a>). After much gnashing of teeth, I finally ran across this <a href="http://msmvps.com/blogs/rakeshrajan/archive/2005/07/04/56461.aspx" target="_blank">blog post</a>, that explained the problem and provided a link to this <a href="http://support.microsoft.com/default.aspx?scid=kb;EN-US;825738" target="_blank">MSDN article</a>.</p>
<p>Basically, you need to make sure that the user has permissions on both the file in which the .csv file resides, and also the file in which the <a href="http://en.wikipedia.org/wiki/Microsoft_Jet_Database_Engine" target="_blank">Jet Engine</a> will create temporary files. It is this last piece that I didn&#8217;t know, and lead to days of heartache.</p>
<p>So I thought I&#8217;d post, in the hopes of minimizing the heartache for others&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.techknowsolve.com/blog/?feed=rss2&amp;p=16</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

