Account: (login)

More Channels


Are you the publisher? Claim this channel

Search in 110,534,763 RSS articles:

Channel Description:

The .NET Developer Community

Latest Articles in this Channel:

  • 09/15/11--08:08: Toggle Between Widows 8 Metro Interface and Windows 8 Starndard Interface (chan 2127976)
  • Use the Windows key.

    If you are in Metro press it to switch to the Windows 7 interface.

    If you are in the Windows 7 interface press it to switch to the Metro interface.


  • 09/19/11--05:28: How To Print the Content of a Windows Forms ListView (chan 2127976)
  • Introduction
    I tweaked this code a while back when I just wanted to take a screenshot of the contents of a ListView.  Essentially, it just uses BitBlt to grab all the required content, stores it as a temporary image, and then uses the standard PrintPage method to print it out.

    The ListView
    Here’s a screenshot of the list view I’ve used:

    ListViewToPrint1

     

    While I was experimenting with the printing, I found that I got a better printed result if I increased the font size on the list view.

    ListViewToPrint2

    The Code
    Here’s the code for the Windows Form:

        1 Public Class Form1

        2   Friend WithEvents prntDoc As New System.Drawing.Printing.PrintDocument

        3   Friend Print_Image As Image

        4   Declare Auto Function BitBlt Lib "GDI32.DLL" (

        5   ByVal hdcDest As IntPtr,

        6   ByVal nXDest As Integer,

        7   ByVal nYDest As Integer,

        8   ByVal nWidth As Integer,

        9   ByVal nHeight As Integer,

       10   ByVal hdcSrc As IntPtr,

       11   ByVal nXSrc As Integer,

       12   ByVal nYSrc As Integer,

       13   ByVal dwRop As Int32) As Boolean

       14 

       15   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

       16     MakeImage()

       17   End Sub

       18 

       19   Private Sub MakeImage()

       20     Dim prnDialog As New PrintDialog

       21     Application.DoEvents()

       22     Me.Refresh()

       23     Application.DoEvents()

       24     'Get a Graphics Object from the form

       25     Dim FormG As Graphics = ListView1.CreateGraphics

       26     'Create a bitmap from that graphics

       27     Dim i As New Bitmap(ListView1.Width, ListView1.Height, FormG)

       28     'Create a Graphics object in memory from that bitmap

       29     Dim memG As Graphics = Graphics.FromImage(i)

       30     'get the IntPtr's of the graphics

       31     Dim HDC1 As IntPtr = FormG.GetHdc

       32     Dim HDC2 As IntPtr = memG.GetHdc

       33     'get the picture

       34     BitBlt(HDC2, 0, 0, ListView1.ClientRectangle.Width, ListView1.ClientRectangle.Height, HDC1, 0, 0, 13369376)

       35     'Clone the bitmap so we can dispose this one

       36     Me.Print_Image = CType(i.Clone(), Image)

       37     'Clean Up

       38     FormG.ReleaseHdc(HDC1)

       39     memG.ReleaseHdc(HDC2)

       40     FormG.Dispose()

       41     memG.Dispose()

       42     i.Dispose()

       43     prnDialog.Document = prntDoc

       44     Dim r As DialogResult = prnDialog.ShowDialog

       45     If r = DialogResult.OK Then

       46       prntDoc.Print()

       47     End If

       48   End Sub

       49 

       50   Private Sub prntDoc_PrintPage(ByVal sender As Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles prntDoc.PrintPage

       51     e.Graphics.DrawImage(Print_Image, 20, 90)

       52   End Sub

       53 End Class

       54 

     

    Firstly, it creates a couple of variables, one for the PrintDocument that’s going to be created, and one for the image that will be built using BitBlt. 

    As you can see, BitBlt is at the heart of this task, and the next block of code comprises the BitBlt API .  Jumping to the core method in line 19 that creates the image for printing, you’ll see how BitBlt is used to make a copy of the area of the Windows Form that’s occupied by the list view.

    Once a copy of the list view has been taken and assigned to the Image named Print_Image, the user is shown a standard print dialog.  Once they hit the OK button in that dialog, the PrintPage method of the print document is called and this uses the standard DrawImage method to print the image to the printer page.    You can change the values for the left and top points (currently 20 and 90) if you want to reposition the printed list view on the printer page.

    Summary
    You’ll probably realise that although I’m capturing a list view here, this same procedure can be used for any area of the form, or any individual control, that you want to print out.


  • 09/25/11--12:43: SharePoint 2010 Picture Library Slideshow Web Part Image Size (chan 2127976)
  • Well although the Picture Library Slideshow Web Part is a great OOTB feature, one thing that bugged me when I first started playing with it was the fact that it shrinks the size of the pictures that it displays with no means of overriding the size it decides to make them.

    But with some simple jQuery in a Content Editor WebPart we can easily overcome this.

    <script> 
    $(document).ready(function() { 
    var divList = $("div[id^='MSOPictureLibrarySlideshowWebPart']"); 
    var currImage= $("img[id$='curr']"); 
    divList.height('100%'); 
    divList.width('100%'); 
    currImage.height('125%'); 
    currImage.width('125%'); 
    });</script>
    


  • 09/26/11--03:01: How to populate a ListView from a text file (chan 2127976)
  • Introduction
    The source of your data for a ListView can come from various sources and, if your requirements, a text file can sometimes be all you need.  Because of the way the ListView is structured, there are a couple of things you need to look out for.

    The ListView
    Here’s a screenshot of the ListView I’m using as the example:

    ListViewfromFile2

    The text file
    The only reason for showing you the text file is to point out that it uses the “-“ symbol to break up the data into the required columns:

    Brian Bilbro - ( bbilbro@hotmail.com )- Module Communicator code and architecture
    Fredi Gertsch- ( fredi@gerts.ch ) - Tab Administrator
    John Dyer -  (http://www.revjon.com) - Revjon Studios
    Robin Lilly, Vanessa Monzon - N/A
    Tom Trefz & Scott Willhite -NK - PopupCalendar.js (original by Tom, localization & Netscape by Scott)
    Richard Cox - ( http://www.bydesignwebsights.com )- Search engine optimization at the Tab level ( Description, KeyWords, Title )
    Dino Esposito - ( http://weblogs.asp.net/despos )- Personalization architecture from MSDN magazine ( Cutting Edge - March 2004 )
    Jeff Martin- ( http://www.jeffmartin.com )- move ViewState to bottom of page for better search engine spidering
    Jonathan de Halleux - ( http://www.dotnetwiki.org )- PA Installer
    David Haggard -( http://www.newcovenant.com )- function to obfuscate sensitive data to prevent collection by robots and spiders and crawlers
    Vicenc Masanas - ( http://lacolla.europe.webmatrixhosting.net ) - SMTP authentication
    Joe Brinkman - ( http://www.tag-software.net )- Module Action Menu concept
    Patrick Santry - ( http://www.wwwcoder.com ) - PayPal price checking and account checking
    M. Murali Dharan - ( http://www.phpbuilder.com/columns/dhar20040217.php3 )- Search Engine Concepts
    Craig Dunn - ( http://users.bigpond.com/conceptdevelopment/ ) - Search Engine Concepts ( Searcharoo )
    Stan Schultes - ( http://www.vbnetexpert.com ) -  RSS Generator ( Visual Studio Magazine - April 2004 )
    James Clarkson  - ( http://www.blogolith.com ) - Favicon per portal
    Scott Mitchell - ( http://4guysfromrolla.com ) - URL Rewriting
    Scott Stokes- ( http://www.adverageous.com )- File Manager UI ( based on DNNExplorer )
    Michael Beller - ( http://www.lightshippartners.com ) - Database model for abstraction and refactoring of the core database
    Sebastian Leupold - ( http://www.gamma-concept.de ) - German resource files

    Using that symbol was my choice, and I could have opted for another character, symbol, or even a combination such as “-//-“ .

    The code that populates the ListView
    Here’s the code that will read the file and allocate the sections of text to the columns of the ListView:

        1 Imports System.IO

        2 

        3 Public Class Form2

        4 

        5   Private Sub Form2_Load(sender As Object, e As System.EventArgs) Handles Me.Load

        6     ListView1.View = View.Details

        7     ListView1.Columns.Add("Name", 176)

        8     ListView1.Columns.Add("Contact Information", 266)

        9     ListView1.Columns.Add("Expertise", 276)

       10 

       11     Try

       12       ' Declare StreamReader and pass the Path of the ini file to be read as a Parameter

       13       Dim MyStream As New StreamReader("C:\Temp\Contributors.txt")

       14       ' A string array to hold each line as it is read

       15       Dim strTemp() As String

       16       '  Code that reads the file line by line

       17       Do While MyStream.Peek <> -1 ' Use Peek to read the file until there are no more lines

       18         Dim LVItem As New ListViewItem

       19         ' Split the line using the -  delimiter

       20         strTemp = MyStream.ReadLine.Split("-"c)

       21         ' Assign the content of the first element of the array to the first column

       22         LVItem.Text = strTemp(0).ToString

       23         ' Then add the item to the ListView

       24         ListView1.Items.Add(LVItem)

       25         ' Assign the content of the second element to the next column

       26         LVItem.SubItems.Add(strTemp(1).ToString)

       27         '  Check if there is a third section.  If so, assign it to the next column

       28         If strTemp.Length > 2 Then LVItem.SubItems.Add(strTemp(2).ToString)

       29       Loop

       30 

       31       MyStream.Close() ' Close the StreamReader

       32     Catch ex As Exception

       33       MessageBox.Show("Error reading file." & ex.Message)

       34     End Try

       35   End Sub

       36 End Class

     

    I think that the commenting fairly well explains exactly how it works.

    I chose to set the properties in lines 6 to 9 here in the code.  I could of course have set them using the properties window instead.

    The test in line 28 is important, because if strTemp(2) is empty then you’ll get an error at runtime that will cause the display to stop rendering fully.

    The only other point I wanted to make is that, if you look at the Dino Esposito entry, you’ll see that not all the information is shown.  That’s because there is an additional “-“ in that piece of text, and as a result the words “March 2004” at the end of his entry are not shown in the ListView.  In fact, they have been saved, but they will be in element (3) of strTemp and the code doesn’t do anything with that element.  To avoid this kind of problem, it’s usually better to use a delimiter that won’t occur naturally, such as the “-//-“ example I gave earlier.

    Summary
    Populating a ListView from a text file is relatively easy, as long as you ensure that the delimiter will work properly and that you’ve accounted for all elements of the string array you use with the Split function.


  • 09/29/11--01:33: How to copy and paste a section of a PictureBox image (chan 2127976)
  • Introduction
    This is just a quick and dirty way to copy a section of image from one picture box and paste the selected area into a second picture box.

    Here’s the basic Windows Form with two PictureBox controls at design time:

    CopyPartImage1

    The code

     Private Sub btnCopyPart_Click(sender As System.Object, e As System.EventArgs) Handles btnCopyPart.Click

     

        'Grab the content of the first PictureBox and save it as a bitmap

        Dim sourcebmp As New Bitmap(picImage.Image)

        '  Create an empty bitmap the size of the second PictureBox

        Dim destinationbmp As New Bitmap(picDestination.Width, picDestination.Height)

        ' Create a Graphics object for the destination

        Dim gr As Graphics = Graphics.FromImage(destinationbmp)

     

        ' Set the size of the area you want to copy

        Dim selectionrectangle As New Rectangle(140, 20, 270, 400)

        ' Set the size of the destination rectangle to match the size of the second PictureBox

        Dim destinationrectangle As New Rectangle(0, 0, picDestination.Width, picDestination.Height)

     

        ' Draw selected area on to the destination bitmap.

        gr.DrawImage(sourcebmp, destinationrectangle, selectionrectangle, GraphicsUnit.Pixel)

     

        ' Set the drawn destination bitmap as the image of the second PictureBox

        picDestination.Image = destinationbmp

     

      End Sub

     

     

    I hope that the detailed commenting makes it clear how this works. You can change the start points  and the size of the selection rectangle to grab the required area. Of course, you may want to expand this to let the user select an area and I plan to cover that in a later blog.

     

    The result of the above will be:

    copyPartImage2


  • 10/02/11--23:30: How to search for an item in a ListView (chan 2127976)
  • Introduction
    Sometimes the list of entries in a ListView is so large that you need to give the user the means of finding a particular item.  Here’s one way of doing that.

    The user interface
    Here’s the Windows Form I’m using for the demonstration:

    ListViewSearch1

     

    The user enters the search term, hits the Find button and if a match is found that row will be selected.  If no match is found, then a message will appear in the label (that currently just has a dash as its content).

    The Code for the Search 
    Starting with the function that carries out the search:

       53   Private Function FindItem(ByVal LV As ListView, ByVal TextToFind As String) As Integer

       54   

       55     ' Loop through LV’s ListViewItems.

       56     For i As Integer = 0 To LV.Items.Count - 1

       57       If Trim(LV.Items(i).Text) = Trim(TextToFind) Then

       58         ' If found, return the row number

       59         Return (i)

       60       End If

       61       For subitem As Integer = 0 To LV.Items(i).SubItems.Count - 1

       62         If Trim(LV.Items(i).SubItems(subitem).Text) = Trim(TextToFind) Then

       63           ' If found, return the row number

       64           Return (i)

       65         End If

       66       Next

       67     Next

       68     ' If not found, then return -1.

       69     Return -1

       70   End Function

    you can see that the name of the list view and the search term are passed in as parameters. The first part of the For-Next loop checks if the search term exists in the first column of the list view.  If it does, then the index number of that row is returned.

    If it’s not found in the first column, then the remaining columns of that row are checked.  Again, if a match is found, the index number of the row is returned.

    The loop continues until either a match is found or the end of the list view is reached.  If the end is reached, then a value of –1 is returned.

    The Calling Code
    Here’s the code in the click event of the Find button:

       37   Private Sub btnFind_Click(sender As System.Object, e As System.EventArgs) Handles btnFind.Click

       38     ListView1.MultiSelect = False

       39     ListView1.FullRowSelect = True

       40   

       41 

       42     Dim checkInt As Integer = FindItem(ListView1, TextBox1.Text)

       43     If checkInt <> -1 Then

       44       ListView1.Items(checkInt).Selected = True

       45       ListView1.Focus()

       46      

       47     Else

       48       Label1.Text = "Search string not found"

       49     End If

       50 

       51   End Sub

    I’ve set MultiSelect to False so that only the first occurrence is returned.  The setting of FullRowSelect in line 39 is optional, but I prefer to use it.

    The FindItem function is called and then the If-Then-Else block deals with the returned result.  If the result isn’t –1 then a match has been found.  That row number is then selected. 

    Because the last user action was the clicking of the button, the button will still have focus, so the selection in the list view won’t be highlighted (and you’d be tempted to think that the function had failed).  Setting the Focus on to the list view solves this issue.

    If the returned value is –1, then a message is shown in the label to let the user know.

    How to deal with hidden rows
    In most cases, the row being searched for won’t be one of the rows that is currently visible.  So, if a match is found and that row is selected, once again the user probably won’t be aware of the successful match.  The easiest way to deal with this is to add:

    ListView1.SelectedItems(0).EnsureVisible()

    to the code immediately after the ListView1.Focus() statement.  If the SelectedItems(0) has you confused, the way it works is that SelectedItems is a collection of rows that are currently selected.  Because in this example we’re just looking for the first occurrence, we know that it will be element 0 of that collection.  (I plan to deal with multiple results in a follow-up blog).  So the relevant lines of code will now be:

       43 If checkInt <> -1 Then

       44       ListView1.Items(checkInt).Selected = True

       45       ListView1.Focus()

       46       ListView1.SelectedItems(0).EnsureVisible()

       47     Else

       48       Label1.Text = "Search string not found"

       49     End If

    This will cause the list view to scroll to the selected and highlighted row.


  • 10/06/11--04:39: How to display a countdown timer (chan 2127976)
  • Introduction
    Going through some of my old posts this morning, I saw that this question seems to have been asked a lot.  So I thought it was worth posting up an easy way of doing it.

    Here’s the form at design time:

    Countdown1

    The label with the text of “Countdown finished” has its Visibility property set to False.  So when the application first runs, the user sees:

     

    Countdown 2

    The controls
    Here’s a quick rundown of the controls used in this example:

    Control Type Name Purpose Notes
    Label lblElapsed Displays the countdown in minutes and seconds Font set to Bold and Font Size 18
    Label Label1 Displays the instructions to the user  
    Label lblFinished Displays a message when the countdown in complete Visible property set to False. Foreground Red.
    FontSize = 22
    TextBox txtMinutes Allows the user to set the countdown time  
    Button btnStart Start the countdown  
    Timer Timer1 Counts down the elapsed time  

    The code

    Here’s how it works:

        4  Dim tspn As New TimeSpan()

        5 

        6   Private Sub btnStart_Click(sender As System.Object, e As System.EventArgs) Handles btnStart.Click

        7 

        8     If IsNumeric(txtMinutes.Text) AndAlso CInt(txtMinutes.Text) > 0 Then

        9       tspn = New TimeSpan(0, CInt(txtMinutes.Text), 0)

       10       Timer1.Enabled = True

       11     Else

       12       MessageBox.Show("Please enter a numeric value in the text box", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)

       13     End If

       14 

       15   End Sub

       16 

       17   Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick

       18     tspn = tspn.Subtract(New TimeSpan(0, 0, 1))

       19 

       20     lblElapsed.Text = String.Format(" {0} Mins : {1} Secs", tspn.Minutes, tspn.Seconds)

       21     If tspn.Minutes = 0 AndAlso tspn.Seconds = 0 Then

       22       Timer1.Stop()

       23       lblFinished.Visible = True

       24     End If

       25 

       26   End Sub

    Line 4 creates a new TimeSpan object. As it’s name suggests, this object represents a given period of time.

    When the user clicks the button, Line 8 checks that a valid number has been entered.  If it has, then the TimeSpan object is given the number of minutes the user entered. Note that the TimeSpan takes three values there – they represent, hour, minute and second values.  Hour and second have been set to zero for this example, but you can change the code if you need to.

    Line 10 then kickstarts the timer.

    If the user had failed to enter a valid number in the text box, then Line 12, points out their error and the timer isn’t started.

    The Timer Tick event occurs every second, so Line 18 ensures that as each second passes, one second is subtracted from the initial valur of the TimeSpan.

    Then, the display is updated to show how many minutes and seconds still remain in the TimeSpan.

    Next, in Line 21 a check is made to see if there is zero time left in the TimeSpan.  If so, the timer is stopped.  (If you didn’t do this,the timer would continue deducting seconds and the display would show negative times).  As the countdown is complete, as an optional extra, the user is shown a message. This is done simply by making the previously hidden lblFinished label visible.

    Summary
    And that’s all there is to it.  TimeSpans do seem to cause a lot of confusion, so if you’ve found yourself stuck on what seems like a fairly trivial task, it’ll probably be because you didn’t get the TimeSpan syntax right.


  • 10/09/11--22:26: How to save ListView content to a text file (chan 2127976)
  • Introduction
    Sometimes you might need to take a copy of what’s displayed in a ListView and save it.  There are several options and one of these is simply to save it to a plain text file.

    Saving to a known file name
    If you know the file name, then you can use the following code:

      Private Sub SaveToKnownFile(LV As ListView, FilePathAndName As String)

     

        Dim sw As New StreamWriter(FilePathAndName)

     

        For i As Integer = 0 To LV.Items.Count - 1

          sw.Write(LV.Items(i).Text)

          For subItemIndex As Integer = 1 To LV.Items(i).SubItems.Count - 1

            sw.Write(":::" & LV.Items(i).SubItems(subItemIndex).Text)

          Next

          sw.Write(Environment.NewLine)

     

        Next

          sw.Close()

     

      End Sub

    You’ll see that I’ve hard-coded the separator characters as “:::”.  These are the characters that any code that wants to read the data back from the file will need to use in order to split the lines back into the separate entries for the columns in the list view. I’ve found that it’s usually better to use some combination of characters that won’t come up in standard text writing.  For instance, if you just used a comma as the delimiter then you’ll probably find that your data won’t be split correctly when you read it back, because commas are so common in everyday text.

    So, you might want to expand the method to allow for a delimiter to be included as a parameter:

      Private Sub SaveToKnownFileWithDelimiter(LV As ListView, FilePathAndName As String, Delimiter As String)

     

        Dim sw As New StreamWriter(FilePathAndName)

     

        For i As Integer = 0 To LV.Items.Count - 1

          sw.Write(LV.Items(i).Text)

          For subItemIndex As Integer = 1 To LV.Items(i).SubItems.Count - 1

            sw.Write(Delimiter & LV.Items(i).SubItems(subItemIndex).Text)

          Next

          sw.Write(Environment.NewLine)

     

        Next

        sw.Close()

     

      End Sub

    And you could call it with something like this:

      

      Private Sub btnSave_Click(sender As System.Object, e As System.EventArgs) Handles btnSave.Click

        SaveToKnownFileWithDelimiter(ListView1, "C:\Temp\Contributors3.txt", "@@--@@")

      End Sub

    Letting the user select a file
    You won’t always want to hard code the file path and name, so you can build in a save dialog and take out FilePathAndName :

      Private Sub UseSaveFileDialogToSave(LV As ListView, Delimiter As String)

        Dim sw As StreamWriter

       Dim sfDialog As New SaveFileDialog

     

        sfDialog.Filter = "Text Files (*.txt)|*.txt"

       

        If sfDialog.ShowDialog = DialogResult.OK And sfDialog.FileName <> "" Then

          If File.Exists(sfDialog.FileName) Then

            sw = New StreamWriter(sfDialog.FileName)

          Else

            MessageBox.Show("Error with file selection")

          End If

     

          For i As Integer = 0 To LV.Items.Count - 1

            sw.Write(LV.Items(i).Text)

            For subItemIndex As Integer = 1 To LV.Items(i).SubItems.Count - 1

              sw.Write(Delimiter & LV.Items(i).SubItems(subItemIndex).Text)

            Next

            sw.Write(Environment.NewLine)

          Next

          sw.Close()

        End If

      End Sub

     

    Summary
    You can use these simple methods to save ListView data to a text file. You can see how to write the data back from the text file to the ListView in this earlier blog item.


  • 10/13/11--13:57: How To Print a Windows Forms ListBox to a selected printer (chan 2127976)
  • Introduction
    Here’s an easy way you If you have a list of items in a list box and print them out to a printer.  This version lets the user choose a printer from the PrintDialog first.

    The Windows Form
    It’s a very simple form – just a list box and a button:

    PrintListBox

     

    The code that does the printing
    You start by adding an Imports statement for the System.Drawing.Printing class.

    Imports System.Drawing.Printing

    Next, you create a PrintDocument.  Essentially this object will hold whatever it is we decide we want to print.  In this case, we know it will be the contents of the list box. Note that it’s declared WithEvents.

     Private WithEvents docToPrint As New PrintDocument

    And the reason it’s declared with events is because next we’re going to create the PrintPage event:

     Private Sub document_PrintPage(ByVal sender As Object,

         ByVal e As System.Drawing.Printing.PrintPageEventArgs) _

             Handles docToPrint.PrintPage

    This event handler really does all the important work.  First, it creates a Font object that describes which font to use, what font size it will be, and whether any font attributes will be set, such as bold or italic. or this example, I’m staying with fairly plain text, but you can change these settings to whatever you want.

     Dim printFont As New Font("Arial", 15, System.Drawing.FontStyle.Regular)

     

    The next line creates an integer that will be used to move the print head down the printed page. You’ll see how this works in a moment.

    Dim YPosition As Integer = 40

    I picked the value of 40 to create the amount of space between the lines that looked right to me.  You can of course change this – and you would need to if, for instance, you used a larger font.

    The final four lines of the PrintPage event print the content.

        For Each hotel As String In lstHotels.Items

          e.Graphics.DrawString(hotel, printFont, System.Drawing.Brushes.Black, 25, YPosition)

          YPosition += 40

        Next

    As you can see, each item in the list box is dealt with separately. The DrawString method is passed the following parameters:

    • the next string in the list box,
    • the font that we created earlier
    • A Brush that determines the color of the text, and
    • the distance down the printer page to start printing this item.

    Then, to set the print head up for the next line, the YPosition value is increased, and this moves the start position down the page.

    The calling code
    If you want to give the user the opportunity to select a printer, you can create and display a PrintDialog. Actually, the PrintDialog has a whole bunch of properties that you can configure, if you want to give the user even more options. But for this example, I’m just going to keep those choices to the minimum.

      Private Sub Button1_Click(ByVal sender As System.Object,

          ByVal e As System.EventArgs) Handles Button1.Click

     

        Dim PrintDialog1 As New PrintDialog

        Dim result As DialogResult = PrintDialog1.ShowDialog()

       If result = DialogResult.OK Then docToPrint.Print()

     

     End Sub

    Essentially, what happens here is that when the user clicks the OK button of the dialog, the PrintDocument’s Print method is called. The page will then be printed, with each item of the list box in turn on a new line.

    Summary
    So, there it is – an easy way to print out the items in a list box to the printer.


  • 10/16/11--22:26: How to Serialize and Deserialize ListView data (chan 2127976)
  • Introduction
    Although you’ll most often use serialization to store objects in a file, you can use it to store the data from a ListView.  Here’s how.

    Serialize the data
    The following code serializes a ListView’s data to a file:

      Private Sub SerializeListViewData(LV As ListView, ByVal filename As String)

        '  Create a FileStream and get the file to write to.

        Dim FS As FileStream = File.Create(filename)

        '  Create a Binary Formatter for Serialization process

        Dim BinFmtr As New BinaryFormatter

        '  Create an arraylist as temp storage for listview items data

        Dim alSavedLV As New ArrayList

     

        '  Iterate through the ListView's listitem collection and add

        '  each to the temporary ArrayList

        For item As Integer = 0 To lv.Items.Count - 1

          '  Add next item/subitem to the arraylist

          alSavedLV.Add(LV.Items(item))

        Next

     

        '  Serialize the complete arraylist to the file

        '  The arraylist contains all the listview data

        BinFmtr.Serialize(FS, alSavedLV)

     

        '  Close the FileStream

        FS.Close()

     

      End Sub

    The first step is to create a FileStream that will create the pipeline from the data to the file it’s going to be stored in. This FileStream will be passed the path and name of the target file

    Next, you create a BinaryFormatter object that will do the serialization for you. Note that you need to have an Imports statement pointing to  System.Runtime.Serialization.Formatters.Binary to access this.

    You can’t directly serialize the columns and rows from the ListView to the file, so what you do is create a collection and then serialize this. One collection type that works well is the ArrayList. The next line of code creates this.

    Then, you read each row of data from the ListView into the ArrayList.

    Finally, you take that BinaryFormatter, use its Serialize method, passing in the FileStream (to connect to the file) and the ArrayList(to give access to the ListView data).

    Deserialize the data to a ListView
    The serialized data is fine where it is, but presumably at some point you may want to pipe it back into the ListView. To do that, you use a similar approach. You create a FileStream, a BinaryFormatter, and an ArrayList again.

    Then, you use the Deserialize method of the BinaryFormatter object and read the data from the file into the ArrayList.

    Once the ArrayList holds the data, you can iterate through it, read the content, cast each element to ListViewItem, and then add the ListViewItem to the ListView.

    Here’s the code that does this:

      Private Sub DeserializeToListView(ByVal LV As ListView, ByVal filename As String)

        '  Create a FileStream to access the storage file

        Dim FS As FileStream = File.Open(filename, FileMode.Open)

        '  Create a Binary Formatter for Serialization process

        Dim BinFmtr As New BinaryFormatter

        '  Create an arraylist as temp storage for listview items data

        Dim alSavedLV As New ArrayList

     

        '  Deserialize the data from the file and put it in the arraylist

        alSavedLV = CType(BinFmtr.Deserialize(FS), ArrayList)

     

        '  Read the arraylist contents into the listview

        Dim lvi As ListViewItem

        For item As Integer = 0 To alSavedLV.Count - 1

          lvi = New ListViewItem

          lvi = CType(alSavedLV(item), ListViewItem)

          LV.Items.Add(lvi)

        Next

     

        '  Done with the FileStream

        FS.Close()

      End Sub

     Summary
    Once you understand the tools you can use – FileStream, BinaryFormatter, and ArrayList – serializing and deserializing is a trivial task.


  • 10/19/11--12:31: SharePoint 2010 And Excel Services when switching to Claims Based Authentication. (chan 2127976)
  • Doing some work for a customer on SharePoint 2010 where I hadn't setup the initial environment & came across an interesting situation which had me pulling what little hair I have out, so thought I'd create a quick blog post in case anyone else stumbles upon this situation in the future.

    The web app had initially been setup using Classic Mode Authentication but due to access being required with both Windows & Forms Based Authentication using the SQL provider mechanism I needed to change it to Claims Based Authentication.  This all went relatively smoothly apart from one tiny problem....

    Previously to the switch over spreadsheets had been opening nicely in the browser with Excel Services however after the change over, they were getting the error that the user did not have permissions to open the file in the browser.  This was easily remedied by jumping into Global Settings for excel services changing the File Access Method from Impersonation over to using the Process account instead, and I also setup the Unattended Service Account which for some reason they hadn't done in the initial install.

    Then tried opening the file in the browser again only to be confronted with a new error "The workbook cannot be opened."  This had me scratching my head for a little while until I looked in the event log where I found that the Service Account being used for Excel Services hadn't been given any rights on the content database.  After which the fix was easy to implement with the following PowerShell commands

    $webApp = Get-SPWebApplication "http://YourSharePointSite" 
    
    $webApp.GrantAccessToProcessIdentity("YourDomain\ExcelServicesAccountName")
    

    Hopefully this will save someone else a bit of time.

     


  • 10/20/11--00:45: How to Create a Numerals Only TextBox (chan 2127976)
  • Introduction
    If you want to restrict the user input into a text box, you can check what the current key press is and then decide if it’s an allowed key or not. At the other end of the scale, you can create a standalone user control that can be added to the Toolbox, and have instances of it dragged on to forms across several projects.  This article looks at an approach half way between the two. 

    The TextBox code
    In a Windows Forms application, create a new class and name it NumericTextBox.  Add an Inherits statement as shown below that will make this class inherit from the standard TextBox class:

    Public Class NumericTextBox

      Inherits TextBox

     

    The next step is to identify the keys that we will allow the user to use in this text box. One way of doing this is to create an array that holds the Ascii key codes for allowed keys.

    In our case, this will obviously be the numerals 0 to 9, but we probably also want to allow things like the period, comma, delete and backspace key.  So, these are all added to the array.

      '  Allowed keys

      Dim allowedKeys As Short() = {8, 44, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 127}

     

    With that in place, the reminder of the code overrides the KeyPress event of the text box and checks if the current key press is allowed or not.

    Protected Overrides Sub OnKeyPress(ByVal e As KeyPressEventArgs)

        Dim KeyAscii As Short = CShort(Asc(e.KeyChar))

        MyBase.OnKeyPress(e)

     

         '  Check if this key is allowed

        If allowedKeys.Contains(KeyAscii) Then

          Exit Sub

        Else  ' Ignore input

          e.Handled = True

          Beep()

        End If

      End Sub

    When the user presses a key, the value of that key is stored as a KeyChar property. So, firstly, this code casts the key char to a Short value named KeyAscii before it then allows the text box standard key press code to continue.

    Then it checks to see if the current key press Ascii code is one of the ones contained in that array of allowed values. if it is, then the code lets the key press go through. if it’s not an allowed key, then the Handled property of the KeyPressEventArgs is set to True.  This effectively tells the key press handler that this key press has been dealt with and instructs it not to consider it any further. In other words, that key press is to be ignored.  Optionally, you can warn the user by playing the Beep sound. 

    At its most basic, that’s all that’s needed.  Here’s a summary of the code so far:

    Public Class NumericTextBox

      Inherits TextBox

     

      '  Allowed keys

      Dim allowedKeys As Short() = {8, 44, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 127}

     

      Protected Overrides Sub OnKeyPress(ByVal e As KeyPressEventArgs)

        Dim KeyAscii As Short = CShort(Asc(e.KeyChar))

        MyBase.OnKeyPress(e)

     

        '  Check if this key is allowed

        If allowedKeys.Contains(KeyAscii) Then

           Exit Sub

        Else  ' Ignore input

          e.Handled = True

          Beep()

        End If

      End Sub

     

    End Class

      The next step is to use the NumericTextBox in a form.

    Using the text box in a form

    After you Build the project, go to the Windows Form code page and add the following code:

      Private Sub Form1_Load(sender As Object, e As System.EventArgs) Handles Me.Load

        Dim numericTextBox As New NumericTextBox

        With numericTextBox

          .Left = 20

          .Top = 50

          .Name = "ntxtPrincipal"

          Me.Controls.Add(numericTextBox)

        End With

      End Sub

    Now, when you run the application, the new NumericTextBox will have been added, and the user will only be able to add those allowed characters into it.

    A couple of options
    As all experienced developers know, if it’s possible for a user to foul up the input, they probably will at some time.  So one basic safety check you may want to include is to stop them entering more than one period character.

    This is easy to implement. Change the code for the NumericTextBox class as shown:

     '  Allowed keys

      Dim allowedKeys As Short() = {8, 44, 46, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 127}

      Private periodUsed As Boolean = False

     

      Protected Overrides Sub OnKeyPress(ByVal e As KeyPressEventArgs)

        Dim KeyAscii As Short = CShort(Asc(e.KeyChar))

        MyBase.OnKeyPress(e)

     

     

        If KeyAscii = 46 AndAlso periodUsed = True Then

          e.Handled = True

        End If

     

        '  Check if this key is allowed

        If allowedKeys.Contains(KeyAscii) Then

     

          If KeyAscii = 46 Then periodUsed = True

          Exit Sub

        Else  ' Ignore input

          e.Handled = True

          Beep()

        End If

      End Sub

    I’ve highlighted the changes. First, I added a Boolean that keeps track of whether a period has already been entered.  Then before the code even checks if the current key press is an allowed one, it specifically checks to see if this key press is a period and  the text box already contains a period.  If this is the situation, then this attempt to enter another period is blocked by the use of the e.Handled = True line.  The final action is to switch that Boolean to True the first time the user enters a period.

    Summary
    That’s a very basic numerals only text box.  You can of course expand the options to control what the user is allowed to enter, if you want a text box that, for instance, only allows certain letters.  Or certain letters and numbers, and so on.


  • 10/24/11--02:35: Three ListView Tips and Tricks (chan 2127976)
  • Introduction
    The ListView is a really useful control for display data, but it’s not always easy to see how to get it to look just the way you want.  Here are a few tips and tricks.

    First, there’s how to change the color of alternative lines, then there’s how to insert a new line of data at runtime. Finally, how to find an item in a ListView and change it.

    Change the color of alternate lines
    To enhance the look of the otherwise plain white background, you can inject color into alternate lines:

    ListViewAlternateLines

    The code is quite simple:

      Private Sub ChangeAlternateColors(LV As ListView)

        Dim color1 As Color = System.Drawing.Color.LightBlue

        Dim color2 As Color = System.Drawing.Color.Beige

     

        Dim alternator As Integer

        Dim lvi As ListViewItem

        For Each lvi In LV.Items

          If alternator Mod 2 = 0 Then

            lvi.BackColor = color1

          Else : lvi.BackColor = color2

          End If

          alternator += 1

        Next

      End Sub

    The key that makes this work is Integer variable named alternator. As the code enumerates through each line of the ListView, this variable increments by 1. Then, a check is made to see if the value of alternator is odd or even. That’s what the

     If alternator Mod 2 = 0 Then

    line does. If the line number is even, then color1 is used as the background; otherwise color2 is used.  Simple, but effective.

    Insert a new item into a specific row of a ListView
    If you want to programmatically add a new item, there are a couple of options. if it’s just a question of adding text to the first column, then you can use this approach:

    ListView1.Items.Insert(3, "James May")

    In this example, the name is inserted as a new row (which is of course the fourth row down, because the ListView Items are zero indexed).

    In reality, you’ll usually want to insert data in other columns too.  This takes a slightly more verbose approach, but it’s still easy:

        With ListView1

          .Items.Insert(3, "James May")

          .Items.Item(3).SubItems.Add("www.bbc.co.uk/topgear")

          .Items.Item(3).SubItems.Add("Technology, cars, engineering, aeroplanes, flying")

        End With

    You can see the result here:

    ListViewInsertItem

    James May has been added to the fourth line.

    Find an item and change it
    If you need to programmatically find a particular item in the ListView, and then edit the content, you can use code like this:

      Private Sub FindAndChangeAnItem(LV As ListView, SearchText As String, ReplacementText As String)

        For i As Integer = 0 To LV.Items.Count - 1

          If Trim(LV.Items(i).Text) = SearchText Then

            LV.Items(i).Text = ReplacementText

          End If

        Next

      End Sub

     

      Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click

        FindAndChangeAnItem(ListView1, "James May", "James A. May")

      End Sub

    This example only looks in the first column.

    And, as before, in the real world things are seldom as easy as just needing to change something in column 1. So if you need to dig deeper into the other columns, then you can search the subitems too, find the search term,and make the change:

      Private Sub FindAndChangeASubItem(LV As ListView, SearchText As String, ReplacementText As String)

        For i As Integer = 0 To LV.Items.Count - 1

          If Trim(LV.Items(i).Text) = SearchText Then

            LV.Items(i).Text = ReplacementText

            Exit Sub

          Else

            For subitems As Integer = 0 To LV.Items(i).SubItems.Count - 1

              If Trim(LV.Items(i).SubItems(subitems).Text) = SearchText Then

                LV.Items(i).SubItems(subitems).Text = ReplacementText

                Exit Sub

              End If

            Next

          End If

        Next

      End Sub

      Calling code:

    FindAndChangeASubItem(ListView1, "www.bbc.co.uk/topgear", "http:www.jamesmay.com")

    Summary
    These little tips and tricks can change your ListView experience from one that’s quite limited and frustrating, to something that makes you realize that it’s a really useful control that you’ll be happy to use.


  • 10/31/11--11:11: How To Search for Multiple Occurrences of a String in a ListView (chan 2127976)
  • Introduction
    In an earlier blog I showed how to search for a word or phrase in any column of a list view, and then select and highlight any rows that contained the search word or phrase.  In that first example, I restricted the search in two ways. 

    Firstly, I stopped as soon as the search string had been found once (and so ignoring the situation where the same term might occur several times).  Secondly, and perhaps more importantly, that example required the search term to be matched exactly with what appeared in any of the columns.  In other words, if the search term was ‘Jeff’, then it wouldn’t be found as a match in a column that contained the phrase ‘Jeff Martin’.  In many real world scenarios, this simply won’t cut it, so let’s move on to the next stage and build in these features.

    Contains – not Equals
    The key to the partial match search is to use the Contains string function in place of the “=” symbol approach we first used.  As you’d expect from the name, Contains will return a value of True if the string contains the search term within any part of its whole length.  So, it will return True for ‘Jeff’ in Jeff Martin, or True for ‘Mar’ in Jeff Martin, or even True for ‘ff M’ in Jeff Martin.  You get the picture.

    Here’s part of the code for the function that carries out the search:

      Private Function FindPartialItems(ByVal LV As ListView, ByVal TextToFind As String) As List(Of Integer)

       

        ' Loop through LV’s ListViewItems.

        For i As Integer = 0 To LV.Items.Count - 1

          If Trim(LV.Items(i).Text).Contains(Trim(TextToFind)) Then

     

     

    As you can see, the Contains function is used to check if the first column contains the search term.  Trim is used to remove spaces either side of the search term and the text in the column, simply to avoid any matches that might fail just because one side has a space and the other doesn’t.

     

    Storing the row numbers where a match is found

    Let’s look at a bit more of the procedure to see what happens if a match is found:

      Private Function FindPartialItems(ByVal LV As ListView, ByVal TextToFind As String) As List(Of Integer)

       Dim rowsFound As New List(Of Integer)

     

        ' Loop through LV’s ListViewItems.

        For i As Integer = 0 To LV.Items.Count - 1

          If Trim(LV.Items(i).Text).Contains(Trim(TextToFind)) Then

            ' If found, add to collection

            rowsFound.Add(i)

          End If

    At this stage, a List(Of Integer) has been added, and this will be used to hold the row numbers where matches are found.  List(Of T) is probably a bit of a sledgehammer for this task, but I find it much easier to work with than other options, such as an array of ints. 

    So, if the text in the first column of the current row is found to contain the search term, the row number is added to the list. 

     Checking the remaining columns
    That’s the first column dealt with, so next the code will check the remaining columns.

      Private Function FindPartialItems(ByVal LV As ListView, ByVal TextToFind As String) As List(Of Integer)

        Dim rowsFound As New List(Of Integer)

     

        ' Loop through LV’s ListViewItems.

        For i As Integer = 0 To LV.Items.Count - 1

          If Trim(LV.Items(i).Text).Contains(Trim(TextToFind)) Then

            ' If found, add to collection

            rowsFound.Add(i)

          End If

          For subitem As Integer = 0 To LV.Items(i).SubItems.Count - 1

            If Trim(LV.Items(i).SubItems(subitem).Text).Contains(Trim(TextToFind)) Then

              ' If found, note the row number unless the same search term was found in an earlier column of this row

              If Not rowsFound.Contains(i) Then rowsFound.Add(i)

            End If

          Next

        Next

    The nested loop For subitem As Integer … checks through each of the remaining columns of the current row.  Again, it uses the Contains method to see if there’s a match to be found.

    Then, we want to deal with the case where the search phrase occurs more than once in the same row.  To avoid duplicate numbers in the list of rows, you’ll see that the  Contains method is used again for a different purpose:

    If Not rowsFound.Contains(i) Then rowsFound.Add(i)

    This time it makes sure that a row number is only added to the list once.

    Returning the result
    The final task, once the whole list view has been processed is to return the list of integers:

     Return rowsFound

    So the complete FindPartialItems method looks like this:

     

      Private Function FindPartialItems(ByVal LV As ListView, ByVal TextToFind As String) As List(Of Integer)

        Dim rowsFound As New List(Of Integer)

     

        ' Loop through LV’s ListViewItems.

        For i As Integer = 0 To LV.Items.Count - 1

          If Trim(LV.Items(i).Text).Contains(Trim(TextToFind)) Then

            ' If found, add to collection

            rowsFound.Add(i)

          End If

          For subitem As Integer = 0 To LV.Items(i).SubItems.Count - 1

            If Trim(LV.Items(i).SubItems(subitem).Text).Contains(Trim(TextToFind)) Then

              ' If found, note the row number unless the same search term was found in an earlier column of this row

              If Not rowsFound.Contains(i) Then rowsFound.Add(i)

            End If

          Next

        Next

        ' Return the resulting collection of rows

        Return rowsFound

      End Function

    The Calling Code
    All that remains is to write some code that uses this search method:

      Private Sub Button_Click(sender As System.Object, e As System.EventArgs) Handles btnPartialSearch.Click

        ListView1.FullRowSelect = True

        ListView1.MultiSelect = True

     

        Dim foundRows As New List(Of Integer)

        foundRows = FindPartialItems(ListView1, TextBox1.Text)

     

        If foundRows.Count = 0 Then Label1.Text = "Search string not found"

     

        For i As Integer = 0 To foundRows.Count - 1

          ListView1.Items(foundRows(i)).Selected = True

        Next

     

        ListView1.Focus()

        ListView1.SelectedItems(0).EnsureVisible()

     

      End Sub

    This is similar to the calling code used in the earlier blog.  The main changes are that MultiSelect is now set to true.  Obviously, if we’re returning a list of potentially multiple hits, we want to able to highlight them all.

    Next, a temporary list of integers is created and the search function called.  Once a result has been returned, it first tests that there has been at least one match.  If not, a message is displayed.

    Then, if there are one or more matches, the row numbers can be pulled from the list of integers and each of those rows is selected. 

    Finally, as in the earlier blog, the focus is handed off to the list view to bring the highlights to life, and if necessary the list is scrolled to reveal the first matching row.

    listViewSearch2


  • 11/07/11--00:39: How to Bold text in a Windows Forms ListView (chan 2127976)
  • Introduction
    Sometimes you’ll want to highlight items in a ListView to grab the user’s attention. One way you can do this is to programmatically apply Bold font weight to text.

    Bold all items in the first column
    Let’s say you have a ListView like the one below:

    ListViewBold1

    To bold all the text in the first column is particularly easy. There are only two steps:

    1. Set the UseItemStyleForSubItems property to False so that only the first column is affected.
    2. Enumerate through the ListView items and apply Bold font to the ListViewItem by its name (lvi):

        For Each lvi As ListViewItem In ListView1.Items

          lvi.UseItemStyleForSubItems = False

          ' lvi.SubItems(0).Font = New Font(ListView1.Font, FontStyle.Bold)

          lvi.Font = New Font(ListView1.Font, FontStyle.Bold)

        Next

    ListViewBold2

    Using ‘lvi.Font’ in this example is effectively the same as using lvi.SubItems(0).Font. So, this would work just as well:

        For Each lvi As ListViewItem In ListView1.Items

          lvi.UseItemStyleForSubItems = False

          lvi.SubItems(0).Font = New Font(ListView1.Font, FontStyle.Bold)

          'lvi.Font = New Font(ListView1.Font, FontStyle.Bold)

        Next

     Bold all items in a selected column
    The second example above should make it clear what we need to do to bold one of the other columns. You simply change the index of the target column and use the same code:

        For Each lvi As ListViewItem In ListView1.Items

          lvi.SubItems(2).Font = New Font(ListView1.Font, FontStyle.Bold)

        Next

    The result will be:

    listviewbold3

    Bold only items that contain a search term
    Let’s take a scenario where you want to highlight all items in the second column that contain the string ‘web’ as part of its text.

        For Each lvi As ListViewItem In ListView1.Items

          If lvi.SubItems(1).Text.Contains("web") Then

            lvi.UseItemStyleForSubItems = False

            lvi.SubItems(1).Font = New Font(ListView1.Font, FontStyle.Bold)

          End If

    In my example, the result will be:

    Listviewbold4

    Of course, you could use this kind of code to search for an exact entry, not just a substring. In that case, you’d use something like

                 If lvi.SubItems(1).Text.Contains(" (fredi@gerts.ch )”) Then

    But bear in mind that spaces might mean that sometimes you don’t get a match you think exists.  You can use the Trim function to strip out unimportant space characters.

    And you can search through the whole ListView for a partial or exact match if you tweak the above code a little.


  • 11/12/11--13:09: Web Essentials - a look at the VS Extension (chan 2127976)
  • Recently I was browsing through the extensions available for Visual Studio when I came across this handly little extension called Web Essentials.

    Ive been using this extension for a few weeks now and figured it was time for me to share the wealth.

    For any web developer this extension is a nice tool to have in your arsenal, I know I enjoy having it in mine.

    A few features of the Web Essentials extension that I favor the most are 

    • Live Web Preview, right in Visual Studio.  (Allows you to preview your site in real time as your editing it)
    • Support for Live CSS Updating in the Live Web Preview (Allows you to preview css changes to your site as you make them)
    • The Color Glyph (Shows a preview of color codes in your text editor.)
    • The ability to add Javascript and CSS file directly from the context menu in the solution explorer.

    If your interested in checking out the full list of features you can find the documentation here

    Happy Coding!


  • 11/14/11--08:23: How to compress the size of an image file at runtime (chan 2127976)
  • Introduction
    This came up as a question on VB City recently, where the poster wanted to reduce image file sizes before saving to a database as a BLOB. It turns out that it’s easier to do than you might think.  If you have an Image object, you can use its Save method to store it to your hard drive or other storage media.  At the same time, you can use an encoder parameter that sets the quality of the saved image.

    Here’s how to do it:

    The core code

    This method takes the image to be compressed, the path and file name that you want to use for the save, and a quality level between 1 and 100.  The lower the value of the quality level parameter, the greater the compression.  Of course, as you increase the compression (i.e. the lower the number), the quality of the saved file will reduce.  So you’ll often have to experiment to find the best compromise between size and quality.

     

      Private Sub CompressAndSaveImage(ByVal img As Image, ByVal fileName As String, ByVal quality As Long)

        Dim parameters As New EncoderParameters(1)

        parameters.Param(0) = New EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality)

        img.Save(fileName, GetCodecInfo("image/jpeg"), parameters)

      End Sub

    You’ll see that the second parameter of the Save method calls another method called GetCodecInfo and passes in a string that represents a mime type.  Here’s that second method, which loops through all image encoders on the system and returns the one that’s required for the selected image type.  In the event that a non-existent image type is passed in to this method, an error is thrown.

     

      Private Shared Function GetCodecInfo(ByVal mimeType As String) As ImageCodecInfo

        For Each encoder As ImageCodecInfo In ImageCodecInfo.GetImageEncoders()

          If encoder.MimeType = mimeType Then

            Return encoder

          End If

        Next encoder

        Throw New ArgumentOutOfRangeException(String.Format("'{0}' not supported", mimeType))

      End Function

    Finally, you call the compress and save image method, passing in the required arguments.  For example:

    CompressAndSaveImage(selectedImage, reducedImage, 50)

    where selectedImage is an image object, reducedImage is a string that defines the path and file name to save, and 50 represents the quality level.

    So, that’s all the core code you need to compress an image file.  Let’s take a look at how you can make it available to your users.

    Adding a user interface
    Here’s one way of using it:

    ImageCompress

    The key controls on this form are:

    • A NumericUpDown named qualityLevel
    • A button named btnCompress
    • Two  picture boxes named PictureBox1 and PictureBox2
    • An OpenFileDialog named OpenFileDialog1

    The code is as follows:

    First, add Imports statements :

       Imports System.Drawing.Imaging
       Imports System.IO

    Then, declare a form level variable to keep track of the user’s choice of compression/quality level:

       Dim level As Long = 50

    Catch the user’s choice of quality level when it changes from the default of 50:

      Private Sub qualityLevel_ValueChanged(sender As System.Object, e As System.EventArgs) Handles qualityLevel.ValueChanged

        btnCompress.Enabled = True

        level = CLng(qualityLevel.Value)

      End Sub

    Finally, when the user clicks the button, do the following:

    1. Display the open file dialog
    2. If the user chooses a file, create an image using the selected file as the source.
    3. Display the image in its original form in the first picture box.
    4. Create a file name for the compressed file.
    5. Call the compress and save method on that image.
    6. Show the user that something’s happened by displaying the reduced image in the second picture box. This also lets them check the quality of the reduced size image.

      Private Sub btnCompress_Click(sender As System.Object, e As System.EventArgs) Handles btnCompress.Click

        ' Get user's choice of file

        If OpenFileDialog1.ShowDialog = Windows.Forms.DialogResult.OK Then

          Dim selectedImage As Image = Image.FromFile(OpenFileDialog1.FileName)

          ' Display it

          PictureBox1.Image = Image.FromFile(OpenFileDialog1.FileName)

          ' Create a name for the reduced file

          Dim reducedImage As String = "C:\Temp\Reduced_" & OpenFileDialog1.SafeFileName

          ' Compress and save the reduced file

          CompressAndSaveImage(selectedImage, reducedImage, level)

          ' Display the reduced image so that user can compare quality

          PictureBox2.Image = Image.FromFile(reducedImage)

          PictureBox2.SizeMode = PictureBoxSizeMode.StretchImage

        End If

      End Sub

    Final Note
    That works well, although you still need to build in real world checks, such as making sure the user selects an image file type from the open file dialog, and so on. Another small problem is that the code will fail if the reduced file name already exists. You can code round this in several ways, according to your preference, but one way would be simply to tell the user about the problem:

        If Not File.Exists(fileName) Then

          img.Save(fileName, GetCodecInfo("image/jpeg"), parameters)

        Else

          MessageBox.Show("Reduced file already exists.")

        End If

    You could extend this code so that it either automatically deletes an existing file or asks the user to authorise the deletion before proceeding.  I’d also be tempted to add a couple more labels to the form and show the user the original file size and the reduced file size. You can use FileInfo objects for this.

     Summary
    This is a useful little procedure that you can use when you want to reduce the size of an image file, but want to be able to judge the loss of quality.


  • 11/27/11--06:11: Metro Visual Basic Hello World Application (chan 2127976)
  • Looking for a hello world app for Metro written with Visual Basic?

    ...(read more)

  • 11/28/11--08:19: How to read text file content into a List (of String) (chan 2127976)
  • Introduction
    I was looking through some questions I answered a while back and came across this problem where someone wanted to read text from a file, strip out the commas, and then store the individual items in an in-memory List.  Here’s the way I did it:

    The text file
    Here’s the structure of a text file that we want to use.  This is just an example:

    All red berries, Blackcurrant, Strawberry, Cranberry
    Banana, Pineapple,
      Rhubarb, Pear, Granny Smith Apple
    Other apple,     cherry, damson
    grape
    plum, mandarin orange

    Code that reads the file
    The first step is to create the List that will hold the items:

          Dim stockList As New List(Of String)

    Next, we need to access the text file and set up some variables that we’ll use to store the data as we process it:

      Try

                Dim file_name As String = "C:\Temp\stockList.txt"

                Dim stream_reader As New IO.StreamReader(file_name)

                Dim line As String

                Dim ReadResult() As String

    The first line identifies the path and name of the source file. The second line creates a StreamReader that will be used to get the text from the source file.  If you use an Imports statement for System.IO at the top of the file, you can drop the “IO.” part of the code.

    The variable named “line” will hold all the characters in each line of the file as it’s being read. Finally, the array “ReadResult” will temporarily hold each sub-string from a line of text in the file. So, to take the first line as an example, ReadResult would hold four strings -

    All red berries
    Blackcurrant
    Strawberry
    Cranberry

    Now, the code for the reading, processing, and adding to the List tasks:

                ' Read the file one line at a time.

                line = stream_reader.ReadLine()

                Do While Not (line Is Nothing)

                    ' Trim  the line in case there are any leading or trailing spaces in file line   

                    line = line.Trim()

                    '  split using comma chars

                    ReadResult = line.Split(",")

     

                    '  Populate List

                    For i As Integer = 0 To ReadResult.Length - 1

                        If ReadResult(i).Length > 0 Then stockList.Add(ReadResult(i).Trim.ToString)

                    Next

     

                    ' Move on to the next line.

                    line = stream_reader.ReadLine()

                Loop

    The ReadLine method does what you’d expect, and reads a complete line from the file. It then stores that line in the String variable named “line”.

    Next, the Do While Loop first removes any leading or trailing spaces from the line.  Don’t be confused here:  This only affects spaces at the very beginning of line, such as the third line in the file that has spaces before the first word, or spaces at the very end of the line.

    The Split function reads the line of text and splits it up whenever it finds a comma.  It then assigns each chunk of text to one of the elements in the ReadResult array.

    Now that ReadResult has the split contents of the line, the next step is pass those strings to the List. The code block begins with a For statement that ensures that each element of the ReadResult array will be read in turn. 

    The next line starts with an If statement and might look  a bit complicated.  But really all it does is:

    1. Checks that the element isn’t empty. (This can happen, for instance, if the line ends with a comma – which line 2 does)
    2. Then adds that element to the List ….
    3. ….While at the same time removing any unwanted spaces from the string (for example the spaces in front of cherry in the fourth line).

    The last action in the loop is to move the reader down to the next line in the text file.

    Finally in the reading and processing stage, the StreamReader is closed and a message box is used if there’s any problem accessing the file or processing the text:

            Catch exc As Exception

                ' Report all errors.

                  MessageBox.Show(exc.Message.ToString, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)

            End Try

    Displaying the result
    For the purposes of demonstration, I’ve added code that will fill a list box with the individual items:

     

            For Each Str As String In stockList

                ListBox1.Items.Add(Str)

            Next

    The result in the windows form when this code runs looks like this:

    ReadTextFileToList


  • 12/05/11--09:29: How to identify an item or sub item the users selects in a ListView (chan 2127976)
  • Introduction
    Here’s a little ListView trick that might come in useful sometimes.  The user selects an individual sub item in a list view and you want to know what they selected.

    The code
    You can code the MouseDown event of the ListView to identify the selection:

      Dim usersSelection As String = String.Empty

      Private Sub ListView1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles ListView1.MouseDown

     

        Dim info As ListViewHitTestInfo = ListView1.HitTest(e.X, e.Y)

        usersSelection = info.SubItem.ToString

        usersSelection = usersSelection.Substring(18)

        usersSelection = usersSelection.Substring(0, usersSelection.Length - 1)

     

        Me.TextBox1.Text = usersSelection

     End Sub


    How it works
    The first line creates a String variable that will store the user’s selection.

    Then, in the MouseDown event, an instance of the ListViewHitTestInfo class named ‘info’ is created. This object can return information about the ListView if it’s passed information such as the current location of the cursor.  That’s where the ListView’s HitTest function is used and, as you can see, this function is passed in the current X and Y points of the mouse cursor (e,X and e.Y).  Alternatively, you can pass in e.Location in place of the X and Y values and this seems to work just as well.

    In the next few lines, I’ve purposely broken the code into three steps just to make it easier to read.  You could of course put this all in one line of code. It works like this:

    • Firstly, it gets the SubItem that the cursor is currently over.
    • Then – because this particular property happens to return some additional information that we don’t need – the code strips off the first 18 characters.  (If you’re curious, you can comment out this line)
    • For the same reason, the code removes the final characters from the string that the ListViewHitTestInfo returns.
    • For demo purposes, this code sample then displays the selection in a text box.

    The result

    Here’s an example that shows this in action:

    ListViewHitTest

    If the full row selection is confusing, you can turn it off in the properties window. That way, it’s a bit more obvious where the user is clicking:

    ListViewHitTestAlt

    You can see the cursor position here. 

    Summary
    This code returns items (i.e. column 1 text) and sub items (any other column).  If – as in my example – you let the user see an area of the list view that doesn’t contain a column (i.e. the blank area at the right hand side), you’ll need to code agains the user clicking in that area.  As it stands, the system will crash. You can do this very simply by testing with:

     

     If Not info.SubItem Is Nothing Then

       . . .

       It’s also possible to include code that returns the index number of the selected column text of the column header of the selected column, although that’s not really a requirement you’re likely to need often.  


  • 12/19/11--10:59: Book Review: Murach's ASP.NET 4 Web Programming with VB 2010 (chan 2127976)
  • Murach's ASP.NET 4 Web Programming with VB 2010

    This is the first Murach book that I have the chance to read and I love the "paired-paged" layout, the organisation and the overall flow of the book.

    The paired-paged layout gives the reader information and explanations on the left side and code samples, guidelines, descriptions on the right.

    Starting out the book takes you through the basics of ASP.NET and moves you right into real world scenerios and concepts.

    Reaching the end of the book you will have learned a great deal about the core concepts of asp.net, making web applications responsive and secure.

    By far one of the best programming books on my shelf.

    No matter the skill level, this book is a great read and full of knowledge!

    Click here to check out the page on Murach's website.


    Thanks Murach!!


  • 12/20/11--04:08: VS 11 Developer Preview(s) (chan 2127976)
  • The descriptions on Microsoft’s site don’t make it very clear that there are two separate versions of the Visual Studio 11 preview that you can download and try. The one you’ll probably find first is the almost complete VS preview here.

    This is pretty much the whole package in terms of the changes they’ve made to the Windows 7/Win 32 base version. The best advice generally is to install it somewhere other than your main system – a separate partition, on a spare machine, or in a virtual machine. VMware and Virtual Box both seem to do the job nicely.

    Just for the heck of it, I have tried installing a copy on my main machine, and uninstalled it without causing any problems to the original VS 2010 that was also installed. But that’s no guarantee that it’ll work as smoothly for you, so as they used to say on Hill Street Blues, “Be careful out there”.

    I said ‘pretty much’ the whole package, but of course the much talked about Metro UI is a Windows 8 feature and so you can’t get at it with the Windows 7 based preview. If you want to play with Metro then you need to download the much bigger package from here

    Now this is an installation that you definitely want to keep well away from your workaday system. Again, most people seem to install this in a virtual machine and the most successful one seems to be Oracle’s Virtual Box.

    Although I’ve used both VMWare and Virtual Box extensively in the past, and found them both to be excellent, intuitive tools, my Windows 8 experience wasn’t quite so good. I’m sure this has more to do with the fact that it’s a developer preview than any fault with the VMs. But I had issues with speed (not unusual for VMs, but more obvious on this occasion) and also some problems with display resolution and size.

    So I thought I’d try and find an alternative that still let me use my main developer machine. Dual booting usually leads to frustration, and is especially tricky when one of the OSs isn’t fully baked. And you wouldn't get good odds on a clean and successful uninstall at some later stage either. The route I took was to use Paragon’s Hard Disk Manager tool.

    The key feature of this tool that I needed was the ability to hide a partition. That way I could have Win 7 on one partition, Win 8 on another, and when I booted up the system only the one I wanted at that particular time would be visible to the system.

    And so that’s what I did – created two partitions on the drive, one of them hidden. I then installed Windows 8 preview on the second partition. I used a DVD I‘d created from the original downloaded iso to install the Windows 8 OS. One thing I did find is that I had to leave this disk in the tray when I rebooted, although I ignored the ‘Boot from CD/DVD’ message each time I ran it after the first installation. I really don’t know why it seemed to need that, but anyway, it worked OK.

    When I wanted to go back to my Windows 7 installation, I rebooted with the Paragon Recovery Disk in the CD tray (you’ve got a recovery disk right?). The Paragon menu software then let me switch the partitions back (i.e. hiding the Windows 8 one, and making the Windows 7 one available).

    Of course, this only works well if you’re happy to be restricted to the one OS at a time, which I was. Although I have the full Paragon Hard Disk Manager 11 Suite, which is an exceptionally useful tool, you can in fact create and hide partitions with their free version of Partition Manager (although currently on offer at $9.95 it probably wouldn’t break the bank to get the retail version, which has more features).

    Windows 8, with its Metro UI tiles, is interesting, but takes some getting used to. The ‘immersive’ experience, that Microsoft like to talk up, generally means that you find yourself searching around for some way to minimize, resize, or even close down a running Metro UI app. Like most people, I find the way it switches back to desktop (Windows 7) mode a bit jarring, although I realise that you can’t magically “Metrofy” all those old applications.

    I’m most interested in seeing if all those long hours I’ve put in learning WPF and Silverlight over the past few years will be useful for creating Metro apps with XAML. I’m optimistic that they will be. The namespaces and classes may have changed, but the underlying approach seems very similar.


  • 12/27/11--07:01: How to populate a combo box with an enumeration (chan 2127976)
  •  

    This is one of those simple things that comes into the category of “I know how to do it, but, umm, it’s been a while, and now I’ve forgotten how!”

    So, here’s an enumeration of strings:

    Public Enum QuestionCategory
        Art
        Music
        People
        Places
        Science
        Words
        Miscellaneous
        BeginsWith
        Inventions
        History
        Animals
        Legends
    End Enum

    If I want to populate a combo box named cboCategories with these strings, I can use the following code:

       Me.cboCategories.DataSource = System.Enum.GetValues(GetType(QuestionCategory))

    Then, when I want to know the user’s selection, I use:

         Me.cboCategories.SelectedValue.ToString()

    That’s it!


  • 12/30/11--06:31: Three and a half simple tips (chan 2127976)
  • Happy holidays.  Here are a few easy programming tips that can improve your technique.  They're aimed at beginners, as well as more experienced programmers who started with VB Classic.

    TIP 1:  Combine variable declaration and initialization.

    The following two code snippets are equivalent:

    Dim sr5 As Decimal 
    ... 
    sr5 = Math.Sqrt(5)
    

    Dim sr5 As Decimal = Math.Sqrt(5)
    

    However, I strongly prefer the second usage, because:

    • It's less typing.
    • The intention of the variable is clearer.  The reader doesn't have to hunt through code, thinking "I wonder what sr5 means?"
    • It avoids "variable not initialized" errors.
    • By not declaring a variable until you're ready to use it, you can keep its scope smaller.  This code can be placed anywhere in a block, and the later you do so, the simpler your debugging becomes.

    TIP 2: Use Booleans to help document, and to avoid recoding the same test condition.

    Again, here are the "before" and "after" versions:

    Dim emp As New EmployeeRec 
    If (HoursWorked > 40) Then 
        emp.RegHours = 40 
        emp.HasOT = True 
        emp.OTHours = HoursWorked - 40 
    Else 
        emp.RegHours = HoursWorked 
        emp.HasOT = False 
    End If
    

    Dim emp As New EmployeeRec 
    Dim WorkedOT As Boolean = (HoursWorked > 40)
    If (WorkedOT) Then
        emp.RegHours = 40 
        emp.OTHours = HoursWorked - 40 
    Else 
        emp.RegHours = HoursWorked 
    End If
    emp.HasOT = WorkedOT
    

    In this case, the second version doesn't benefit from significantly briefer code (although it often does).  The benefits are readability, and a more obvious mapping of the condition to the EmployeeRec.HasOT attribute.  I could have shortened this further by using emp.HasOT directly instead of introducing the Boolean, but it would have been less illustrative.

    TIP 2A: Use the shorthand boolean assignment.

    The assignment of WorkedOT in the above example is much shorter than the code below.  So don't do it this way:

    Dim WorkedOT As Boolean
    If (HoursWorked > 40) Then
        WorkedOT = True
    Else 
        WorkedOT = False
    End If
    

    TIP 3: Use variables to prevent multiple calls to functions.

    Again, before and after:

    If CalculateOTPay(HoursWorked, HourlyRate) > 0 Then
       ...
       emp.OTPay = CalculateOTPay(HoursWorked, HourlyRate)
    Else 
       emp.OTPay = 0
    End If
    

    Dim PayOT As Decimal = CalculateOTPay(HoursWorked, HourlyRate)
    If (PayOT > 0) Then
       ...
       emp.OTPay = PayOT
    Else 
       emp.OTPay = 0
    End If
    

    It's really important to avoid the first usage.  Running complicated functions multiple times can be expensive in run time.  And worse, in some cases you may get a different answer!  For example, if the function returns "seats available" and someone else just booked a seat.  Or if the date changes.  Or if the function communicates with a sensitive hardware gauge that measures continually changing values like network traffic or conveyor belt speed.  Trust me, there are more examples.

    Thanks for reading.  Happy new year to all.

     


  • 01/04/12--03:50: How to filter files in an OpenFileDialog (chan 2127976)
  • Introduction
    I don’t know what it is about the syntax for the Filter property of the open file dialog, but it often seems to take me longer than it should to get it to work the way I want.  If you’ve had problems too, then this may help you.

    Step 1: create the OpenFileDialog
    Although you can drag an open file dialog from the toolbox, it’s just as easy to create it on the fly:

      Dim openfiledlg As New OpenFileDialog

    Step 2: Create a With block
    You can write code that’s easier to follow if you use a With block:

    With openfiledlg

    End With

    Step 3: (Optionally) set a default path
    You can make life easier by setting a value on the InitialDirectory property:

    With openfiledlg
            .InitialDirectory = "C:\Images"
    End With

    Step 4: Set the Filter property
    So here’s the usually tricky bit.  To start with a typical example:

    .Filter = "Image Files (*.png *.jpg *.bmp) |*.png; *.jpg; *.bmp|All Files(*.*) |*.*"

    Then, to break this down, first look at the sub string from Image Files to the first pipe (|) symbol:

    .Filter = "Image Files (*.png *.jpg *.bmp)

    This is what the user will see in the file type combo box at the bottom right corner of the dialog.

    openfiledialog

     

    openfiledialog

    It’s traditional to show the user the file extensions of a given category – such as the three shown here – but it isn’t mandatory.  You could just use the string ‘Image Files’ on its own, for instance.

    The next part:

    |*.png; *.jpg; *.bmp

    tells the dialog what file types to filter in and allow to be displayed.  In most cases you’ll use same file extensions as you used in the display.  Note that you need to insert semi-colons between the file extensions to identify where one extension ends and the next one begins.

    The last part of the Filter property code in this example simply adds a second choice of file type.  This time, it’s the standard catch-all of the universal wild card:

    |All Files(*.*) |*.*"

    You can see this as the second choice in the file type combo box above.

    Because there’s only one extension being used, there’s no need to include a semi-colon after the extension.

    So, to summarize the syntax of the Filter property, it’s:

    1. Description of the first file type or types   - e.g. “Image Files (*.png *.jpg *.bmp)
    2. followed by a Pipe symbol
    3. followed by an asterisk, a period, and the first extension – e.g. *.png
    4. followed by a semi-colon
    5. followed by further file extensions, with a semi-colon between each extension
    6. If you want to display more than one line in the file type combo box, repeat steps 1 to 5 above for each extension or group of extensions you want to include.

    Step 5: (Optionally) Set a value on the FilterIndex property
    If you have a long list of extensions and you want to encourage the user to home in on a particular one first, you can set the FilterIndex property to make one of the file type combo box items display first.

    .FilterIndex = 3

    Unusually, this value isn’t zero based, so you set it to 3, for example, to make the third item in the combo box the default selection.

    Summary
    And that’s all there is to it.  I think it’s combination of multiple pipes and semi-colons that makes this task look trickier than it really is.