CanOz Blog

Neil Knobbe's Blog at vbCity

vbCity Blogs moved to:
http://cs.vbcity.com/blogs
  Home :: Syndication  :: Login

OctNovember 2009Dec
SMTWTFS
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

Archives

Image Galleries

vbCity Blogs

Saturday, April 11, 2009 #

My blog has moved to it's new address.

You can find my new blog here.

posted @ 2:01 AM | Feedback (1)

Saturday, October 25, 2008 #

It is a little longer than I expected to get the the project that goes along with this post about background colours in WPF but as they say better late ....

The project can be downloaded from here.

posted @ 10:49 PM | Feedback (0)

I got caught the other day with a "what the heck" moment.

I was trying to display "Mr & Mrs" as an Item in a ComboBox but it just was not happening.

I suppose that this would not have come to light if my computer was not slowing down when I opened the ItemCollection window in Visual Studio.  It was so slow that I would type something then have to wait for a couple of seconds to show what I had typed.  If I made a mistake I had to change it which would take more time, so I decided to just add the five combobox items in the XMAL itself.

As soon as I typed the item in, I got the squiggly blue line and the following error.

 

 

Which really threw me. 

Being an old HTML boy from years past it finally hit me.  XAML is a markup language and most, if not all, markup languages use the ampersand (&) for defining special characters and XML (which XAML is based on) is no different.

XAML has the same character entities as XML and one of these is for using the ampersand in markup.

Having refreshed my memory getting the desired result was an easy fix.

 

Which, when run, shows correctly in the ComboBox.

 

 

 

posted @ 10:11 PM | Feedback (0)

Saturday, October 18, 2008 #

I have just discovered the most compelling reason to port over any projects I have to Windows Presentation Foundataion (WPF) as well as only starting new projects as a WPF project.

The reason you ask?  Well the answer is one word.

Printing

Being a File I/O guy, printing has almost always needed to be a part of most projects that I have written so this is a really big thing for me.  Looking back printing with Visual Basic.NET was painful for me at times especially if the document spanned several pages and I don't even want to get into printing with pre .NET Visual Basic.
That, however, is the past and today we take a look at the present and future.

After creating a table in a flowdocument I got to thinking about being ability to print out the flowdocument.

The WPF PrintDialog class has two methods for printing.  The two methods are PrintVisual and PrintDocument.

This post will deal with the PrintDocument method.

When you use PrintDocument you don’t actually pass the flowdocument that you want to print as a parameter, you use a DocumentPaginator object.

What the documentpaginator does is take the content of the flowdocument and breaks it up into multiple pages (if required) then passes the page(s) to the printer to be printed out.

After importing the necessary namespaces and declaring two Form level variables

 

 

I started out with the code to create a flowdocument that goes over more than one page I used the following code.

 

' Create the parent FlowDocument...

        flowDoc = New FlowDocument()

 

        Dim table2 As New Table()

 

        flowDoc.Blocks.Add(table2)

 

        table2.Columns.Add(New TableColumn)

        table2.Columns.Add(New TableColumn)

        table2.Columns.Add(New TableColumn)

        table2.Columns.Add(New TableColumn)

 

 

 

        ' Create and add an empty TableRowGroup to hold the table's Rows.

        table2.RowGroups.Add(New TableRowGroup())

 

        ' Add the first (title) row.

        table2.RowGroups(0).Rows.Add(New TableRow())

 

        ' Alias the current working row for easy reference.

        Dim currentRow2 As New TableRow()

        currentRow2 = table2.RowGroups(0).Rows(0)

 

 

        Dim v As New Image

        v.Source = New BitmapImage(New Uri("dice.jpg", UriKind.Relative))

        v.Height = 80

        v.Width = 80

 

 

 

        ' Add cells with content to the second row.

        currentRow2.Cells.Add(New TableCell(New Paragraph(New Run("Loan Report"))))

 

        currentRow2.Cells(0).ColumnSpan = 3

        currentRow2.FontSize = 50

        currentRow2.Foreground = Brushes.RosyBrown

        currentRow2.Cells(0).TextAlignment = TextAlignment.Center

 

        currentRow2.Cells.Add(New TableCell(New BlockUIContainer(v)))

 

        table2.RowGroups(0).Rows.Add(New TableRow())

 

        currentRow2 = table2.RowGroups(0).Rows(1)

 

 

 

        currentRow2.Cells.Add(New TableCell(New Paragraph(New Run(" For: Neil Knobbe, " & Now.Date.ToLongDateString))))

 

        currentRow2.Cells(0).TextAlignment = TextAlignment.Center

        currentRow2.Cells(0).ColumnSpan = 4

 

        table2.RowGroups(0).Rows.Add(New TableRow())

 

        currentRow2 = table2.RowGroups(0).Rows(2)

 

        currentRow2.Cells.Add(New TableCell(New Paragraph(New Run("Ammount Borrowed: Borrowed Variable" & vbCrLf & _

                                                                  "Monthly Payment: Payment Variable" & vbCrLf & _

                                                                  "Interest: Interest Variable" & vbCrLf & _

                                                                  "Duration: Duration Variable" & vbCrLf & _

                                                                  "Reason For Loan: Reason Varaible" & vbCrLf & _

                                                                  "Lender: Lender Variable" & vbCrLf & _

                                                                  "Loan Number: LoanNum Variable"))))

 

 

        currentRow2.Cells(0).ColumnSpan = 2

        currentRow2.Cells(0).Padding = New Thickness(10)

 

        ' Create and add an empty TableRowGroup to hold the table's Rows.

        table2.RowGroups.Add(New TableRowGroup())

 

        ' Add the first (title) row.

        table2.RowGroups(1).Rows.Add(New TableRow())

 

        ' Alias the current working row for easy reference.

        Dim currentRow As New TableRow()

        currentRow = table2.RowGroups(1).Rows(0)

 

        ' Add the header row with content,

        currentRow.Cells.Add(New TableCell(New Paragraph(New Run("Date"))))

        currentRow.Cells.Add(New TableCell(New Paragraph(New Run("Balance"))))

        currentRow.Cells.Add(New TableCell(New Paragraph(New Run("Payment"))))

        currentRow.Cells.Add(New TableCell(New Paragraph(New Run("Interest"))))

 

        currentRow.Cells(0).Foreground = Brushes.RosyBrown

        currentRow.Cells(0).TextAlignment = TextAlignment.Left

        currentRow.Cells(1).Foreground = Brushes.RosyBrown

        currentRow.Cells(1).TextAlignment = TextAlignment.Left

        currentRow.Cells(2).Foreground = Brushes.RosyBrown

        currentRow.Cells(2).TextAlignment = TextAlignment.Left

        currentRow.Cells(3).Foreground = Brushes.RosyBrown

        currentRow.Cells(3).TextAlignment = TextAlignment.Left

 

        table2.RowGroups(1).Rows.Add(New TableRow())

 

        currentRow = table2.RowGroups(1).Rows(1)

 

        currentRow.Cells.Add(New TableCell())

 

        currentRow.Cells(0).ColumnSpan = 4

        currentRow.Cells(0).BorderThickness = New Thickness(0, 5, 0, 0)

        currentRow.Cells(0).BorderBrush = Brushes.RosyBrown

 

        Dim i As Integer

 

        For i = 2 To 25

            table2.RowGroups(1).Rows.Add(New TableRow())

 

            currentRow = table2.RowGroups(1).Rows(i)

 

            currentRow.Cells.Add(New TableCell(New Paragraph(New Run("Column " & i - 1 & " Entry - " & i.ToString))))

            currentRow.Cells.Add(New TableCell(New Paragraph(New Run("Column " & i - 1 & " Entry - " & i.ToString))))

            currentRow.Cells.Add(New TableCell(New Paragraph(New Run("Column " & i - 1 & " Entry - " & i.ToString))))

            currentRow.Cells.Add(New TableCell(New Paragraph(New Run("Column " & i - 1 & " Entry - " & i.ToString))))

 

 

        Next

 

        ScrollView1.Document = flowDoc

 

Which, once I applied the table to a flowdocument and set the flowdocument to be the document of my FlowDocumentScrollViewer,

 

 

gave me a table with 50 entries, shown in three columns, which I wanted to print.

 

 

Now that the flowdocument was ready to print all that was left to do was create instance of a WPF PrintDialog and enter the one line of code needed to print the document.

Yes you heard right, one line of code* to print a WPF flowdocument.  How much easier can it get?  (And I thought I was happy when the people at MS made reading the entire contents of a file into a single line of code for Visual Studio 2005.  I am simple ecstatic about this change to printing!)

(* Note – Although you can accomplish printing with just this one line, there are a few gotchas that you will need to be aware of.  I will touch on some of these in a bit.)

So, the magic line of code is:

 

 

Ok, I hear all you out there going "Ummm.... Neil that looks like 5 lines of code to me not one like you said."  Which would be a valid statement and it is true there is a couple more lines of code. 

Basically what I have done is put the print code in an If...End If statement which gives displays the printdialog to the user where they can choose their printer and print the document or cancel the print job all together.
 
All in all six lines of code to print out a single or multiple page document is nothing.

What is the code doing then?

As I mentioned earlier a new instance of a printdialog is created.  The printdialog is the window that is shown where you can select which printer you want to print with and other printing options.

The printdialog is shown as a dialog window and if the user clicks the "OK" button, the flowdocument is cast as a DocumentPaginator object which is used as the first parameter of the printdialog’s PrintDocument.  The second parameter of the printdocument is the name of the document being printed.  This name is what is displayed in the print queue of the printer so you can uniquely identify what documents are lined up to be printed.

The Else portion of the If...End If statement handles if the user clicks the "Cancel" button.  A simple message box is displayed letting the user know that the print job has been cancelled.

That in a nutshell is all that you need to do to print a flowdocument in a WPF application.

Now for the gotchas that caught me while I tried to print.

#1)  Multiple columns.  Let me tell you I this one really got me.  When I first tried to print the flowdocument in the image above, I expected the print out to look like the window.  Such was not the case.  What I ended up with was the entire table printed out on two columns per page over the three pages* the printed document covered.

 

 

This was not quite what I was expecting, but is apparently the default behaviour without having set any properties of the document to match the printer.  What I wanted was to have the table fill the entire width of the page.

(* Note - As a rather interesting side note here this is not what I got the first time I tried to print this flowdocument.  My first results were rather disappointing and I was very disillusioned with what I thought was going to be a much simplified printing process.  The image below is my first attempt at printing.

 

 

As you can see it ended up quite the mess.  What happened was that all three pages of the flowdocument got printed in two columns on one page.  (If you look real close at the left column you can see the header of the table in the background then the first 8 lines have been printed twice.) 

I can happily report that the fault with this lies with the printer and not how the WPF printdialog sent the document to the printer.  I have since tested several other printers and they all print as the multiple columns image.)

Getting back on track and printing the document on only one column.

The way to get around having multiple columns is to set the column width of the document to be printed prior to casting it as a documentpaginator object.  This is a simple process and requires only one line of code.

 

 

What this code does is sets the width of document in the scrollviewer to be the entire printable width of the page.  Now when the document is printed the table will span the width of the page.

#2) Page size.  While perhaps not quite as important as multiple columns is getting the proper page size and margins for your printed output.

You can set the bounds of your document to be printed by setting three properties of the document.  The three properties are the PrintableAreaHeight, PrintableAreaWidth and the Thickness. 

The PrintableAreaHeight and PrintableAreaWidth properties are pretty self explanatory.  The Thickness is what is used for the margin.  The thickness can be set with a universal value which will be applied to all sides, or you can set pass different parameters for the margin on each side.

 

 

While it is not essential to set these three properties for printing it does ensure that your document fits the page or pages.

Summary

So, with adding in the few lines of code from the two gotchas, I finally was able to print out the report and have it look as I wanted it to.

 

 

The entire print code I used was:

 

 

There you have it a quick overview of printing in a WPF application.  As I said it is much easier and I have my doubts if I will ever look at starting another WinForms application.

posted @ 1:05 AM | Feedback (2)

Wednesday, October 08, 2008 #

vbCity Leader (and Microsoft MVP) Ged Mead showed how to create a FlowDocument in his article published on devCity.com.

I got the challenge recently to display a data inserted in a table in a flowdocument.  So I embarked on my quest.

I knew that what I wanted could be done because some quick testing with XAML I was easily able to add a table to my flowdocument.

Which gives an output like the following.

My challenge, however, was that I needed to be able to do this with Visual Basic.NET code behind as the data that was to be displayed in the table was going to be read from a file.

I made my first mistake almost immediately.  (Now that is probably not the best thing for me to admit when I am trying to convince everyone that I actually know what I am talking about, but hey, I am big enough to admit my mistakes.)

The mistake I made was trying to use the wrong table.  I was able to create and insert the data from the file into the table I created with VB code, but when I tried to add the table to the flowdocument I couldn’t.  No matter what I tried, I was just unable to add the table and after a couple of days, I finally gave up and asked for help.  Microsoft MVP Jay Harlow quickly pointed me in the right direction.

What the problem was is that there are more than one table that is accessible for use in the .NET Framework.  I was trying to use the table in the System.Web Namespace, but in fact I needed to be using the table from the System.Windows.Documents Namespace.

Once I was referencing the correct table, the whole project came together quite nicely.

(While the project I was doing required reading data from a file that will be outside the scope of this blog post.  In this post I will just be showing how to hardcode data into a table in a flowdocument.)

The first thing that is needed is to Import the Namespace to give us access to use a table.

Next declare two form level variables.  One variable is declared as a flowdocument and the other is declared as a table.

In the event you want to create the table in, I used the Initialized event of the form for this example, set the two variables to a new instance of a flowdocument and table respectively.

Now that there is a flowdocument and a table the table needs colums, rows and content for the table.

The columns are the first things to be added to the table.  Columns are added to the collection, or array, of columns of the table.  For this example I am going to add four columns to the table.

With the columns added, Rows can now be added to the table.  Like columns, rows are also held in an array of rows.  Where rows differ from columns is rows are actually part of RowGroups.  You can have several rows in a rowgroup and more than one rowgroup in a table.

So to start a new rowgroup must be added to the rowgroups of the table.

and into that rowgroup a new row is added.

Although you still can’t see it if you were to look at the form itself, the table now has four columns and one row.  Into the row Cells need to be added.

At this point there is a great deal of possibilities to how what the table is going to look like.  While you can set some formatting for the table with changing the properties of the table and rows, you have much greater control over the look of the table by manipulating the properties of the cells.

For this table I want to have a header that stretches across the entire top of the table, so while I can have four cells in the row (I can do this because I added four columns to the table earlier) only one is going to be added to the row.  The cell will then be made to stretch over the entire width of the table.

There is quite a bit going on in the above line of code.  A new TableCell is added to the collection of cells of the row and to add content to the cell a new Paragraph is used as a parameter of the tablecell and a new Run of text is passed as a parameter of the paragraph.

After adding what is going to be the title of the table, some formatting can be assigned.

The first line of code above tells the cell to span the entire width of the four columns of the table.  (If you have worked with tables in Microsoft Word think of this process to be like merging cells in a table.)

The second line sets the size of the font to make the text stand out as a title and the third line centers the text in the cell.  (By default the text alignment of a table, row or cell is left.)

The fourth line of code makes the font bold.

The fifth line of code sets the colour of the text in the cell and the sixth line gives the cell a colour for the background.

If we add two more lines of code the table can be shown in the FlowDocumentReader.

The table is first added to the Blocks of the flowdocument that was declared at the beginning of our code then the flowdocument is assigned as the document of the FlowDocumentReader of the form.

(Note:  Interestingly enough it does not seem to matter where you place the code to add the table into the flowdocument and make the document of the reader to be your flowdocument.  The code can be added just after the declaration of the flowdocument and table or anywhere in the middle of the code that formats and populates the table.  Personally I put these two lines at the very end prior to displaying the flowdocument.)

Now when the project is run, you can see the table starting to take shape.

Putting Headers for each column are next to be added to the table.

A new row is added to the rowgroup of the table then four cells are added to the row with content also being added to each cell.

You can see by the Index number of the rows that the new cells have been added to the second row.  Like all .NET arrays the rows array of a rowgroup, as is the rowgroup itself, are zero based so if you need to remember that the actual row number is one higher than the index number.

Running the project shows that the columns now have headers.

The table is really starting to look like a table now.

A line under the column headers keeps the data in the columns separated from the headers.  To accomplish this, a new row is added under the row of headers.  One cell is added to the row and it will span the four columns like the title cell does.  To make the line, the border property of the cell is going to be used.  The top border of the cell will be made larger and given a colour.

To make the border thicker a New Thickness is applied to the cell.  Thickness can either be set by passing a single parameter to the new thickness, which would give the same thickness to all sides of the cell, or you can pass four parameters and assign separate thicknesses to each side.  While it does not make any difference to what I am demonstrating here, I have only assigned a thickness to the top border of the cell.  I could have just as easily assigned a uniform thickness to the cell.

Now the contents of the table will be separated from the column headers by a red line.

With the formatting of the table set out, it is time to add some content into the table itself.

For this example I am going to use a For…Next Loop to populate the table.

Two Integer variables are declared.  The first is used to keep track of the index of the row in the rowgroup.  The variable is declared with a value of 3 because the first line that will be added in the loop will be the fourth element of the array of rows.  The second variable is just used for adding content to each of the cells as they are added to the row.

In the loop the first line of code adds a new row to the table then the next four lines add the cells to the row and put some content in the cell.  In this example the content of the cells in the row will just have the text "Number: 0" to "Number: 97".

In the last line the value of the variable j is incremented by 1 so the content number of the next row will be one higher than the last.

Now when the project is run the table is complete.  The table starts with:

and six pages later going to:

posted @ 12:24 AM | Feedback (2)

Tuesday, October 07, 2008 #

Once again it seems that I had what I thought was a great idea only to find out that someone else had it before I did.

I don’t even know how I got to thinking about ToolTips and how boring they look, but I did and that got me to wondering what could be accomplished with Windows Presentation Foundation (WPF).

What I eventually ended up with was using a Border which I would create custom messages in and display when the mouse was hovered over the object that the ToolTip was for.

All in all I was fairly pleased with how it all looked and worked though it was kind of fiddly to implement.  I wasn’t really sure, however, how to incorporate this tooltip idea into an application I did want to use it. 

That was, however, before I found out about the versatility of a WPF tooltip.

In WPF, the tooltip is actually just a container like a panel or grid and pretty much anything that you can put into a container you can now use in a tooltip.  This expanded capability leads to endless possibilities for how a tooltip looks and how the user can now interact with it.

We all know how boring tooltips look in a WinForms application.

With just a few lines of code, this plain tooltip can be transformed into something a little more visually exciting.

The tooltip in the next image was formatted with just six lines of code.

The code for this was pretty straight forward.

A gradient was applied to the background of the tooltip.  Creating a gradient colour is the same process as creating a gradient for anything in a WPF application.  You can have as few as two colours up to a virtually endless number of colours.  A gradient is also applied to the border of the tooltip as well.

The thickness of the border was increased so the colouring is more noticeable.

The content is filled with what we wanted to have the tooltip say and added a drop shadow effect to give the tooltip a little bit of a 3D effect.

The last property that is set is the Placement property.  The placement property allows you to set where the tooltip is displayed in relation to the control that it is for.  Some of the positions that you can place the tooltip are Top, Left, Right and Bottom.  You can also set an Absolute or Relative position for the tooltip.
The last thing to do is set the tooltip that has just been defined as the tooltip of the control it is to be displayed for.

In addition to being able to customize the tooptip itself I mentioned earlier that you can place WPF content into the tooltip itself.  One drawback to putting WPF content into a tooptip you do still will see the thin border of the tooltip behind the WPF content.  I’m sure that there must be a way to get rid of the border, and with Vista it is not as noticeable, I just have not found the way to do it yet.

So with this in mind we will forge ahead with making an even more visual tooltip.

The first component required for creating a tooltip for WPF content would be some sort of container.  In this example I am going to start with a StackPanel.

In the stackpanel there is going to be some text and an image so the code is going to start with declarations for the three objects.

Add some formatting to the stackpanel.  In this case there are only two changes which are going to be applied to the stackpanel.  A LinearGradientBrush is going to be applied to the background and the Orientation of the stackpanel is also set.

For the Image there are just three properties that are going to be set.  The source, height and width of the image are defined.

For the textblock the content is set as well as some text formatting and the text is also centered in the textblock.

All that is left now is to add the image and textblock to the stackpanel then apply the stackpanel to be the tooltip of the textbox on the Form.

All this work now gives a much more fancy tooltip, looking like the following image.

So you can see that the boring old tooltip is now a thing of the past.

This post has only scratched the surface of what can be done with a tooltip in a WPF application.  I plan on investigating this tool much more to see just what can be done with it.

You will need to keep in mind that you can’t put content into the tooltip that can have user interaction because the tooltip can’t get focus.  If you put something like a button in a tooltip, which you can do with WPF, the click would just go through the button and click onto the control on the form.

posted @ 11:39 PM | Feedback (0)

Sunday, August 17, 2008 #

Once again it seems that a post from vbCity is to be fodder for a post here.

Although not part of the original query by vbcity member quicksun, the question of getting a Windows Presentation Foundation (WPF) Form to be resized as the expander control was either expanded or collapsed came up.

I went with what I thought was the quickest way about resizing the Form and that was to use the Collapse and Expand events of the expander control to reset the height of the WPF Form to its desired size.

Private Sub Expander1_Collapsed(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Expander1.Collapsed
Win1.Height -= 40  ' Set the Height back to original size.
End Sub

Private
Sub Expander1_Expanded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Expander1.Expanded
Win1.Height += 40  ' Set the Height to new size.
End Sub

As simple an approach as the above code is there is an easier way to resize the Form thanks to the increased control programmers have been given over forms and controls with WPF.

With a WPF Form there is a property named SizeToContent.  By utilizing this property you can make the Form resize itself depending on, as the name implies, the content of the Form.

There are four setting for the SizeToContent property.

Manual
If you have SizeToContent set to Manual then the size of the WPF Form will not change from what is initially declared as the size of the Form either in the XAML or code behind of the Form.

Height
Setting the SizeToContent property to Height would mean that only the height of the Form will automatically change should the height of the Forms content become greater than the height of the Form.

Width
Similar to the Height setting, by setting the SizeToContent property to Width would mean that a WPF Form would automatically change widths should the Forms content become greater than the width of the Form.

WidthAndHeight
As you can probably guess by the name of the setting, WidthAndHeight would mean that the WPF Form can change size in both width and height should the Forms content be greater than the current size of the Form.

If you do use the SizeToContent setting you must remember that you can not specify a height, width or both depending on which setting you have.  If you want to give your WPF Form the ability to change in a direction then you must not declare a size for that property. 

For example if you want the WPF Form to be able to grow taller (height) then you would change the SizeToContent property to Height and not declare any value for the height of the WPF Form either in the XAML or property window.

All in all I think this is a nice little addition to what we can do with Forms. 

posted @ 1:17 AM | Feedback (2)

Wednesday, July 16, 2008 #

I mentioned in an earlier post that for a control in a Windows Presentation Foundation (WPF) application that you had to give each control that you wanted to write code behind for a name in the XAML of the form.

Strictly this is not true.  If you want don’t want to use the built in features of the Visual Studio’s IDE for selecting classes and methods on the code behind page you could type in the code on the code behind yourself.

For me, at least, the easiest way to reach the code behind is to give each control a name in the XAML markup

then from the code behind page, you can select the control from the dropdown list.

After you select the control, you have access to all the events associated with the particular control.

By selecting a method from the list Visual Studio automatically generates the method declaration for you.

Once the declaration is made you can happily enter the necessary code you want for that event.

If you don’t want to take advantage of this great feature of Visual Studio, then you can write methods for controls the slightly more difficult way.

Instead of giving your control a name in the XAML of the form, have toadd an attributes for the control in the XAML.

The attribute needs to include are the action of the control you want to code against and the name of the method that you will write on the code behind.

Once you have added this to the XAML, go to the code behind and declare the method adding the two required parameters of Object and RoutedEventArgs.

Then you can add the required code for that method just as you would if you had Visual Studio declare the method for you.

So there you have it.  Two ways to reach the code behind with a Windows Presentation Foundation (WPF) application.

posted @ 2:58 PM | Feedback (0)

I don't think I will ever get over just how much easier it is to do some things in a Windows Presentation Foundation (WPF) application than it is in a Windows application.

I was messing around with changing the background colour of a button to see what could be done.  I ended up looking at how to apply a gradient to be the background of a button and realized that doing gradients with Visual Basic was just about as easy, if not easier, than creating them by modifying XAML markup.  (You could also easily create gradients for the background properties of controls in a couple of mouse clicks by using Expression Blend.)

I started out with a plain button on my Form.

Like all experiments of mine I started off with the basics.  I wanted to have a button with a two colour gradient background so I declared a variable as a LinearGradientBrush.  (Note - Now before I hear back from people saying: "You could have declared and set your variable on one line…" or "You could have just set the Background property…." ... I know.  Due to limitations with taking the screen shots (the screen resolution didn't allow me to get the whole line of code without scrolling or having the code on multiple lines) I wanted everything to be as easy to read as possible.)

The next thing I did was declare the variable as a New LinearGradientBrush and set the parameters which were the starting colour, the finishing colour and the angle that I wanted to gradient to be displayed at.  A 0 degree angle shows the gradient from left to right and a 90 degree angle shows the gradients from top to bottom.  You can also declare any degree from 0 to 360. (I thought that being able to change the angle of the gradient this easily was a wonderful feature.)

Then all that was left was to apply the brush to the background property of the button.

Run the project and I had the desired effect of a button with a two colour gradient background.

Now my creative juices started flowing and I got to wondering about having more than two colours in the gradient.

(Note - I have apologized in the past for my rather horrible colour matching abilities and I will do so again now and warn those who have not witnessed my graphical abilities to be prepared.)

Having more than two colours for a gradient background is just as easy as a two colour gradient.  One of the overloaded constructors of the LinearGradientBrush is to pass an array of gradient stops as one of the parameters.

To create the array of gradient stops, you start be declaring and defining variables as New GradientStops.  The overloaded constructor for a gradient stop requires that you pass a colour and an offset.  (The offset is where the colour is at its full colour in the gradient.  The first colour starts at 0 and the last colour ends at 1).

For my button I decided to try three colours and have the colours starting with red on the left then becoming green in the middle and then changing to from green to blue on the right side.

Next I needed to declare an array to hold the gradient stops in.  The type of array that is used for this is a GradientStopCollection and you add the gradient stops to the array by using the Add method.

With all the gradient stops in the array/collection, you then set the background of the button as a New LinearGradientBrush and pass the array and an angle for the gradient as parameter to the overloaded new constructor for the brush.

Now when the project is run, the three colours are displayed on the button.

I mentioned the angle parameter of the constructor for the LinearGradientBrush earlier and changing it can lead to some very different looks.

Using the same code for the three colour button, but changing the angle of the gradient to 45 degrees

the colour change goes from the top left corner of the button to the bottom right.

One thing I did notice once I started changing the angle of the gradient I did find that if I wanted the gradient to show evenly I would also have to also change the offset property of the first and middle colours to even out the effect.

By changing the offset of the red, there is a little more solid red on before the colour starts mixing with the green.  The offset of the green is moved over by .2 as well to keep the green close to the middle of the button.

By using the GradientStopCollection adding more colours is a breeze.  You just need to create another gradient stop and then add that to the collection.

As you can see doing gradient colours is now a simple process with Windows Presentation Foundation (WPF) and Visual Basic.NET 2008.

posted @ 2:48 PM | Feedback (2)

Friday, July 11, 2008 #

I have uploaded the project showing how to do all the Tab content which I posted in this post.

The project can be downloaded from here.

posted @ 12:36 AM | Feedback (0)

Thursday, July 10, 2008 #

When I last visited the TabControl project, I changed it so that the look of the Tab content was done via VB.  One thing that has been niggling at me since was how the first Tab content was done.

The content on the Tab was still entered on the XAML code and the spans were defined there as well so the look could was not really created purely with VB.  Since I was after creating the look with VB, the first Tab also be included with this rather than a mixture of XAML and VB.

I did find that getting the same visual look took a lot more lines of code but, if you were to use the same process on a TextBlock, adding more text in various styles during run time could be done.

The beginning XAML for the Tab is now very basic with just a Grid on it.

On the code behind starts with declaring variables for both a TextBlock and a Span.

The textblock is going to be placed inside the grid on the tab and the span is going to end up being the content of the textblock.

Using a span for this is really great.  A span is used for grouping a set of different inline content together.  Thus allowing several different look to be incorporated in the same span and the really great thing about spans is that they are not inherited so each inline element you add to a span can have its own totally separate look.  You don’t need to get rid of the formatting of the previous element before applying a new formatting.

The first line I add to the span is going to be in plain text.  The text is added by passing the text I want as a Parameter of the Run Class.  The run class is an inline content element that may contain either formatter or unformatted text.  So basically it is a container for the text I want to add to the span.

The run is passed into the Add method of the Inlines property.  The inlines property is actually a collection of inline elements which make up the span.

From this plain text beginning it is just a matter of declaring a new span for the style that is wanted to be added next, defining the style and adding that span to the inlines collection of the root span.

One the span is formatted as is wanted, the textblock is added to the grid on the tab and the Span is applied to the inlines property of the textblock.

Initially I thought that the property of the textblock to apply the span to would have been the text property, but after a little digging I found that because a span is an inline property, it needed to be included in the inline collection of the control.

Running the App shows that all the formatting that is set with the code behind is working perfectly.

Thus giving a more pure VB setup of the tab contents.

posted @ 4:25 PM | Feedback (1)

Sunday, July 06, 2008 #

I have uploaded the project for the Gadget Style Window with one minor change.  Beethoven is out and a small midi file has replaced it. 

I know that some of you are probably saddened as I am by Beethoven's departure, but I didn't want to subject everyone to a 30Mb+ download.

The project can be downloaded from here.

posted @ 11:45 PM | Feedback (0)

Saturday, July 05, 2008 #

I have made the project that goes with the post for the TabControl with WPF available for download.

The project can be downloaded from here.

Again I must apologise for the file size.  Like the project for the Visual Basic.NET version of the TabControl it is a little bloated due to the video file.

posted @ 11:56 PM | Feedback (0)

Sometimes it just takes me a while, but I finally got to the point where I figured I should also be including the Visual Basic projects to go along with the posts and the videos.

You can download the project that goes along with the TabControl with WPF and Visual Basic.NET 2008 post.

The project can be downloaded from here.

My apologies for the size of the file.  It is a little bloated because of having the video file.

posted @ 4:44 PM | Feedback (0)

A while back I posted up about showing more interesting content on that tab of a tab control using Windows Presentation Foundation (WPF).

In the example that I posted, I created the custom look of the tab control just using XAML and I thought that it would be good to also show how to do the same thing using Visual Basic.

To do this I decided to cut back to the basics for the content of the tabs and I started with a tab control with four tabs.  The first tab had a textblock with some text as well as a couple style blocks in it.  The second tab starts with a stack panel.  The third and fourth tabs have grids on them.

The XAML for my base project is.

<Window x:Class="Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="Window1"
    Title="Window1" Height="437" Width="532" WindowStartupLocation="CenterScreen">
<Grid x:Name="Form1">
<TabControl>
<TabItem x:Name="Tab1">
<TabItem.Header>
<TextBlock x:Name="Tab1TextBlock">
<Span x:Name="Tab1TbSpan1">Words</Span> <Span x:Name="Tab1TbSpan2">in</Span>
<Span x:Name="Tab1TbSpan3">Italics</Span>
</TextBlock>
</
TabItem.Header>
</TabItem>
<
TabItem x:Name="Tab2">
<TabItem.Header>
<StackPanel x:Name="Stack" Orientation="Horizontal">
</
StackPanel>
</TabItem.Header>
</TabItem>
<
TabItem x:Name="Tab3">
<TabItem.Header>
<Grid x:Name="Grid1">
</
Grid>
</TabItem.Header>
</TabItem>
<
TabItem>
<TabItem.Header>
<Grid x:Name="Grid2">
</
Grid>
</TabItem.Header>
</TabItem>
</TabControl>
</Grid>
</Window>

The window does not look too interesting yet,

but we will make it look better soon.

Tab 1

Within the XAML of the text block that is in the first tab, I have added in where I want the different styles to be.  I have giving the each span block a name so that it can be referenced by the code behind.

There are different ways to go about this depending on what you want to do.  As you will see I have created one style with several different properties, since I am only going to be setting one property per span block I have only created one new style, or you can create a new style for each span block if you are going to have different styles for overlapping properties.

I started off by declaring a variable as a New Span, then I set the properties for the variable that I wanted.

Dim s As New Span

s.Foreground = Brushes.Blue
s.FontWeight = FontWeights.Bold
s.FontStyle = FontStyles.Italic

Now that I have the properties set, I just need to assign them to the various spans that I have on my tab.

Tab1TbSpan1.Foreground = s.Foreground
Tab1TbSpan2.FontWeight = s.FontWeight
Tab1TbSpan3.FontStyle = s.FontStyle

Tab one now has something more elaborate on it.

Admittedly, I could have just used Brushes.Blue to set the Foreground of the first span, but by creating and using a new span I can now re-use this over and over in my code if I wanted to and if I wanted to change the colour, then I would only have to change one line of code rather than possibly having to several to change.

Tab 2

Tab 2 starts out with a stack panel on it with the orientation of the stack panel set to horizontal.I could have set the orientation of the stack panel with VB code if I wanted by using:

With Stack
.Orientation = Orientation.Horizontal
End With

if I wanted.

In the stack panel I am going to place a text block, a rectangle and a circle.

To add the text block, I need to start out with declaring a new text block then set the Text property.  With that done the last line of code adds the text block to the stack panel.

With tb As New TextBlock

tb.Text = "Circles and Rectangles"

Stack.Children.Add(tb)

I now have a caption on the second tab.

Next I want to have a circle showing on the tab, so I declare a variable to hold a new ellipse and then set the Height, Width, and Fill.  I also set the Margin for the ellipse to a new thickness and pass the numeric representations of left, top, right and bottom to position the ellipse on the tab.  Once I have the properties I want set, I add the ellipse to the stack panel.

Dim c As New Ellipse

c.Height = 20
c.Width = 20
c.Fill = Brushes.Blue
c.Margin = New Thickness(10, 0, 0, 0)

Stack.Children.Add(c)

Tab 2 now has a caption and a circle on it.

The last item I wanted on the tab was a rectangle, so I did much the same for this as for adding the ellipse.  I declared a variable to hold a new rectangle then set the Height, Width and Fill.  Again I set the margin property to a new thickness to position the rectangle on the tab.  Then I added the rectangle to the stack panel.

Dim r As New Rectangle

r.Height = 15
r.Width = 25
r.Fill = Brushes.Red
r.Margin = New Thickness(10, 0, 0, 0)

Stack.Children.Add(r)

I now have my desired look for the second tab.

Tab 3

Tab 3 will hold an image.

Once again I start off by declaring a variable which will hold a new image, then set the Width and Source properties.The source property is declared as a New BitmapImage and the path of the image file, as well as what kind of Uri the path is, are passed as parameters of the Uri of the file.  The image control is then added to the grid on the tab.

Dim v As New Image

v.Width = 80
v.Source = New BitmapImage(New Uri("Lizard004_RJ.JPG", UriKind.Relative))

Grid1.Children.Add(v)

The third tab now displays an image.

Tab 4

The last tab on my tab control is going to display a video.

I start out by declaring a variable to hold a new instance of a media element, then set the Width and Source properties of the element before adding the control to the grid on the fourth tab.

Dim m As New MediaElement

m.Width = 80
m.Source = New Uri("butterfly.wmv", UriKind.Relative)

Grid2.Children.Add(m)

The tab now displays the video and completes the effect I was after.

So you can see that it can be just as easy to do in Visual Basic what you can with XAML.

posted @ 2:44 AM | Feedback (1)