Microsoft Research Stitching Tool

I’m a little late to the game, but Microsoft released a stitching tool called Image Composite Editor (ICE, and please note my restraint in not naming this blog post ‘ICE ICE Baby’), this is also available in Live Photo Gallery apparently (don’t use it myself).  I’ve always used the tool that came with my Canon software because it was easy, but after taking a couple panorama shots in Death Valley while I was at Mix09, I became very disappointed.

  BoraxPano

You can see above the very obvious seams, and that is after I touched it up a little bit.  Destiny provided me link to ICE right after this failed experiment with the Canon tools and I tried it, and was blown away.  It can do a lot of very cool things, and most importantly it merged my images without the slightest indication of a seam. 

ms_researchBorax

What you might have missed at Mix09

MIX09_BlogBling_InterfaceInspiration_CR4_2

The first and foremost thing that you missed if you didn’t attend Mix09 was the opportunity to hang out with Barry, Bruce and myself.  If you were at Mix09 and didn’t come over and say hello, I can only assume it had something to do with the unnatural resemblance Barry shares with Dr. Evil.

For me, the two big things at Mix were Expression Blend improvements (preview) and Silverlight 3 beta.  If you are interested in something other than those two products check out both keynotes and all of the session videos on the Mix09 site.  For a nice non-technical change of pace I strongly recommend watching the Day 2 keynote around minute 32 for a great example of UX design.  Deborah Adler explains how she set out to change the design of prescription bottles after her grandmother mistakenly took her husbands medication instead of her own.

Expression Blend 3 Preview

Expression Blend took some really big steps to become a more mature product for both developers and designers.  For a good overview of what’s new in blend check out Douglas Olsen and Christian Schormann in their ‘The Future of Expression Blend’ session.

SketchFlow

Not actually available in the preview. Sketchflow is an amazingly simple way to sketch out some rough UI designs and publish them in a manner that allows you to actually navigate around your app (no code required, but XAML is actually produced) and also provides a mechanism for stakeholders to leave feedback on each of your designs.  Hard to do this functionality justice, so be sure to checkout Christian Schormann’s blog, his presentation at Mix09 or the Day 1 keynote presentation (About minute 97), this had a lot of buzz during the week.

A Better IDE

Blend 3 also went a long way to make the integration of developers and designers much smoother.  Developers get Code-Behind Support and TFS Functionality (designers should find this helpful as well hopefully).  Designers get SketchFlow and the ability to import files from Adobe Photoshop and Illustrator.  Blend can parse these files and replicate the gradients, shapes, layers, etc and create Xaml.  A demo of the Adobe support can be found in the Keynote Day 1 (again around the 97 minute mark) and the ‘Integrating Microsoft Expression Blend with Adobe Creative Suite‘ session.  Designers (and those of us that pretend to be) will also enjoy the new simple Sample Data panel to generate sample data, or read it from an xml file.  This gives you a very simple way to see your Xaml in the designer exactly how you would see in the actual application.  There is a sample in the Keynote Day 1 (minute 97, it was an exciting point of the keynote).

Silverlight 3

There was a beta release of Silverlight 3 made available at Mix this year as well as a new drop of the Silverlight Toolkit. Shawn Burke has a great breakdown of the Toolkit drop and the work they did to make it work with Silverlight 2 and 3.  Silverlight 3 has made many changes that will make working in Silverlight a lot less painful, bringing it more in line with WPF.  Checkout the ‘What’s New In Microsoft Silverlight 3’ session video for a great overview of all the features.  The big features that I found interesting were Out Of Browser Support (video), which Bruce explains isn’t really out out of browser, but is still a great feature for giving your Silverlight app that WPF application feel.  You can couple out of browser with the new Offline support (video) and really turn your Silverlight application into an almost fully fledged desktop application that can run across several different operating systems. 

Application Navigation Framework is great way to get some built-in navigation between pages, I’m really loving this feature.  Tim Heuer shows you how to do some URI routing with the deep-linking that is available with this framework as well.  There doesn’t seem to be a lot of info out on the internet about this feature, but you can create a new Silverlight Navigation Project and the stubs it creates will explain everything you need to know.

The other features that will probably be of interest to you include Perspective 3D for easy, yet stunning, 3D transforms, the Blur Effect, Element-to-Element Binding (yay! It’s about time), Merged Resource Dictionaries, and Style Inheritance.

Mix09 showed us that in the next few months as Silverlight 3 and Expression Blend 3 get released, the designer-developer workflow gets easier, and you no longer have any excuses to avoid using Silverlight in your personal or business applications.  If you haven’t even looked at Silverlight yet, get cracking.  If you want to try SL3 and still deploy SL2 apps, check out this article by Jeff Wilcox.

UI Safe BindingSource

It caught me off guard that the BindingSource is not really UI thread safe.  The situation we had was a model running on a background thread that was updating a dataset.  My view contained a grid, that was bound to a BindingSource which was bound to a table in that dataset.    The result was cross-threading exceptions being thrown as soon as we opened our view.  The thread that updates the dataset is the same thread that fires off the events that tell the BindingSource the underlying data has changed, which in turn tells the UI piece that data has changed, all the while still on that background thread.

My first pass at fixing the issue was to override OnListChanged in the BindingSource and marshal the thread back on to the UI thread.  This seemed to solve the problem until we bound to the entire dataset instead of just a table.  Internally the BindingSource creates a BindingSource for every list inside the collection of lists.  In this case, for every table in the dataset. 

Thanks to Reflector and the ability to debug into the source code, I found a way to get around the creation of more BindingSources, and instead created my own ObjectsharpBindingSource internally. 

This solution is probably only happy path, but that is the only path my code was following so that’s the only code I looked into.

Comments?  Questions?  Concerns?  Don’t like my code?  Better idea? Let me know, feedback is always welcome.

The idea behind UIThreadMarshal can be found at this great article by

    public class ObjectsharpBindingSource : BindingSource
{
private delegate void OnListChangedDelegate(ListChangedEventArgs e);
private Dictionary<string, ObjectsharpBindingSource> relatedBindingSources;

public ObjectsharpBindingSource() : base()
{
relatedBindingSources = new Dictionary<string, ObjectsharpBindingSource>();
}

public ObjectsharpBindingSource(object dataSource, string dataMember)
: base(dataSource, dataMember)
{
}

public override CurrencyManager GetRelatedCurrencyManager(string dataMember)
{
CurrencyManager result = null;
if (string.IsNullOrEmpty(dataMember))
{
//If you call the CurrencyManager property you end up in a recursive loop
Type t = this.GetType().BaseType;
result = t.InvokeMember("currencyManager", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField, null, this, null) as CurrencyManager;
}
else if (dataMember.IndexOf(".") != -1)
{
//dot notation is not supported by the BindingSource
result = null;
}
else if (relatedBindingSources.ContainsKey(dataMember))
{
result = relatedBindingSources[dataMember].CurrencyManager;
}
else
{
ObjectsharpBindingSource bindingSource = new ObjectsharpBindingSource(this, dataMember);
this.relatedBindingSources.Add(dataMember, bindingSource);
result = bindingSource.CurrencyManager;
}
return result;
}

protected override void OnListChanged(System.ComponentModel.ListChangedEventArgs e)
{
if (UIThreadMarshal.InvokeRequired)
{
OnListChangedDelegate changeDelegate = new OnListChangedDelegate(base.OnListChanged);
UIThreadMarshal.Invoke(new MethodInvoker( delegate { OnListChanged(e); } ));
}
else
{
base.OnListChanged(e);
}
}
}

New MS (Dundas) Chart Controls

The client I’m currently working with needed a charting control that would allow us to create something similar to a Gantt chart.  Unfortunately the control suite we were using wasn’t quite up to the task.  Fortunately a fellow Objectsharpee (and former Dundas employee) told me that Microsoft was going to be putting the Dundas controls they had purchased into the framework, even better was that it had been released just the week previous.  I’ve never used Dundas controls previous to this, so I’m not 100% clear what the feature set differences are, or if there are any.  The MS Chart control did everything we needed and it was dead simple to do. 

All you need to do is download and install the small installer and have .Net 3.5 SP1 already installed.

Chart Docs
Chart Controls
Chart Forums – Note: Not a lot of information in the forums as of this posting, but the Dundas support forums are filled with great, applicable, information.
Chart Samples

Also, Alex Gorev has started a blog all about the new data visualization in the .Net Framework.

TFS Powershell PSSnapin

The October Team Foundation Power Tools drop includes three new features:

  • TFS Power Shell Extensions
  • TFS Windows Shell Extensions
  • Team Members Tool

The only one I care about is the Powershell extensions. Keith Hill has a great post with some examples.  I already had a script that made some .NET assembly calls to get me the latest good build off of TFS.  I converted that script to use the new snapin, and posted it below.  I’m sure some of this is not best practices, feel free to let me know if you have a cleaner implementation.

(Get-TfsServer -Name myTfsServer).GetService(Microsoft.TeamFoundation.Build.Client
.IBuildServer]).QueryBuilds("myProjectName", "myBuildName") | 
where { $_.BuildDefinition.LastGoodBuildUri -eq $_.Uri } | select DropLocation
 
Two lines in my profile.ps1:

[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Build.Client")

SQL Server – Dropped my default database

Today I learned an important lesson about Sql Server 2005, don’t change your default database unless you absolutely have to.  I set mine to DatabaseX and then I promptly dropped DatabaseX.  When I tried to log in I got a nice error message

            Cannot Open User Default Database, Login Failed

I didn’t setup the VM that I was using, so I didn’t know the SA password.  I basically had no way to get back into the server.  So if you ever find yourself in this predicament, execute the following from the command line:

C:\> sqlcmd -E -d master 
1> ALTER LOGIN [YOUR USER NAME HERE] WITH DEFAULT_DATABASE=master 
2> GO
 

That will reset your default database back to master and you can login again. 

Infragistics Tips and Tricks - Part 1 of N

The current project I'm on is using Infragistics controls exclusively.  Infragistics can do some wonderful things, but damn, sometimes it does it horribly.  So here are a couple little hints and tips that might save someone a couple of frustrating moments of despair.  Find something in my list that I did wrong?  Found something I could have done better / cleaner / quicker? Please let me know.

Binding to a List<>

If you are binding your Grid to a BindingSource that in turn is bound to a Generic List, the key of your band needs to be the name of the class your list contains.

List<Message> myList = new List<Message>();
myBindingSource.DataSource = myList;
myUltraGrid.DataSource = myBindingSource;
 

Band key in your schema is 'Message'.  If your class contains another collection there will be bands for those collections which will add 'plus' signs beside all your rows even if that collection is empty.  Create another band in your schema with a key equal to your child collection and then set Hidden = true.  (See below about the Hidden property...)

The other note for binding to a generic list is that if it isn't an ObservableCollection or BindingList  (or anything that doesn't implement IBindingList or IBindingListVIew) then you are not going to get an update when you add or remove and item from the list.  If you know these things are happening you can call myBindingsource.ResetBindings(false) when they happen to update your grid with the new bindings.

Good article on what interfaces have what binding functionality.

Can't Find the .Visible property?

This one baffles me, and I'd love to know why some infragistics controls do not have a .Visible property, instead they have a .Hidden.  Watch out for that.  Apparently this is some sort of VB throw back blah blah blah.

CreationFilter's To Change GroupBy Headers

CreationFilters are a really cool concept that let you change the layout of a lot of Infragistic controls and add new functionality.  I used this to add some status lights to the GroupByRows of my grid. 

Create a Creation Filter class that implements IUIElementCreationFilter.  My AfterCreateChildElements(UIElement parent) does nothing but here is my  BeforeCreateChildElements method.  This will create 3 icons and some text in the group by row.  I create my own text element but if you want to grab the existing text element: 

DependentTextUIElement dependentTextUIElement = parent.GetDescendant(typeof(DependentTextUIElement)) as DependentTextUIElement;

 
public bool BeforeCreateChildElements(UIElement parent) { bool value = false; if (parent is GroupByRowDescriptionUIElement) { int X = 17; int Y = parent.Rect.Y + 1; int Width = 516; int Height = 17; UltraGridGroupByRow groupByRow = (UltraGridGroupByRow)parent.GetAncestor(typeof(GroupByRowUIElement)).GetContext(typeof(UltraGridGroupByRow)); DeviceStatusInfo deviceInfo = groupByRow.Tag as DeviceStatusInfo; if (deviceInfo == null) { deviceInfo = new DeviceStatusInfo("", DeviceState.Offline, DeviceOnlineState.NotOnline, "", FoundationHelper.GetImage(typeof(string))); groupByRow.Tag = deviceInfo; } string text = deviceInfo.DeviceName; if (!string.IsNullOrEmpty(deviceInfo.DeviceCurrentOperationsText)) text += " - " + deviceInfo.DeviceCurrentOperationsText; TextUIElement textElement; ImageUIElement firstIndicator; ImageUIElement secondIndicator; ImageUIElement deviceIcon; parent.ChildElements.Clear(); deviceIcon = new ImageUIElement(parent, deviceInfo.DeviceImage); textElement = new TextUIElement(parent, text); firstIndicator = new ImageUIElement(parent, deviceInfo.DeviceStatusImage); secondIndicator = new ImageUIElement(parent, deviceInfo.DeviceOnlineImage); deviceIcon.Rect = new Rectangle(X, Y - 1, deviceInfo.DeviceImage.Width, deviceInfo.DeviceImage.Height); firstIndicator.Rect = new Rectangle(deviceIcon.Rect.X + deviceIcon.Rect.Width + 2, Y, deviceInfo.DeviceStatusImage.Width, deviceInfo.DeviceStatusImage.Height); secondIndicator.Rect = new Rectangle(firstIndicator.Rect.X + firstIndicator.Rect.Width + 2, Y, deviceInfo.DeviceOnlineImage.Width, deviceInfo.DeviceOnlineImage.Height); textElement.Rect = new Rectangle(secondIndicator.Rect.X + secondIndicator.Rect.Width + 2, Y, Width, Height); parent.ChildElements.Add(deviceIcon); parent.ChildElements.Add(textElement); parent.ChildElements.Add(firstIndicator); if (deviceInfo.DeviceStatus == DeviceState.Online) { parent.ChildElements.Add(secondIndicator); } firstIndicator.ToolTipItem = deviceInfo.GetDeviceStatusToolTip(); secondIndicator.ToolTipItem = deviceInfo.GetDeviceOnlineStatusToolTip(); value = true; } return value; }

 

Set the creation filter:

this.ultraGrid.CreationFilter = new GroupRowIndicatorsCreationFilter();

 

TabClosing Event Order

This tip is kind of specific, but thought I'd post it here anyway.  If you are using the Mdi Tabbed Workspace (and I assume the Mdi Tab Control) then a little gotcha is that when the user closes a form, either by clicking the 'X' or by you firing the form.Close() method the Mdi_Tab_Closing method is fired BEFORE the Form_Closing event.  If you think about it, it makes sense, however it is a pain in the butt if you want to handle someone closing a tab, and someone closing the whole app differently.  In our app we have functionality similar to visual studio, if you caused it to fire?!? Short answer is you can't.  So here is a little method that will fire before either Mdi_Tab_Closing and Form_Closing.

protected override void DefWndProc(ref System.Windows.Forms.Message m) { if (m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_CLOSE) { applicationClosing = true; } base.DefWndProc(ref m); }

The applicationClosing bool allows me to check if the user hit the X button when I'm in my Mdi_Tab_Closing.  If you have an 'Exit' option from a file menu then in that code you will want to set applicationClosing = true in there as well.

Reset permissions for existing folders on a new Vista Install

I just did a fresh install of Vista Ultimate on my home desktop PC.  The install all went fairly smooth except for 2 things:

1) IIS was not installed, and I missed the little checkbox to install ASP support.

2) I had a lot of problems accessing my existing Documents And Settings folders and could not access (only read access) my other partitions.  Even as Administrator I could not seem to set permissions on these folders and drives so I could write to them.  Thankfully Tim Sneath came to the rescue with a posting about 'Deleting the Undeletable' in which he explains how to reset the permissions on files to give yourself access to them. 

it's not unusual to find some folders that can't be accessed, even by an administrator, because their ACLs were set for accounts with SIDs that applied to an old partition

Tim provides a quick batch command that will allow you to reset the proper permissions for the Administrators group. 

takeown /f %1 /r /d y
icacls %1 /grant administrators:F /t

Just pass it a directory to start at (it is recursive).

Big thanks to Tim.

IIS 7, ASP, and Vista

When I did a fresh install of Vista on my home desktop machine it did not install IIS by default which is to be expected.  But the real problems started when I could not find out how to install ASP support.  Anytime I would try and load an aspx file it would say it didn't know how to handle .aspx as a static file.  Very frustrating.

Barry Gervin provided a link that shows the step by step instructions on how to properly install IIS 7 on vista, including the slightly hidden ASP.NET support.  Is anyone really installing IIS7 and not installing ASP.NET support?

Vista DreamScene

While I was out at the Vista Ice House in Toronto last week they were demo'ing 'DreamScene', which is movies as desktop wallpapers.  The basic idea is that you take a small subtle looping video and apply it as your background.  Obviously this is eye candy only, but it is pretty impressive eye candy when done properly.  There is a video here that shows a couple of examples.

 

DreamScene is one of those annoying Ultimate Extras which must really drive anyone without Ultimate absolutely nuts.  Thankfully I have Ultimate, and managed to get my hands on a beta (the official release is apparently some vague time in the future), only problem is that the beta does not seem to support dual-monitors, something that hopefully will be addressed in time for the final release.  WinCustomize has started a page where you can get some DreamScene movies, apparently both in-house created, and user submitted.  It doesn't appear that the page is ready for primetime, but you can check it out none the less.