Tuesday, June 12, 2007

What not to do with a progress bar.


This morning I installed an update for adobe software. As the software updated this dialog would display progress from 0% to 50% over and over again for over a minute. The text on the dialog didn't change at all during the process. It just seemed to be stuck in one of those out of control infinite updater loops from hell where it tries to perform a task and can't so it just keeps trying over and over again until you run out of patience and kill it. For your software you may think of a few other ways to utilize the progress bar and dialog in your apps.

First, the progress bar does go all the way to 100%. Test your update dialog and make sure it is listing the progress smoothly.

Second, If you have a long install you have a few choices. One way to do it is to break them up into a bunch of small tasks and display progress of each individual task and properly display and update the message to the user so that they know what your updater is doing.

Third, and probably the best way for a large update is to show the total progress for the entire update and change the message text to indicate that something is actually being done. Your users really want to know how long its going to take so that they can get on with their life. Why not tell them? That's why this is the best choice.

This updater is a good example of an update dialog. This is an updater for a Blizzard product. It shows the progress of the udpate, the percentage completed, and even tells the user an estimated time to completion. It even has some blinky lights in the title bar that indicates that its doing something!


P.S. The game is pretty good too.

Happy Coding!
Jas

Monday, May 07, 2007

Unit Testing and Mock Objects with NMock2 in VB.NET

I've been reading through Jean-Paul Boodhoo's article in Code Magazine "Layered Architecture, Dependency Injection, and Dependency Inversion" and spent some time reading up on the presenter pattern in his original article on microsoft's site in Design patterns on the Model View Presenter.

http://msdn.microsoft.com/msdnmag/issues/06/08/DesignPatterns/

In his article he explains the benefits of using mock objects in your unit tests. Although this post isn't going to go over the details of the article I will cover how I migrated his C# example to VB.NET and other issues I noted in the article.

First, the NMock2 framework is a useful tool for unit testing. Its a tool that can be added to NUnit to enhance your NUnit tests. If you aren't familiar with unit testing with NUnit I suggest starting there.

This is a sample of an NMock2 test found on the design patterns article:
C#:

[Test]
public void ShouldLoadListOfCustomersOnInitialize()
{
mockery = new Mockery();
ICustomerTask mockCustomerTask = mockery.NewMock();
IViewCustomerView mockViewCustomerView =
mockery.NewMock();
ILookupList mockCustomerLookupList = mockery.NewMock();

ViewCustomerPresenter presenter =
new ViewCustomerPresenter(mockViewCustomerView,
mockCustomerTask);

ILookupCollection mockLookupCollection =
mockery.NewMock();

Expect.Once.On(mockCustomerTask).Method(
"GetCustomerList").Will(Return.Value(mockLookupCollection));
Expect.Once.On(mockViewCustomerView).GetProperty(
"CustomerList").Will(Return.Value(mockCustomerLookupList));
Expect.Once.On(mockLookupCollection).Method(
"BindTo").With(mockCustomerLookupList);

presenter.Initialize();
}


Without duplicating the article and taking this line for line I'll just point out a few obvious things. Its a function with an NUnit annotation that tells Nunit it is a test. It creates a mockery class, some objects, and it runs three tests. Now, if you were to run this against your code it would completely pass assuming all your interfaces are created. Why? because the article left out that in the sample code this function also exists in the test code:

C#:

[TearDown]
public void TearDown()
{
mockery.VerifyAllExpectationsHaveBeenMet();
}


This little tidbit gets the mockery class to spit out the results of the tests. Okay, now you have a test that fails... Now lets take a look at the VB.NET version.


<Test()> _
Public Sub ShouldLoadlListOfCustomersOnInitialize()
mockery = New Mockery()

Dim mockCustomerTask As ICustomerTask = mockery.NewMock(GetType(ICustomerTask))
Dim mockViewCustomerView As IViewCustomerView = mockery.NewMock(GetType(IViewCustomerView))
Dim mockCustomerLookupList As ILookupList = mockery.NewMock(GetType(ILookupList))
Dim mockLookupCollection As ILookupCollection = mockery.NewMock(GetType(ILookupCollection))

Expect.Once.On(mockCustomerTask).Method("GetCustomerList").Will(NMock2.Return.Value(mockLookupCollection))
Expect.Once.On(mockViewCustomerView).GetProperty("CustomerList").Will(NMock2.Return.Value(mockCustomerLookupList))
Expect.Once.On(mockLookupCollection).Method("BindTo").With(mockCustomerLookupList)

Dim presenter As ViewCustomerPresenter = New ViewCustomerPresenter(mockViewCustomerView, mockCustomerTask)
presenter.Initialize()


End Sub


You'll notice it's pretty much the same thing. It just has a few syntax changes but the test will work fine. I hope this helps out some VB.NET programmers when trying to get this to work. I found little documentation on it.

Happy Coding!
Jas

Thursday, April 26, 2007

Editor Update build 0.03



I've been working on additional features for my editor. The two main items I added were:

Spherical Mapping:
While doing research for spherical mapping textures to geometry I ran across several examples and tutorials. Some of which were in published books such as 3D Game Programming with DirectX9.0c A Shader Approach. Another good one was by the zman(I'll include link later). I found that all of these examples had a rendering issue at the poles. It took me a little time to come up with a way of solving the problem. If you need to find out how to do it feel free to post a reply. I'll post this fix later when I have time.

Relative Extrusion:
Wrote a new algorithm that takes into account faces with shared edges that are to be extruded. This feature was a blast to code.

Wednesday, March 21, 2007

ASP.NET SqlDataSource Parameters Don't play with HiddenField controls

A little piece of information that might be helpful to someone...
If you have a SqlDataSource that has parameters and you are binding them to a control, you may have problems if you try binding them to HiddenField controls.

I had a simple gridview that was looking up records based on an ID. I had everything working fine with the sqldatasource bound to a session variable called session("myid"). But, I decided I wanted to cache the value on the page to eliminate timeout issues. So I added a hiddenfield to the page. In the page load event I set this hiddenfield with the ID value, just like I did with the session, but the grid would not pull the records anymore. I tried calling DataBind on the grid and even on the SqlDataSource and it doesn't pull the records.

When I changed the variable back to a session variable it worked just fine. I didn't have to call Databind. The SqlDataSource is smart enough to detect a change in the parameter and will refresh.

I also tried using a label control. This one worked fine too. In my instance, I just wrote at the top of the page "Welcome [label with my userid]" and I was on to the next task.

Happy Coding!
Jas

Monday, March 19, 2007

Nerd Test

I am nerdier than 90% of all people. Are you nerdier? Click here to find out!
Just took the nerd test. If you want to take it click on the image. Happy coding!
Jas

Friday, February 16, 2007

VB.NET 2005 MDI Docking to Floating Window

Have you ever wanted to create a tool panel that can dock on your GUI and free float as a tool window anywhere no the screen?

You may think that you can just create a child window and set its mdi parent and dock it to the left. But there are issues with this approach when you make it floating and try to redock it. Especially if you have a child window that is using that area of the screen. What I propose here is to to use panels to pull off the trick.



The first step is to create an MDI Parent window. Just create a new project in vs2005 (VB or C#) and set the "IsMdiContainer" property to True. Go ahead and add a menustrip and add a view option with sub options of Left, Right, Floating.

Next, we want to add a panel to the form and dock it. Go ahead and add panel1. Dock it to the left and throw a textbox on it for testing. Write the code in the menu events to change the dock property of your form. Leave the floating event blank. We'll get to that... If you run your app, you should be able to switch the docking to left and right.

Create a new form called frmTools. This window will be the container for our panel when we want it to float. Change the FormBorderStyle to SizableToolWindow. Now hit F7 to go to the code view. Add 2 member variable. 1 panel called mPanel and 1 Form1 call mParent. Modify the constructor of frmTools so that you can pass in a reference to Form1 and a reference to a panel. Set these variables before "Initializecomponent."

Next, create a private function call InitPanel(). What we'll do here is add the panel to the Controls Collection so that it can be rendered. You'll also want to set the Dock property to DockStyle.Fill and remember to use the SuspendLayout() and ResumeLayout(). Essentially, what we've done is create a secondary "Initializecomponent" function. I wouldn't recommend changing the "Initializecomponent" to do this code as it could cause issues during design time in Visual Studio 2005 designer. Once you've created this function call it in your constructor function after "InitializeComponent()."

Now, lets go back to Form1. In the event for View->Floating we'll create the frmTools window and call Show().

private void floatingToolStripMenuItem_Click(object sender, EventArgs e)
{
Form1 form = this;
frmTools tools = new frmTools(ref form, ref panel1);

this.SuspendLayout();
this.Controls.Remove(this.panel1);
this.ResumeLayout(false);
this.PerformLayout();
tools.Show();

}

Notice that I created a form and set it to "this" and then passed the reference to form into the function. There are other ways of referencing the main form. This was just a quick and dirty way. Maybe we'll get into that on another day. :)
In addition, we removed the item from the controls collection. Now, in testing I was able to remove this code completely and got the same results but lets play it safe. (BTW: If you know why this is so, please comment on the blog, thanks.)
Anyway, if you run your application you get your panel to float! Not to bad. One problem remains though. If you close the tool window your panel is now gone. Its been destroyed with the frmTool Control collection. So, we need to let the Parent window know that we are done with the panel. And we have to code a function in the parent window so that it can reinitialize the panel.
In Form1, create a new function called SetToolPanel(ref Panel panel).

public void SetToolPanel(ref Panel panel)
{
this.SuspendLayout();
this.panel1 = panel;
//set the dockstate to default.
panel1.Dock = DockStyle.Left;

this.Controls.Add(this.panel1);
this.Controls.SetChildIndex(this.panel1, 0);
this.ResumeLayout(false);
this.PerformLayout();
}

What we're doing here is something similar to "InitializeComponent()." We're just adding this control back in. Notice that I called "Controls.SetChildIndex." I did this because if you don't have these controls in the right order it could affect other docking controls. If you were to comment out this line and test, it would mess up the docking on your menustrip. So, remember to set it properly in your app.
Next, we need to modify the frmTools window so that it passes this panel back to the parent when its closing. In the properties window of frmTools, click the Events lightning bolt and override the "FormClosing" event under "Behavior." Call it onClosing. In this function we're only going to call "SetToolPanel" and remove the panel from the control collection so it doesn't get wiped out.

private void onClosing(object sender, FormClosingEventArgs e)
{
//Pass it off to the parent.
mParent.SetToolPanel(ref mPanel);
//Remove the control so it doesn't get ditched.
this.Controls.Remove(mPanel);
}
Thats it. Running the program you'll have a floatable dockable panel for your app. While testing, type something in the panel's textbox to show that its the same panel when it cycles through its states.
If you need source code let me know...
Happy Coding!
Jas

Tuesday, January 23, 2007

3D Blueman


This is a quick post of the first human head I've done in my editor (120 polys). I'm working on build 0.03 now. This one exports .x files for import into engines. Although it does texture mapping this picture doesn't show it. I'm really trying to keep the feature set down to a minumum until I work out the geometry workflow.

Happy Coding!
Jas

Tuesday, November 07, 2006

3D Desk



Well, I got to use my editor at work today. They needed a graphic of an 8 x 10 cubicle for our case managers. Kakoa, our Visio guru was out today, and so I gave it a go with my new editor. I didn't have much time to do the modeling but it turned out okay. I added a little shadowing in Photoshop but that was about it.

Happy Coding!
Jas

Monday, November 06, 2006

SQL Views with an ID column

I was recently given the task of replacing a table with a view and this table had an id column. There is a way to represent this id column in a view.

The following article explains the way to handle it:
http://support.microsoft.com/kb/186133

Keep in mind the limitations of this approach. Your row count can't be that large. If you have a large set of data and can use snapshots, consider using a temp table filled periodically for reporting. This will improve your query size and enable additional indexes if you require them.

Happy Coding!
Jas

Tuesday, October 10, 2006

SQL Case Statement Where? Use the "Dataman Maneuver"



Lets say you have an ice cream application. And you have two tables. One for storing the base ice cream and another for storing the actual flavors that are offered by the store. Your tables would have the following data:



Next, lets say that you have a dropdown for the base ice cream type which stores as its value the bid. In addition, one of the options is "ALL" with a value of "0." How would you write a query that will give you the rows from tblFlavors?

In VS.NET 2.0 you can add parameters to your selectcommand in the sqlDataSource control. Then, you can configure the parameter to get the value from your dropdown box. But, you have to do some work on the query to get this to work... Enter the Case statement in the where clause. Also known ast the "Dataman Maneuver" by certain trekky programmers with the initials of CRJones. :) You can visit Charley Jones at http://crjones.com


At first attempt you might try:
SELECT * FROM tblFlavors f
WHERE f.bid = @bid

This would work, but what would happen when you select the "All?" You wouldn't get any rows. You don't have any rows with a BID of 0. Enter the power of the Case statement in the where clause.

When you take a look at the where clause above, the WHERE clause is comparing the value of the bid for each row to the parameter @bid. This is a boolean operation. It is either true or false. All it cares about is whether the variables on both sides of the operator are the same datatype and that it can compare them. So, this allows us to do some crazy things with cases.

Lets try something else:
SELECT * FROM tblFlavors f
WHERE (Case when @Bid = 0 then 1 else 0 end) = 1


In this statement what are the two variables that are being compared? The right side is a 1, and the left side is whatever my case spits out. The database is smart enough to execute the case first and then compare the result against your 1. If you were to run your application, it would only work when you selected the "All" option. If you selected another option such as Vanilla, you would get nothing because @Bid would be = to 1 and in the above 1 isn't 0 so it returns 0. 0 doesn't = 1.

The solution is:
SELECT * FROM tblFlavors f
WHERE (Case when @Bid = 0 then 1
when @Bid = f.Bid then 1 else 0 end) = 1


Here it will check the first statement.
Does @Bid = 0?
yes: return the 1.
no: check the next one.
Does @Bid = f.Bid?
yes: return the 1.
no: go to else which returns 0.

Now, it checks the case value to 1 and if this is true you get your row.

Happy Coding

Friday, July 28, 2006

Cool Controls: Custom Validators

Custom validators are pretty cool to use in ASP.NET 2.0. There are quite a few samples on the web for getting these hooked up. However, most of the samples are REALLY simple in the client-side script. I wanted to throw this one out there just in case someone else has to do something similar.

The Sample:
Lets say you have a checkbox and a DropDownList, and you want the DropDownList to have validation on it only when the checkbox is checked. When the checkbox is not checked you want the DropDownList disabled. Okay, sounds pretty simple, but can we do it without a postback.

Toggling the Disabled property

The JavaScript to toggle the DropDownList disabled property can be done like so:

<script type="text/JavaScript">
function Change(chkfield,field)
{
if (chkfield.checked == true)
{ document.getElementById(field).disabled = false; }
else
{ document.getElementById(field).disabled = true; }
}
</script>


Notice that I'm passing in the checkbox object and the field to be disabled. The DropDownList will be called "dd1."
In the checkbox you just plug in the function like so:

<input id="chk1" title="chk1" onclick="Change(this,'dd1')" type="checkbox" value="X" name="chk1">MyCheckBox

Adding the CustomValidator
Next we add the CustomValidator control after the checkbox. The code would like the following:

<asp:CustomValidator
ID="CustomValidator1" runat="server" ClientValidationFunction="Checkit" ControlToValidate="dd1"
ErrorMessage="Required Field" Font-Size="Large">*</asp:CustomValidator>


With the CustomValidator control you can supply a "ClientValidationFunction" that will be called. Remember to provide a server-side function as well because if you don't it can be a security risk according to Microsoft. For this example I left that out.


The Validation Function
The validation function, called "Checkit" in this example, will check the validation of the DropDownList "dd1."

This function would look like this:

function Checkit(sender, args)
{
if(!document.getElementById(sender.controltovalidate).disabled && args.Value=="bad")
{
args.IsValid=false;
}else{
args.IsValid=true;
}
}

Notice that the function is checking for a value of "bad" in the args.Value. The CustomValidator doesn't like having null values in there so just put the word "bad" in the value of your empty selector item in the dropdownlist. There was a hack for getting this to work with null values but for this example this should do nicely.

Anyway, that's it for the Custom Validator control. Another cool control in the ASP.NET arsenal.

Happy Coding!

DX Jas




Thursday, July 06, 2006

Problem stretching images with GDI+


I've noticed a problem when trying to zoom in on an image using the DrawImage method. The above image shows the problem. Basically, if you scale the image, the first row and column doesn't get scaled correctly. I've posted the problem twice on Expert-Exchange but have not found an explanation or fix yet.

I created a test app that takes a 40x40 bitmap with a checkerboard pattern and zooms it by a zoomfactor. The render code is as follows:

Protected Overrides Sub OnPaint(ByVal e As
System.Windows.Forms.PaintEventArgs) Try

If (bmp Is Nothing) Then

Else

Dim g As
Graphics = e.Graphics()
g.SmoothingMode = Drawing2D.SmoothingMode.None

g.InterpolationMode = Drawing2D.InterpolationMode.NearestNeighbor
g.SmoothingMode = Drawing2D.SmoothingMode.None

Dim rect As New Rectangle
rect.X = 0
rect.Y = 0
rect.Width = (bmp.Width * m_ZoomLevel)
rect.Height = (bmp.Height * m_ZoomLevel) 'attribute shows that destination rect is
the right size but not needed for test.

Dim attr As System.Drawing.Imaging.ImageAttributes
attr = New System.Drawing.Imaging.ImageAttributes()

attr.SetWrapMode(System.Drawing.Drawing2D.WrapMode.TileFlipXY)


g.DrawImage(bmp, rect,0, 0, 40, 40, GraphicsUnit.Pixel, attr)
attr.Dispose()

End If
Catch ex As Exception

MessageBox.Show("ouch")

End Try
End Sub


This bug has been posted to Microsoft and confirmed by other programmers. A fix is to do the following:

Use (-0.5 + 0.5*srcw/dstw, -0.5 + 0.5*srch/dsth) as the source origin.

Happy Coding!
Jas

Tuesday, June 27, 2006

A buggy lesson


Two nights ago I was laying in my bed just about to fall asleep when I thought I heard a bug trying to fly in my ear. I jumped out of bed, turned the light on and couldn't find him. Finally I went back to bed after not finding the bug and just as I was approaching dreamland, I thought I heard the bug again. This happened several times during the night.

At some point, I started questioning my sanity. I thought maybe my brain was making up sounds that weren't there. Or, maybe my years of loud music had caught up with me and this was some sort of hearing damage.

(There is a coding point to this...) In the morning, I had two gigantic goose egg bites on my right arm. AHA! there was a bug.

At this point, I knew there was a bug and I had to find it. To make a long story short, two nights later and 6 bites total and I caught the bugger!

The moral of this story:
1. When writing programs never give up on a bug.
2. If you can't reproduce it or find evidence of the bug, don't let it drive you insane because it can. Take some time away from it and go back later. In time, you'll be able to isolate it.
3. Where there is one bug, there are usually two. Remember that unit testing can help but the test can only check logic that you coded for. Review your code change at another time you may spot others. (Yes, there were two mosquitos! I found one on the same wall 5 minutes later!!)

Happy Coding!!

Thursday, June 22, 2006

My Geometry Editor


I've been working on my own geometry editor now for about a year. Its written in C# vs.2005. I should be ready to push out a beta version of it in a few months. The image is one I did on the weekend.

Development has really slowed since my second son Bryce was born in February. I'm just starting to get some work done on it now. I've been working on the rotation gizmo for the last few days. I have it working pretty well now.

What I'm looking for are beta testers or hobbyists who would like to use it on a project. It will output .X files but I can create other outputs as well if needed. Please post a reply if you're interested and describe the project you would like to work on. Its okay for low poly objects but not so great for organic objects yet. It has pretty limited tools. I'll keep posting my progress as I go.

Wednesday, June 21, 2006

Table vs CSS layout for forms

Separating layout elements from your information is an essential element in web design. But when it comes to form design, sometimes its quicker to use the tables.

For example, I've done the last three web forms (10-30 fields) using CSS layout. They look good, but they took twice as long to write all the css to align the items in different patterns. What am I saving here? Were the styles reusable? Not really.

Lets face it we aren't going to be changing the entire look of our input forms. The page itself? Maybe.

Even in Eric Meyers CSS book he used tables for the input forms examples.

So in conclusion:
Styles for layout: Good.
Styles for forms: Think about designing around the table.

Jas

Docking in VS.NET 2005

I was looking for a quick way to solve a docking issue in dotnet and I stumbled across this blogsite on cranky programming.

http://crankydotnet.blogspot.com

The title is "Is anyone doing anything HARD with .NET?
I thought he was right on the money. I would say the answer is "We are NOW!"

VS.NET 2005 promised to make our life easier and that actual code is greatly reduced. But, what they don't tell you is the saved coding time is reallocated to trying to tweak their controls to do what you want. And they make it look so easy in the demos...

I've reported 3 bugs I've found already with VS.NET 2005. The above link has some more. It makes me want to jump ship to the Java camp, but that's not what pays the bills.

The items I found were:

1. ASP.NET: If you comment out a control in the html view of a web form and create a new control with the name of the old one, the compiler still picks up the commented control and lists an error. On Microsoft's website it says its designed this way.

2. ASP.NET: The Textbox control "MaxLength" property does not work if "Multiline" is set to true. Again, by design..... Yeah right.

Bug workarounds:
1. VB.NET: If your design view for a form refuses to display, showing a list of variables missing you know are in place, simply hit F7, go to anyword hit spacebar and then backspace and hit F7 to return to designer. It amazingly figures out that the missing variables DO exist.

Hope this helps someone.