.NET Developments - A SearchWinDevelopment.com Blog

.NET Developments:

 

A SearchWinDevelopment.com Blog


A blog on all things .NET, with news and tips about Visual Studio, ASP.NET, Visual Basic programming, C# and .NET architecture.

VC++ gets update, VB6 gets heave

Microsoft development honcho Soma Somasegar reports that a Visual C++ 2008 Feature pack has shipped. In January the pack came out in beta.

MFC components included in the pack allow developers to create applications with the look and feel of Microsoft Office, Visual Studio and Internet Explorer. The VC++ 2008 pack can be downloaded from Microsoft’s Download Center.

That’s the good news. The bad news is VB6 has reached end-of-life status in terms of Microsoft formal support. The company has recently created a webcast explaining what that means, and what avenues are open for application migration.

VB6 Programmers - What happened to Printer.Print?

This post goes out to all you VB geeks that are wondering what happened to Printer.Print in VB.  This may be a dated topic but I have a feeling there are a few out there longing for those VB6 days when the printer was always sitting there loyal and waiting.  The VB6 programmer’s best friend.  Well, when you needed to print something anyway.   Once upon a time you could just write a few lines of code and *poof* you created a page of information for your users.  Now you have this PrintDocument thing and PrintDialogs and PrintPreviewDialogs and Graphics objects and the list just goes on and on.

Let me re-introduce you to printing in .NET.  Once you get through the slight grade of the learning curve, you’ll be convinced that .Net printing is better than anything you did with the printer object in VB6.

The task - print a smiley face on a piece of paper.  Lines of code in VB6 - about 6.  Lines of code the .net way - about 22 (but you could consolidate…).

That doesn’t sound like a good trade off.  It seems its easier in VB6.  However - what if you wanted to create a bitmap of the smiley face and then use that bitmap in various places as well as print it here and there?  How many line of code do you need now?

 In VB6 - I have no idea.  You would need to drop down to the API level and call graphics functions against a Device Independent Bitmap device context making sure you clean up after yourself in those places where cleanup is necessary.  Then you would need to save that bitmap to a file and/or have an image control somewhere that you could set using the memory bitmap (again using API calls).  Then perhaps you could print the smiley here and there using some similar printing code.

In .NET - its the same 22 lines of code and you can run those lines of code against any “Device Context” (using API terminology) by simply passing a Graphics object to the code that actually creates the smiley.  You could even create a bitmap object and simply use that bitmap throughout your program without ever getting close to the windows API.
Here are my CreateSmiley functions:

private void DrawSmiley(Graphics g, int Width)
{
  Pen p=new Pen(Color.Black);
  SolidBrush b = new SolidBrush(Color.Black);
  SolidBrush YellowBrush = new SolidBrush(Color.Yellow);
  Point Origin = new Point(0, 0);
  Size HeadSize=new Size(Width,Width);
  Rectangle Container=new Rectangle(Origin, HeadSize);
  Point LeftEye=Origin;
  Point RightEye=Origin;
  Point SmileTopLeft = Origin;
  LeftEye.Offset((int)(HeadSize.Width*.25), (int)(HeadSize.Width*.20));
  RightEye.Offset((int)(HeadSize.Width*.65), (int)(HeadSize.Width*.20));
  SmileTopLeft.Offset((int)(HeadSize.Width *.20), (int)(HeadSize.Width * .40));
  Size SmileSize = new Size((int)(HeadSize.Width*.60), (int)(HeadSize.Width*.40));
  Size EyeSize=new Size((int)(HeadSize.Width * .10),(int)(HeadSize.Width * .10));
  g.FillEllipse(YellowBrush, Container);
  g.DrawEllipse(p, Container);
  g.FillEllipse(b, new Rectangle(LeftEye, EyeSize));
  g.FillEllipse(b, new Rectangle(RightEye, EyeSize));
  g.DrawArc(p, new Rectangle(SmileTopLeft, SmileSize), 180, -180);
  b.Dispose();
  YellowBrush.Dispose();
  p.Dispose();
}

private Bitmap CreateSmiley(int Width)
{
  Bitmap Smiley = new Bitmap(Width, Width);
  Graphics g=Graphics.FromImage(Smiley);
  DrawSmiley(g, Smiley.Width);
  g.Dispose();
  return Smiley;
}

Pretty basic stuff and different than you did in VB6. You have access to all the API stuff without dropping down the the API level. Now as far as printing goes - there are a few objects that need your attention. The PrintDocument, PrintDialog, and PrintPreviewDialog objects. The PrintDocument object is the container for all your drawing methods. It handles paging and rendering of the stuff you are printing. The PrintDialog and PrintPreviewDialog objects manage the actual device you are printing to. The PrintDialog as you may have guessed will print to a printer while the PrintPreviewDialog prints to a preview window.

Here is some code that uses a PrintPreviewDialog and calls the printing methods above:

private void button1_Click(object sender, EventArgs e)
{
  PrintDocument pdoc = new PrintDocument();
  // hook up the event handler for the printpage event
  pdoc.PrintPage += new PrintPageEventHandler(pdoc_PrintPage);
  PrintPreviewDialog pdialog = new PrintPreviewDialog();
  pdialog.Document = pdoc;
  pdialog.ClientSize = new Size(640, 480);
  pdialog.Show();
}
void pdoc_PrintPage(object sender, PrintPageEventArgs e)
{
  Bitmap smiley=CreateSmiley(300);
  e.Graphics.DrawImage(smiley, new Point(150, 150));
  e.HasMorePages = false;
}

The VB.Net code is virtually the same. Just change the declaration variables around, change the curly braces to Sub/End Sub, remove the semi-colons and your 80% done.
This method of printing is easy to hook up and offers a great deal of flexibility but if you want real reporting power - there is no substitute for a good reporting engine such as SQL Server Reporting Services or Business Objects’ Crystal Reports. There are others.  I’m a convert.  I was a Crystal Reports bigot but if you’re using a SQL Server database - you get reporting services for free and I must admit after running SQL RS through its paces - I like it better than Crystal Reports.  That, of course, is my opinion.

mysmiley

The elusive project properties

So I put together my setup project using the in-grown version of MSI (don’t get me started on how cumbersome it is to add files!) and then built it. Looked good.

But when I tested it, the suggested path was “C:\Program Files\Default Company Name”. Whaaa? Where was it getting that from? And how could I get it to show the correct name? I figured I needed to modify some properties somewhere.

I right-clicked on the project in Solution Explorer, and then chose Properties. That brought up the configuration properties, not the project properties. Next I clicked on Project | Properties. That brought up the configuration properties again. So did View | Property Pages.

Then light dawned on Marblehead, as they say in New England. In Solution Explorer, I clicked on the name of the project. Then I clicked View on the menu bar and found the entry for Properties Window and clicked that. There it was—the manufacturer was set to Default Company Name. (Maybe I should buy that domain name….) At least it was an easy fix, once I found the right place.

I also noticed that I could choose an icon for my app’s entry in the Add/Remove Programs applet, as well as pre- and post-build events. I got all excited for a minute, thinking these were pre- and post-install events, but no such luck. Now wouldn’t that be nice!

The Deployment Project Properties window (as it is officially called) is very much like the properties windows for controls such as listboxes and buttons. Controls are objects, and so are projects, so I suppose it makes sense that you’d get to their properties the same way.

But they could have told me.

TFS to the rescue — almost

(Editor’s note: This is the first blog post by Christopher Yager, who will be writing on the .NET Developments blog from time to time. Yager is chief software architect at GLD Solutions Inc. and is currently using .NET 2.0 for his new development projects. Here he will blog about topics such as Windows Communication Foundation, Team Foundation Server and SQL Server. Welcome aboard, Chris!)

Before I get into this — welcome to my blog.  I’ll be posting mainly about my adventures in .NET programming — feedback is welcome.  I’m no guru but I did stay at a Holiday Inn Express last night.  (Actually as I write I’m still at said Holiday Inn… )

So TFS (Team Foundation Server), Microsoft’s answer to the software lifecycle management problem, really is a great product.  My team uses most features on a daily basis.  My headline is somewhat misleading but allow me some latitude while I state my case.  I run a software development company.  We produce software products and we have customers that use them.  (Go figure.)  We have a QA staff.  We test our products.  TFS has no way to capture the guts of a user defined test against a product that tests a particular requirement.  Specifically we needed to save metrics of test runs with success and failure rates, reasons for failure, environments tested, and lot of other neat stuff.  I didn’t expect TFS to have all this rich user testing goo so I expected we’d roll our own.  This article is about how we connected our hand-rolled testing metrics program with our Team Foundation Server.

The problem:  A scenario test fails; a bug is created against a product/task/whatever and needs to be linked to the test that caused the problem.

The Solution:  The TFS API!

Team Foundation Server has a plethora of components that you can leverage allowing seamless integration with the back end of your TFS implementation.  These components are found in the following path normally: 

[Program Files Root]\Microsoft Visual Studio 8\Common7\IDE\PrivateAssemblies

**Client requirement: On any system you install your custom TFS linked software, Team Explorer must be installed.  An obvious server requirement is that you have a Team Foundation Server installed somewhere in your network or available via the Web.  If you’re interested in getting TFS running (and why wouldn’t you be?!) you can download a trial from Microsoft.

Our general requirement for this task was to view a list of active bugs for a team project and allow selection of one. 

OK — some meat for you code monkeys. 

Create a windows forms project in your favorite language.  Mine is C# but any .NET language will do.

Add references to the following assemblies.  You’ll need to browse for them since they are not in the GAC or otherwise registered for easy VS reference adding.  The image shows them all together but this is a doctored image to save space.

tfs references

Put a tab control on the form and set it to dock-fill (leave the 2 tab pages alone), size the form to 800X600 (this just saves us some time and coding).

We’re basically going to create two functions that perform the guts of the scenario.  The GetWorkItems function which utilizes the DomainProjectPicker dialog class to allow the user to select the team project they wish to examine and the PickWorkItemsControl user control which allows searching of the TFS work item store. 

                   

private void GetWorkItems()
{
    DomainProjectPicker dpp = new DomainProjectPicker();
    DialogResult dr = dpp.ShowDialog(this);
    if (dr == DialogResult.OK)
    {
        tfs = dpp.SelectedServer;
        tfsProject = dpp.SelectedProjects[0];
        this.Text = "My Team Foundation Link - " + tfsProject.Name;
        Store = (WorkItemStore)tfs.GetService(typeof(WorkItemStore));
        TeamProject = Store.Projects[tfsProject.Name];
        pw = new PickWorkItemsControl(Store);
        pw.Dock = DockStyle.Fill;
        pw.PortfolioDisplayName = TeamProject.Name;
        this.tabPage1.Controls.Add(pw);
        pw.PickWorkItemsListViewDoubleClicked +=
            new PickWorkItemsListViewDoubleClickedEventHandler(
            pw_PickWorkItemsListViewDoubleClicked);
    }
}

The InitWorkItemControl function allows the user to view the details of a selected work item and utilizes the WorkItemFormControl control.


private void InitWorkItemControl()
{
    this.WorkItemControl = new WorkItemFormControl();
    this.WorkItemControl.Dock = System.Windows.Forms.DockStyle.Fill;
    this.WorkItemControl.FormDefinition = null;
    this.WorkItemControl.Item = null;
    this.WorkItemControl.LayoutTargetName = "WinForms";
    this.WorkItemControl.Name = "WorkItemControl";
    this.WorkItemControl.Size = new System.Drawing.Size(683, 428);
    this.WorkItemControl.TabIndex = 0;
    this.tabPage2.Controls.Add(this.WorkItemControl);
} 

We’ll tie this all together in the constructor for the form:


public Form1()
{
    InitializeComponent();
    InitWorkItemControl();
    GetWorkItems();
}

Here is what the finished product looks like: (This is an out-of-the-box dialog,  I didn’t write any of it.)
tfsConnect

The search control on this form does not have any of my code in it.  I only provided the tab control for it to live in.
tfssearch
The dialogs and controls exposed by the TFS API take care of the majority of the user interface, we just need to hook the stuff together with a little glue.  You can download the sample solution which has both C# and VB .NET versions of the program. 

Special thanks to Brian Randell who taught me this stuff through an article on MSDN Magazine.

 Download the source code here

They could have told me

(Editor’s note: This is the first blog post by Chris Madsen, who will be writing on the .NET Developments blog from time to time. Madsen is a consultant who programs in Visual Basic and Visual Studio 2005. Her first few posts will cover the ups and downs of migrating from VS 2003 to VS 2005; she’ll also write about some of the Visual Studio 2005 features that surprised her. Welcome aboard, Chris!)

The other day I got the latest edition of Visual Studio magazine in the mail. Along with it came a glossy, full-color pirate’s map. Evidently, that’s how Microsoft thinks of Visual Studio 2008 — “made for the likes of developers, and other scoundrels.”

I know the calendar says 2008, but in the real world of developers, it’s barely 2005. And I’m more a captain of a leaky little fishing boat than I am a pirate. It takes everything I have to get my work out the door on time. I upgrade my tools (such as Visual Studio) when I can’t live without a new feature, not when I get glossy maps in the mail.

I’m not alone: I still see plaintive questions begging for help with VB 6 apps, and with upgrading to VB .NET. I’ll leave it to others to reveal all the cool new stuff in VS 2008. I’m going to concentrate on Visual Studio 2005, including the woes of upgrading from VS 2003.

Whenever I run across a juicy bit, I’ll let you know. These are the things they never tell you, the information that’s written between the lines in the documentation, the stuff they leave out. It’s the stuff you find after opening a hundred Google links, buried in the answer to the answer to the answer to a question on some obscure site.

Who is this “they” who never tells me stuff? I’ll leave it up to you to decide.

I program mostly in Visual Basic .NET, so that’s what I’ll be talking about. I work almost exclusively with WinForms, and I’ve done a lot of work using Access, Word, and Excel in .NET apps. I love to write macros to make my life easier. I am a consultant with clients in Florida, Massachusetts and Maine. Just to keep things interesting, I live across country from all of them, in Washington State. So I might throw in some tidbits about telecommuting and consulting. Let me know if you are interested.

I’m sure I’ll write about some things you already know. Maybe they’ll make you smack your head and exclaim, “What sort of idiot is she?” But I figure if it wasn’t obvious to me, it wasn’t obvious to someone else, and that’s who the tidbit is for. I’m glad you have a better grasp of some things than I do.

But they could have told me.