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.