Latest Posts
One of the great things about WPF is its ability to let you use animation to enhance your user interface. (Or wreck it if you go too far!) In my opinion, subtle animations can go a long way towards improving the user experience.
One particular way is to fade colors in and out so that text seems to appear and disappear in a way that gives the impression of movement, but without any jarring visual effects.
Doing this in the XAML markup is well documented and you will find many examples around the place. However, I recently had a situation where I wanted to create this animation in the VB code behind. Now, I knew that anything that could be done in XAML can be done in VB, but when it came down to the task it actually caused me more problems than I'd expected. And when I started to search for answers, it took a while.
It turned out that the reason for my difficulty was a fundamental misunderstanding on my part. I was thinking "color" as being the element to change or animate; in reality it doesn't work quite like that. But after a good deal of trial and error, I eventually hit on the answer.
In this case I wanted to fade the text on a button from its original black to white. But because I would use this effect in a number of situations, including some where there was no user driven event to fire it, I decided that putting the animation instructions in the code behind was the way to go.
I'll start with the XAML though, as I think that in most cases this will be your preferred route. I'll cover the VB approach at the end.
here's the XAML:
<Button Margin="30,67,0,111" Name="Button1" Foreground="Black" HorizontalAlignment="Left">Animated Button</Button>
<Button HorizontalAlignment="Right" Margin="0,77,96,111" Name="Button2" Click="Button2_Click" Content="Animated Button" >
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard>
<Storyboard TargetProperty="Foreground.Color">
<ColorAnimation To="White" Duration="0:0:2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Button.Triggers>
</Button>
Most of it is pretty straightforward:
1. Having first created the button and set its main visual properties, we create a Triggers block for the Button.
2. Next we identify the trigger to be used to fire this animation. In this case it is the Button's Click event.
3. The Storyboard is then created and we identify the Target Property which is the Foreground Color of the button.
4. Finally, the animation details which comprise the starting color, the ending color and the duration in seconds.
The remainder of that code snippet are closing tags.
Now it's the fact that the TargetProperty is identified as the Foreground.Color that threw me off the track when I came to create a VB version of this task. I was trying to find a way of assigning the animation directly to the Foreground Color of the button (or the Button.Content Color or various other permutations - none of which worked).
The reason is that you have to set the animation on a Brush, and not directly to the Foreground property. You then assign this brush as the one to be used for the Foreground. And finally, when you run the animation to change the color of the brush, the animation is then seen to be applied to the Foreground. I hope that makes sense!
Here's the VB code that does this:
' Create color animation sequence.
Dim blackToWhite As ColorAnimation = New ColorAnimation(Colors.White, New Duration(New TimeSpan(0, 0, 2)))
'Create a new brush and apply the color animation to the brush
Dim scb As SolidColorBrush = New SolidColorBrush(Colors.Black)
scb.BeginAnimation(SolidColorBrush.ColorProperty, blackToWhite)
'Assign the brush to Button's Foreground
Button1.Foreground = scb
Like all these little glitches and gotchas, you wonder how it seemed so difficult once you've seen the answer. But as we all know, it's really easy to set yourself off on the wrong mindset and find yourself needlessly chasing your tail trying to get the exact syntax for what you're trying to achieve. Hopefully if you need to run this kind of animation in code, you'll now be saved a bit of potential frustration.
Open Source Web Design is a collection of web designs submitted by the community that anyone can download free of charge!
Check it out at: Open Source Web Design
Mike McIntyre
www.getdotnetcode.com
ClickOnce Deployment
A recent post on vbCity regarding deploying an application with ClickOnce got me wondering about doing deployment with ClickOnce.
I have always done deployment of applications by creating and using a Setup and Deployment package which created a .msi installer file, so it was interesting to see some of the differences between the two distribution methods.
First off I created a simple application to test the ClickOnce distribution and installation method with. What I created was nothing special, just a windows form with at button that, when it is clicked, a message box is shown.


As you can see the application is nothing special. One other thing that I did was add a version number to the text of the form. I did this to show how ClickOnce deployment installs newer versions as they are available. I will get to this a little later.
Once your application is ready to go you want to open up the My Project page from the solution explorer.

On the My Project page click the Publish tab.

From this page, you define where your application is going to be available from and how it is going to be installed on the client machine.

Taking a look at the publish page from the top down the first thing you will want to enter will be the location (URL) that you are going to publish to.

As you can see from the image above, you have three options for the location that you are going to publish to. You can publish to a web site (http://www.somesite.com) but to do this you must have FrontPage extensions enabled on the web site. You can publish to a ftp server (ftp://www.somesite.com) as long as you have ftp permissions for the site, or you can publish to a local file (C:\myApplication). (For distribution this last option is not really that realistic unless you are on an internal network where you can share out the directory to others on the network.)
The next option you have is to determine if you application is available offline or not.

If you don’t want the users to be able to access your application offline then select the online option. This will cause your application to run, but not show in the start menu of the user’s computer. They would need to download the application each time they wanted to use your application.
If you make the application available offline then a shortcut is included in the start menu of the computer making the application accessible all the time.
To the right of the Install settings there is a group of four buttons.

These buttons define what files are to be included with your application, any prerequisites that the end user must have installed on their computer to run your application, how and when to get updates as well as options such as adding the publishers name, product name etc.
Under the install mode and the buttons there is the version boxes plus the option to automatically increment the revision with each publish.

Keeping the increment box checked is, I believe, quite important. If you don’t remember to increment the version number when you republish the application then the next time the application checks for updates it looks at the version number and if that number has not changed, even though your application may have, it assumes that there is nothing newer and opens the currently installed version.
The last two items on the window are the Publish Wizard and Publish Now buttons.

The Publish Wizard button will open a series of dialogues and walk you through the settings that you want your installer to use.
The Publish Now button will use the information that you have entered on the page and create the installer files then, if you are deploying the files to either a web site or ftp site, prompt you for log on details.

Simply insert your username and password then click the OK button and the files required will be uploaded to the URL you specified.

You can see in the image above that ClickOnce has created two files and one directory on the web server. Within the Application Files directory you would find one directory containing each version that has been published and uploaded.

I just happen to have two versions in the application files directory and the one that will get distributed will always be the latest version. (I mentioned earlier that I had put a version number on the text of the form and the version number you should see is 2 not 1 like the image of the form above.) It would not matter how many older versions I have on my server.
Now you may distribute the address of your application to your clients. The file that you want to point to is the Application Manifest file, not the setup file. From the image above I would point people to the URL http://www.neilknobbe.com/clickonce/ClickOnce.application. (The link is live and you can navigate to it, download and install the application that I mentioned at the start of this post. It is not very exciting, but it shows how ClickOnce works.)
The prerequisites for installation, which you would have set earlier, are checked.

If all is ok, the user will be prompted to install the application.

Once installed your ClickOnce deployed application is ready to use.
Relaxed delegate conversion, introduced in Visual Basic 2008, enables you to assign subs and functions to delegates or handlers even when the signatures are not identical. Therefore, binding to delegates becomes consistent with the binding already allowed in method invocations.
In Visual Basic prior to 2008:
Sub OnClick(ByVal sender As Object, ByVal e As EventArgs) Handles RunButton.Click
MessageBox.Show("Visual Basic prior to VB 2008")
End Sub
In Visual Basic 2008 (VB9)
Sub OnClick() Handles RunButton.Click
MessageBox.Show("Look Mom, no parameters!")
End Sub
Details: Relaxed Delegate Conversion
Mike McIntyre
www.getdotnetcode.com
Visual Web Gui is an open source product for porting .NET Windows Forms applications to the web.
It is used to create ASP.NET web applications with a very AJAX like experience - without the AJAX programming hassle.
It may be worth it to you to give it a try. Though it's little rough around the edges at this point, this product can be used today to produce web applications from .NET Windows Forms projects. And - the developer is rapidly improving the product each month.
It's easy to get started and it to produce useful web applications. I've been playing around with it for about a week and have already created two small web applications for IT management.
The process is straight-forward:
1. Download and install the free Visual Web Gui Visual Studio project templates.
2. Create a Visual Web Gui project. This is a Visual Studio Windows Forms project.
3. Build out the Windows Froms application.
4. Compile.
5. Run result in web browser.
6. Deploy to web server.
Visual Web Gui web site: http://www.visualwebgui.com/
Visual Web Gui at CodePlex: http://www.codeplex.com/VWGSilverlight
Mike McIntyre
www.getdotnetcode.com
Ok, let’s call this page 22,492 in the book of things I did not know about Visual Studio 2005.
I was reading something the other day, if I can remember or find it I will post up a link, and was surprised that I had missed this little bit before.
(I have recently been reading “WPF for those who know Windows Forms” that can be found here and watching webcasts by William Steele on his WPF Soup To Nuts series so it could have could have come from one of those.)
What was mentioned was having both text and an image on a button. I knew it was possible, but I didn’t know just how easy it was to do.
By default when you add an image to the button the text of the button is overlays the image.

There is a property of a button which helps us set the relation of the text to the image. This name of this property is TextImageRelation.

The TextImageRelation property has five options:
- Overlay
- Image over text
- Text over image
- Image before text
- Text before image

The options are pretty much self explanatory. Below are screen shots showing the different positions.
Image over text:

Text over image:

Image before text:

and lastly
Text before image:

So firing up Expression Blend and getting into the whole WPF thing is always a refreshing change, especially getting away from mundane coding and alike. However, the first thing to trip me up and my colleague up was using the "Edit Externally" command from the project view to edit an existing '.png' file and whipping into my favourite graphics editor. Imagine my surprise when I was greeted with MSPaint! How there are two things to consider here...
- I used to be a design guy prior to becoming a programmer, so MSPaint is the last thing I need to see.
- Two - MSPaint is in no way anything like a sophisticated design application. Just get used to it ;-)
Now the doomsayers and conspiracy freaks might consider that MS has done this on purpose, so I fired up Reflector to work out how the project items (such as image files) were actually being catagorised and executed. What Blend does is by using the old .NET standby of Process.Start but explicitly passing through the 'Edit' string as the 'Verb' when making the call. In short, they're letting explorer handle the file association. Note: this works differently from explorer where if you double-click an existing and recognised dot extension it fires up the application with the selected file because its using the 'Open' verb and not the 'Edit' verb.
Ideally, Blend should use the 'Open' verb rather than hardcoding the 'Edit' verb (well, selection that is then implemented in the EditExternalCommand object) into the 'DocumentType.PreferredExternalEditCommand' property. Or even better - allow the user to specify those application they want for editing resources. But hey, its version 1.
So to get around this, a quick registry tweak will get things working. Navigate to the key...
HKEY_CLASSES_ROOT\SystemFileAssociations\image\shell\edit\command
...and change the value of the '(Default)' value to your favourite package from...
"%systemroot%\system32\mspaint.exe" "%1"
...to , so in my case to Fireworks...
"C:\Program Files\Macromedia\Fireworks 8\Fireworks.exe" "%1"
...and job done + no need restart...
HTH - And remember this fix / hack comes without warranty and will effect other instances where applications use this key as well. In short, be careful and backup your registry before doing this.
The companion video to my post on the expander control in WPF is now available for download.
The video can be found here.
I was taking another look at the WPF expander control that I talked about here and discovered that you don't actually need to use any code to get rid of the background colour of the control when collapsed.
What I discovered is that if you set the VerticalAlignment of the expander control. You can set this property to Bottom, Center, Stretch and Top. All but Stretch will hide the background colour of the control when the control is collapsed.
Here is the revised XAML markup for the control:

A couple of days later than I had planned, but I finished the video that is the companion of this post about custom content in the tabs of a tab control in WPF.
You can download the video here.
After posting up about this feature of Visual Studio I got to messing around with it a bit. (Sara Ford's post got me excited about this topic)
I got to thinking that although it was a great idea to be about to store code snippets in the toolbox, I did get to thinking that it could get confusing having all sorts of code for different things in one tab and be able to separate the code in organized groups would be handy. Well guess what. It can be done.
If you right click on the General tab of the toolbox you can select to add a tab.

A new tab is created and all you need to do is type in the name that you want your tab to have.

Now you can organize your code, and control, snippets so they are easy to find.

There are a lot of neat options now available to us programmers thanks to WPF.
One of these is the expander. The expander is a control pretty much like a groupbox which can hold various controls. The main difference between a groupbox and an expander is the controls in a groupbox are always visible where the expander gives the developer, and by extension the user, the ability to hide any controls and conserve valuable space on a windows form.
As you can see in the image below, the groupbox and expander both contain two radio buttons.

The advantage of the expander, as I see it, is when I click the little arrow next to the caption of the expander. Once clicked the expander collapses to the height of its header hiding the controls, in this example the radio buttons, from view.

I will admit that I had to do a little tinkering with the expander to get it looking and working like I wanted it.
I dragged and expander from the toolbox onto my window, sized it and set the background colour, then added a stack panel, and within the stack panel, the two radio buttons.

This, unfortunately, was not quite what I wanted because the whole background of the expander was light blue and I only wanted the header to be blue with a small border around the controls.
To solve this I had to put a border on the expander before putting the stack panel and the radio buttons. Setting the background colour of the border to white and adding a margin and padding for the border completed the look I was attempting.

Well it had the look as long as the expander was expanded. Once I clicked the button to collapse the expander I was left with a blue square.

No radio buttons but not perfect either.
To get the desired effect of a growing and shrinking panel I used the Expanded and Collapsed methods of the expander to set the height when expanded and collapsed.

Now I have the effect I was after.

Here is the XAML for the expander with the frame, stack panel and two radio buttons.

Sara Ford blogged about this a couple of days ago and I thought it was a really cool feature of Visual Studio.
She pointed out, what could be, a little known feature of Visual Studio.
You can highlight and then drag code snippets into the General tab of the toolbox.

You will then fine the code as an item in the toolbox.

If you want to see exactly what the code is all you need to do is hover your mouse over the item and the code will be displayed.

I think that this is one of the cooler features of Visual Studio and a great and easy way to keep code snippets.
After having looked at how to change the background colour of the tab header I got to wondering what else can be done to the tabs using WPF.In a very short time my question changed from “What can be done?” to “What can’t be done?”
As was shown here by MVP Ged Mead you can easily set the background colour of the tabs on a tab control, and a solution to the setting the background of the header here. Those posts got me wondering just what else could be done with the tabs on a tab control.
With very little time and effort I ended up with a tab control that looked like the following.

As you can see the captions on the tabs are quite varied and although you can’t tell from the image the last tab is very different. The first tab has text with mixed styles, the second tab has a rectangle included with the text and it looks like I have images on the last two tabs, but in fact the last tab has a video playing on it. Yes, I did say video. Complete with sound.

Believe it or not his whole tab control was created with just 33 lines of XAML markup.

So leveraging the power of WPF we can easily create much more visually stimulating tab controls than you could with previous versions of Visual Studio.
I’ll create a companion video for this and post it up in a couple of days which will also show the video on the fourth tab playing.
I found this great POST by the SharePoint Designer team for “Using Javascript to Manipulate a List Form Field”. Unfortunately it didn't work very well for People Picker fields which is exactly what I needed to do today.
After some trial and error, and a bit of head scratching I finally came up with the follow which I thought I'd share, since when I was searching for a solution I found a lot of people in a similar situation with no solution posted.
<script type="text/javascript">_spBodyOnLoadFunctionNames.push(
"fillDefaultValues");
function fillDefaultValues()
{
fillPeoplePickerWithCurrentUser('Submitted_x0020_By');
}
function fillPeoplePickerWithCurrentUser(pickerName)
{
//get the current user from the welcome menu
var currentUser = getCurrentUser();
//check to see that we've got it
if(currentUser !=
null)
{
//get the people pickers input div
var pp = getPickerInputElement(pickerName);
//set it to the current user if we've found it
if(pp !=
null)
pp.innerHTML = currentUser;
} }
function getCurrentUser()
{
var tags = document.getElementsByTagName('a');
for (
var i=0; i < tags.length; i++)
{
if(tags[i].innerText.substr(0,7) ==
'Welcome')
{
return tags[i].innerText.substr(8,tags[i].innerText.length);
} } }
function getPickerInputElement(fieldsInternalName)
{
var result =
"";
var divs = document.getElementsByTagName(
"DIV");
for(
var i=0; i < divs.length ; i++)
{
if(divs[i].id==
"WebPartWPQ2")
{
var tds = divs[i].getElementsByTagName(
"TD");
for(
var j=0; j < tds.length; j++)
{
var cellHTML = tds[j].innerHTML;
if(cellHTML.indexOf(
'FieldInternalName="' + fieldsInternalName +
'"') >= 0)
{
var innerDivs = tds[j].getElementsByTagName(
"DIV");
for(
var k=0; k < innerDivs .length; k++)
{
if(innerDivs[k].id.indexOf(
"UserField_upLevelDiv") > 0)
{
result = innerDivs[k];
break;
}
} }
}
}
}
return result;
}
</script>
. . .
Introduction
Printing can often be a bit of a tricky task in .NET. Some things are more easily resolved than others though.
I saw a post recently that raised a problem that seems to occur fairly regularly: You want to print a large chunk of text to the printer, but VB seems to want to print everything all on one long line - even when this means that a lot of the text will be truncated or "printed" invisibly into thin air!
Fortunately, this is one of the cases where the solution is relatively easy. Essentially, what you do is set a rectangle whose width represents the width of your printed page (or any lesser width you prefer). You then pass this rectangle to the DrawString method and it will obediently print within those boundaries.
Solution
Here's the basic solution:
Imports System.Drawing.Printing
Public Class frmPrint
' The document you will use to print on
Dim DocPrint As PrintDocument
' Set font for printing
Dim fnt As Font = New Font("Verdana", 12, FontStyle.Regular)
' The printing is fired with a button click event
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
' Print the textbox content
DocPrint = New PrintDocument
' A handler for it
AddHandler DocPrint.PrintPage, AddressOf PrintTheTextBox1
' Print the document
DocPrint.Print()
End Sub
' The procedure that does the printing
Private Sub PrintTheTextBox1(ByVal sender As Object, ByVal e As PrintPageEventArgs)
'Set a rectangle to bound the printing
Dim PrintRect As New RectangleF
PrintRect.Width = 800
PrintRect.Height = 1000
' Print the text from the TextBox:
e.Graphics.DrawString(TextBox1.Text, fnt, Brushes.Black, PrintRect)
End Sub
Yes, But.....
That's OK as far as it goes, but it does suffer from one flaw. When you check your printed page you'll find that the text is stuffed right up at the top left of the paper and each line extends fully across to the very last few millimetres at the right hand side. Now, it may be that paper saving is high on your agenda, in which case you'll be happy. But generally you will probably want a layout that's a bit more generous with its whitespace.
The trouble is that there isn't an overload that allows you to pass in the Rectangle and the start position for the printing. Is that going to stump us? Nah, of course not!
If we go back to the Rectangle itself, there is a constructor overload that allows you to pass in the x and y values as well as the width and height. The x and y values will of course be used as the left and top points respectively of the rectangle as it is positioned on the printed page. So this variation will get the start position, the text line width and text block height all sorted:
Private Sub PrintTheTextBox2(ByVal sender As Object, ByVal e As PrintPageEventArgs)
'Set a rectangle to bound the printing
Dim PrintRect As New RectangleF(30, 100, 750, 1000)
' Assign its Left, Top, Width and Height values
' Print the text from the TextBox:
e.Graphics.DrawString(TextBox1.Text, fnt, Brushes.Black, PrintRect)
End Sub
While I was working on that, I remembered that the Rectangle has a useful little method named Offset (something you would normally use when drawing actual rectangles in a graphics based task). However, by using this method and adjusting the values that are passed so that the top left of the rectangle is shunted down and to the right, we can get nearer to the layout we desire. If you chose to use this alternative route, it would look like this:
Dim PrintRect As New RectangleF
PrintRect.Width = 800
PrintRect.Height = 1000
PrintRect.Offset(25, 60)
Show Me The Width
It probably won't have escaped your notice that I very conveniently just happened to know what width and height I needed for the text to span across the page. Many times you will have this information to hand, but if you don't, what do you do then? Answer: You calculate it by querying the PrintDocument's PageSettings, find the width, height and margins and use those. Here's the code:
Private Sub PrintTheTextBox3(ByVal sender As Object, ByVal e As PrintPageEventArgs)
'Set a rectangle to bound the printing
Dim PrintRect As New RectangleF
With DocPrint.DefaultPageSettings
PrintRect.Width = .PaperSize.Width - (.Margins.Left + .Margins.Right)
PrintRect.Height = .PaperSize.Height
PrintRect.Offset(.Margins.Left, .Margins.Top)
End With
' Print the text from the TextBox:
e.Graphics.DrawString(TextBox1.Text, fnt, Brushes.Black, PrintRect)
End Sub
Summary
Although there are many more tweaks we could add to this approach, I think that the above will cover many common situations. If text trimming at the end of lines is something you need to refine to the nth degree then you should check out the StringFormat class in general and the StringTrimming enumeration in particular. There are several options available there.
Don't forget of course that you may not need to hand code your printing processes at all. There is a free Power Pack available which will print the contents of a form with minimum effort on your part. This will often be all that you need, but if not then at least you now know how to package up a bundle of text and send it to the printer to be laid out in a way that suits your requirements.
This is a follow up on the post about changing the colour of the TabPanel part of the tab control.
I created a video showing how I went about changing the template of the tab control using Expression Blend.
You can download the video to watch from here.
Friday was something of a Red Letter Day in the Mead household, because that was the day that the book I've been looking forward to getting for months finally arrived on my doorstep. At last - a WPF book aimed at those of us who prefer to use Visual Basic for the code behind. The book is Matthew MacDonald's "Pro WPF with VB 2008", published by Apress.
In the couple of days since it arrived I obviously haven't been able to get too deeply into reading it - although my wife might offer a different opinion on how many hours I've spent with my head in this book since Friday! However, it's immediately clear that this is another well-written and comprehensive piece of work from a widely respected author.
Unsurprisingly, large chunks of content have been ported directly from his earlier WPF book, which was based on .NET 3.0 and has C# as the code behind. This makes complete sense as it is only the code behind aspects that need the different approach. We VB-ers are just as able to understand the general WPF and XAML explanations as our allegedly "sharper" developer brethren.
Because this is based on WPF 3.5 though, there are some additional items, such as binding to a LINQ expression in Chapter 16. There is also a completely new additional Chapter 26, which deals with the topics of Multithreading and Add-Ins.
I don't think Apress have the full chapter listing on their site yet (or at least I couldn't see it if they did). However, rest assured that the whole gamut of WPF topics is covered in this book, from Layout to Dependency Properties, Routed Events to Navigation - in fact everything from Animation to Z-Index.
The author has a very useful list of links that you can simply click on to save you (mis)typing them yourself from the book. These links and the downloadable code samples are available from here.
In my opinion, you should buy this book for two reasons.
First, it is an excellent, wide ranging, clear description of what you will need to know in order to get fully to grips with this exciting (but not always intuitive) technology.
Second, there have been at least five WPF books published in the past year that have C# as the code behind. Publishers are in the business of selling books and they couldn't care less about whether C# or VB are "better". So I guess it's obvious that their stats show that they will sell more C# books. If you want to keep VB as a viable language, fully supported by authors and publishers, then the only way to ensure this is to make it worth their while to publish VB based books.
So for either or both these reasons, I rate this book as one of the most worthwhile investments you can make if you are a VB developer (or student) and you want to fully embrace all the tempting offerings available in Windows Presentation Foundation.
A question came up in the vbCity Forums that I participate in about changing the background colour of the header portion of the TabControl. The original question was about changing the colour of the tabs themselves (original question).
vbCity Leader (and Microsoft MVP) Ged Mead posted up code to change the colour of the tabs, but once the tab control's DrawMode property was set to “OwnerDrawFixed” the portion of the tab control without button changed to the default colour of “Button” which made it no longer the same as the background colour of the form.

I recalled that Ged had posted up a WPF solution for the background colour of a tab previously and figured that with WPF it may well be possible to change the colour for the rest of the tab header also.
So I forged ahead with my attempt to find a solution. Not being in any way shape or form a pro with WPF, I decided to try modifying the tab control with Expression Blend instead of Visual Studio. After a little messing around I did find that you can set the background colour of a tab control header to whatever colour you want and still have the tabs themselves with different colours.
I started out by taking the XAML that Ged posted and pasted that into my Expression Blend project as a starting point so it looked like the following. ( I did have to remove the image from the 3rd tab as I didn't have that particular image on my computer.)

Then I went in and began to look at editing the template of the tab control itself.
With very little fuss, I was able to set the background property of the TabPanel (this is the part of the tab control which holds the tab buttons) and I ended up with a coloured header background.

To accomplish this change you can either edit the XAML of the tab control, if you know what you are doing with XAML, and add in markup for the tab panel of the tab control and include a color for the background attribute.

or you can, as I did, right click on the tab conrol and from the popup menu “edit control parts (template)”. Moving your mouse over “edit control parts (template)” causes a submenu to become visible and you then select “edit a copy”. The Create Style Resource window opens and you are faced with a few choices. I decided to keep the default choices (resource name and define in this document) just for ease. Click the “OK” button and you are ready to start making changes to the template.
Since all I wanted to do was change the background of the tab panel, I selected it by clicking on the part of the tab panel that didn't have any buttons and in the properties pane I set the background to the colour that I wanted. That is how easy it was to get the effect that was required.
Once I had made all the changes required, I simply copied the XAML of the tab control from Expression and pasted it into a Visual Studio project and was ready to continue.
Below is the complete XAML for the tab control as shown above.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Window1"
x:Name="Window"
Title="Window1"
Width="640" Height="480">
<
Window.Resources>
<
SolidColorBrush x:Key="TabControlNormalBorderBrush" Color="#8C8E94"/>
<Style x:Key="TabControlStyle1" TargetType="{x:Type TabControl}">
<
Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Padding" Value="4,4,4,4"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="BorderBrush" Value="{StaticResource TabControlNormalBorderBrush}"/>
<Setter Property="Background" Value="#F9F9F9"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<
Setter.Value>
<
ControlTemplate TargetType="{x:Type TabControl}">
<
Grid ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local">
<
Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnDefinition0"/>
<ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
< FONT>Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition x:Name="RowDefinition0" Height="Auto"/>
<RowDefinition x:Name="RowDefinition1" Height="*"/>
< FONT>Grid.RowDefinitions>
<TabPanel Margin="2,2,0,0" x:Name="HeaderPanel" Grid.Column="0" Grid.Row="0" Background="#FF0968BA" IsItemsHost="true" Panel.ZIndex="1" KeyboardNavigation.TabIndex="1"/>
<Border x:Name="ContentPanel" Grid.Column="0" Grid.Row="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" KeyboardNavigation.DirectionalNavigation="Contained" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" Margin="{TemplateBinding Padding}" x:Name="PART_SelectedContentHost" ContentSource="SelectedContent"/>
< FONT>Border> < FONT>Grid>
<ControlTemplate.Triggers>
<
Trigger Property="TabStripPlacement" Value="Bottom">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="1"/>
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/>
<Setter Property="Margin" TargetName="HeaderPanel" Value="2,0,2,2"/>
< FONT>Trigger>
<Trigger Property="TabStripPlacement" Value="Left">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="1"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
<Setter Property="Margin" TargetName="HeaderPanel" Value="2,2,0,2"/>
< FONT>Trigger>
<Trigger Property="TabStripPlacement" Value="Right">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="1"/>
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="0"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
<Setter Property="Margin" TargetName="HeaderPanel" Value="0,2,2,2"/>
< FONT>Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
< FONT>Trigger> < FONT>ControlTemplate.Triggers> < FONT>ControlTemplate> < FONT>Setter.Value> < FONT>Setter> < FONT>Style> < FONT>Window.Resources>
<
TabControl Margin="8" Name="TabControl1" Style="{DynamicResource TabControlStyle1}">
<TabItem Header="Members" Background="LightGreen"
Foreground="Navy">
<
Grid>
<
ListBox Width="150" Background="LightGreen" HorizontalAlignment="Left">
<ListBoxItem>J Smith< FONT>ListBoxItem>
<ListBoxItem>J Jones< FONT>ListBoxItem>
<ListBoxItem>C B Travis< FONT>ListBoxItem>
<ListBoxItem>L Fourleather< FONT>ListBoxItem>
< FONT>ListBox> < FONT>Grid>
< FONT>TabItem>
<TabItem Background="Green" Header="Associates"
Foreground="Navy" >
< FONT>TabItem>
<
TabItem Background="LightBlue">
<
TabItem.Header>
<
StackPanel Orientation="Horizontal" >
<Image Width="20" />
<TextBlock Text=" Sponsors" Foreground="Red"/>
< FONT>StackPanel>
< FONT>TabItem.Header>
<
Grid>
<
ListBox>
<ListBoxItem>J Smith< FONT>ListBoxItem>
<ListBoxItem>J Jones< FONT>ListBoxItem>
<ListBoxItem>C B Travis< FONT>ListBoxItem>
<ListBoxItem>L Fourleather< FONT>ListBoxItem>
< FONT>ListBox> < FONT>Grid>
< FONT>TabItem>
< FONT>TabControl>
< FONT>Window>

The day of the first ever Developer Day Scotland is getting close! Registration is still open and I hear that there are still a few places left.
So if you are anywhere in reach of Glasgow on Saturday 10th May 2008 and want to take advantage of this FREE event for developers, you can Register from this page.
Wondering what's in it that might interest you? Check out the agenda here.
Colin and the guys have put in a huge amount of effort to get this off the ground, so I'm sure it will be a great day and well worthwhile attending.
By the way, on a personal note, I'm hoping to use the event to assess if there is enough interest around to start a SouthWest Scotland (or even a SW Scotland and Cumbria) Section of Scottish Developers. So if you live in this general catchment area and think you could be interested in joining such a group, please talk to me on the day. And if you can't make the day and are still interested, contact me via this blog or email to xtab at vb(nospace)city dot com.
Well it's been a long time since I last posted so thought I'd share with you how easy it is to make a custom field type within SharePoint.
Check out this New Article
And see for yourself.
A very quick one. Been playing with the above class for generating emails in .NET 2.0, embedding images within HTML views which is rather cool. However, I noticed an unusual problem. The emails I generated in my test project would not send until I had exited the application. It was almost like it would only 'flush' the generated email once the application had unloaded. Interestingly, if I attempted to send the email using the 'SendAsync' method, it would fire the SendCompleted event but still nothing would come through until the application had ended.
The resolution? Turning off Symantec Anti-Virus's 'Internet Email Auto-Protect' facility from the 'Configure' menu. Once deselected, everything started behaving properly.
I cannot answer for any other AntiVirus packages - but its a good starting point if you're experiencing the above.
M
Jaren Parsons of the Microsoft Visual Basic Team created PInvoke Interop Assistant. In a blog announcing the tool he says: “The motivation behind this tool is writing PInvoke is a hard and often tedious task. There are many rules you must obey and many exceptions that must be taken into account.”
Read about the tool and get a link to download it at: Making PInvoke Easy
I was taking a look at working with a WPF application the other day when I found, what I thought, was a really neat feature of Visual Studio 2008.
What I came across was the “Search” feature that is built into the Properties window of my WPF application. It was quite by accident that I found the search ability because I could not find the property of a control that I was trying to change. I knew the property existed, but for the life of me I could not find it.
If your display is like mine, when I look at the property window in Visual Studio, there are more properties than can be shown on the screen so the scroll out of sight.

Getting to a property, or finding the property as was my case, is much easier if you make use of the property windows search feature.

As you type in the search box, Visual Studio filters the properties of the Control to show only the properties that contain the letter(s) that you enter into the search box.
So if, for example, you want to quickly find the width property. When you type “w” into the search box, the list of properties is narrowed down.

Add an “i” into the search box and the list is filtered even more,

and so on if you want to keep going and type in the whole name of the property.
While this may not always be the quickest way to find a property, I thought it was a nifty addition to Visual Studio 2008.
The latest .NET book from the Murach publishing house is "Murach's Visual Basic 2008". This book is essentially an update of their earlier book for VB 2005 which now includes additional coverage of new features such as Anonymous Types, Object Initializers and LINQ.
I've just been re-reading my original review of the 2005 book and much of what I said then applies equally to this latest version. Here's what I said then:
We all find that some particular authoring styles work better than others for us individually. Some of us like a mass of detail and repetition; some like a few terse lines of explanation. Some of us like to be jollied along with the occasional funny; some like to stay serious. Some like the pages to be jam-packed with screenshots and diagrams; others think this is a waste of teaching space.
It's an individual thing.
Murach have developed their own particular individual style. They use a "facing page" technique. Open the book up at any section and on the left hand page you will find a discussion or explanation of a topic. On the facing page you will see more specific information about this topic, possibly with a diagram or screenshots, or very often demonstration code samples.
The benefit of this approach is that the author has two bites of the teaching cherry. She (in this case, author Anne Boehm) can introduce a topic on the left hand page, cover the essentials and be ready to move on. The value of the right hand facing page though is that it can be used to show additional detail, display sample code and example results and also (this I think being very important) can summarise the key points covered on the first page. The reinforcement of learning points in this way can be a very valuable tool.
Essentially, the reader can decide if he or she has understood enough from the left side page to be ready to move on, or if not then they can opt to read the right hand page for more info, samples or reinforcement and confirmation of their understanding.
Personally I quite like the approach. I tend to dive into books almost at random sometimes, but often just needing to refresh my memory on a particular point. If I'm using a Murach book and need further detail, I can dig into the additional facing page info as much as needed for any one topic, or even specific part of a topic.
If there is a down side to the Murach approach it's probably that because of the facing pages approach they have to limit the number of VB.NET topics they can actually cover in the 800+ pages limit . That said, what they do cover is fairly comprehensive and contains plenty of material to keep a VB.NET beginner engrossed for many a long night. And, most importantly, those topics are covered thoroughly and clearly in plain English.
A full list of the book Contents can be seen here and as you will see, you can drill further into each chapter to exactly what is covered.
If you want to know if the Murach style will suit you, then you can take a look at two Sample Chapters here.
In summary, this is another clearly written, well laid out offering from the Murach stable. This book is particularly suitable for newcomers to VB.NET, whether total developer beginners or those moving to .NET from VB Classic.
I've been working in conjunction with Evan Lim and Young Joo to convert the source code examples from Charles Petzold into VB.NET. As at today there still doesn't seem to be a WPF book on the market that has VB.NET as the code-behind (although I know there are a couple on the way). Add to this the fact that many C# to VB converters at the moment still get it wrong with several areas of the new Framework, this is a real stumbling block for many VB developers who would otherwise be much more interested in digging into WPF.
The link to the final version of the conversion of Petzold samples is here. You can download individual chapter code or the whole shebang from the links in that blog item
I've just started working on a similar project to convert the C# code of another WPF book. I'll post more once I've got something to show. In the meantime I hope that the Matthew McDonald and Billy Hollis WPF/VB books will be on the shelves before long.
To be quite frank, after 3 months of ASP.NET development, the opportunity to do some down and dirty API programming really appealled to me today. So, the question (as indicated by the title) involved a member wanting to disable the right-click context menu from the Flash ActiveX component when being used in a WinForms application. (See previous blog entries for examples of Flash in VB.NET and communication between the two such as http://blogs.vbcity.com/drydo/archive/2005/10/18/5586.aspx).
The simple answer is to capture the right-click of the Flash Window itself and prevent it from being processed. A little play with Spy++ quickly came up with the answers and the rest was all about good old fashioned subclassing. I must admit it pinched the API declarations from Pinvoke.net and smartened them up a tad and that is pretty much it.
For the record, this is something I've been meaning to do for a while + I can leave work not feeling like some CSS floozy :)
Note: to recreate, create one form, one button and add one Flash Active X control. Copy and Paste as necessary. Tested in VS2005. If you get the dreaded 'Failed to import the ActiveX control' message, check out this workaround
Imports System.Runtime.InteropServices
Public Class Form1
#Region "API Routines"
<DllImport("User32.dll")> _
Private Shared Function EnumChildWindows _
(ByVal WindowHandle As IntPtr, ByVal Callback As EnumWindowProcess, _
ByVal lParam As IntPtr) As Boolean
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Sub GetClassName(ByVal hWnd As System.IntPtr, _
ByVal lpClassName As System.Text.StringBuilder, ByVal nMaxCount As Integer)
End Sub
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Overloads Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal
nIndex As Integer, ByVal dwNewLong As Integer) As Integer
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Overloads Shared Function SetWindowLong(ByVal hWnd As IntPtr, ByVal
nIndex As Integer, ByVal dwNewLong As FlashCaptureRoutine) As Integer
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function CallWindowProc(ByVal lpPrevWndFunc As Integer, ByVal
hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
End Function
#End Region
#Region "Delegates"
' Used for processing Flash Window messages
Public Delegate Function FlashCaptureRoutine(ByVal hwnd As Integer, ByVal
Msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
' Used for enumerating child windows
Public Delegate Function EnumWindowProcess(ByVal Handle As IntPtr, ByVal Parameter As IntPtr) As Boolean
#End Region
' Constants
Public Const GWL_WNDPROC As Integer = (-4)
Public Const WM_ENTERMENULOOP As Integer = &H211
Public Const WM_RBUTTONDOWN As Integer = &H204
Public Const WM_INITMENU = &H116
' Private vars
Private mFlashWindowHandle As IntPtr
Private mPreviousHandle As Integer
Private isCapturing As Boolean
Private Sub Form1_FormClosing(ByVal sender As Object, ByVal
e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
' Cleanup if appropriate
If isCapturing Then CleanupCapture()
End Sub
Private Sub Form1_Load(ByVal sender As System.Object, ByVal
e As System.EventArgs) Handles MyBase.Load
' Load the test movie...
Me.AxShockwaveFlash1.Movie = "MyTestMovie.swf"
Me.AxShockwaveFlash1.Menu = True
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal
e As System.EventArgs) Handles Button1.Click
' Capture / Reset Flash Window Processing as appropriate
' React as approrpiate
If isCapturing Then
' Resume
CleanupCapture()
Else
' Capture events
CaptureRightClick()
End If
' Switch over the flag
isCapturing = Not isCapturing
End Sub
Private Sub CaptureRightClick()
' Attempt to obtain the Flash Window
EnumChildWindows(Me.Handle,
AddressOf EnumWindow, IntPtr.Zero)
' Subclass using new routine storing the old result
mPreviousHandle = SetWindowLong(mFlashWindowHandle, GWL_WNDPROC, AddressOf FlashWindowCapture)
End Sub
Private Sub CleanupCapture()
' Reset back to the original handle...
SetWindowLong(mFlashWindowHandle, GWL_WNDPROC, mPreviousHandle)
End Sub
Private Function FlashWindowCapture(ByVal hwnd As Integer, ByVal Msg As Integer,
ByVal wParam As Integer, ByVal lParam As Integer) As Integer
' Capture the appropriate message and prevent it from being processed
Select Case Msg
Case WM_RBUTTONDOWN
' Exit
Exit Function
End Select
' Carry on...
Return CallWindowProc(mPreviousHandle, hwnd, Msg, wParam, lParam)
End Function
Private Function EnumWindow(ByVal Handle As IntPtr, ByVal Parameter As IntPtr) As Boolean
' Obtain the class name of the child window
Dim ClassName As New System.Text.StringBuilder("", 255)
GetClassName(Handle, ClassName, ClassName.MaxCapacity)
' Is this the Flash Window?
If ClassName.ToString = "MacromediaFlashPlayerActiveX" Then
mFlashWindowHandle = Handle
End If
Return True
End Function
End Class
The list has more than doubled since I first published it here.
Below, in alphabetical order, is a partial listing of Visual Basic 2008 books. Some have already been published, some will be published over the next several months.
Accelerated VB 2008 (Accelerated)
Beginning ASP.NET 3.5 in VB 2008 - Programming Techniques
Beginning VB 2008 Databases: From Novice to Professional
Beginning Microsoft Visual Basic 2008