Submitted by Billb on 8/25/2008

(If you have a minute, please add a comment when you're done so I know if I'm presenting this well enough.)

Infragistics Creation and Draw Filters

In this article I present what I learned about Draw and Creation filters for an Infragistics WinGrid along with the particular customizations I needed to make to a grid. I hope it helps you out with writing your own filter methods.

Contents

Introduction
Introduction to UIElements and Filters
My UltraWinGrid Customization
Alternative to Filters - Creative use of Properties
UIElements in Detail
Should I use a Creation or a Draw Filter to Make My Customization?
Creation Filter
    BeforeCreateChildElements Method
        Identifying the UIElement Object Passed to Your Method
        UIElements and Control Objects
    AfterCreateChildElements Method
Draw Filter
    GetPhasesToFilter Method
    DrawElement Method
Before and After
Links

Summary

A quick summary first. It might give you a base understanding to keep you rooted while reading through this admittedly somewhat rambling article. I must say I've never encountered such an evironment in which these filters exist and I found myself being very surprised as I learned more. The fact that a separate tool, a UIElement Viewer, was required in the process was a particular surprise. It all seemed very bizarre.
  • Think of an Infragistics control as made of bricks and each brick can consist of other bricks. Each brick is called a UIElement. So, UIElements can be said to occur in a hierarchy in that one UIElement may contain other UIElements.
  • Infragistics logic will call your filter methods for each UIElement as it's being rendered on the screen, allowing you to intervene and modify or delete an existing UIElement or add a new UIElement.
  • Your Creation and Draw filter methods receive a UIElement object as a parameter and your code needs to figure out if that UIElement is the one you want to somehow modify. To do this, before writing your filter code, you need to understand how the control is built. Infragistics has a tool called the UIElement Viewer which you use to examine your grid's structure while your application is running. (It's very interesting.)
  • UIElement objects are associated with control objects. For example a CellUIElement object is associated with a particular cell object, so you can obtain control objects in your filters and modify them.
  • The UIELement passed to a Creation filter is a parent UIElement that has already been created by Infragistics logic, but it's children have not, so this is where you can prevent children from being created or add new children to the parent.
  • The UIElement passed to a draw filter is a UIElement that has not yet been drawn, so here is where you can customize the drawing of an element. Elements are drawn in phases, each of which you can take over to draw the element as you like. Draw filters can also be used to remove or add elements.

Introduction

Infragistics architecture includes a framework layer called the PLF, Presentation Layer Framework, which provides a way to customize a control beyond what the control's properties support. "Filters" are classes you write that implement two different interfaces and allow you to modify the controls. You should try to come up with a way to customize your control with creative use of the control's properties before heading down the road of writing filter classes, but sometimes you'll have no choice. In this article I present my experience dealing with a specification for UltraWinGrid behavior that I couldn't achieve using grid properties. I learned what I could about filters from forums and Infragistics documentation but it was a bit of a struggle, so I've put this article together to get what I learned down on paper and hopefully help some other coder starting out with Infragistics, Googling in desperation late at night.

UIElements and Filters

One of the concepts of the PLF is a UIElement object, (a class in the Infragistics.Win namespace), which Infragistics describes as a discreet area of a control. (Other software companies use the concept of a UIElement too and I think SAP is one of them.) So, for a grid, there are UIElements for cells, rows, splitter bars, summary lines, summary footers, data areas, captions, etc. It is these UIElements that you modify when customizing a control. The PLF allows you to intervene during the creation and the drawing of UIElements by providing two interfaces you can implement with a class you write yourself:
  1. IUIElementCreationFilter - allows you to modify, add new elements or remove exisitng elements from a control. (Say you want to add a button to the header cell of a grid.)
  2. IUIElementDrawFilter - allows you to change the way an element is drawn. (Say you want to change the appearance of a button.)
Infragistics controls have CreationFilter and DrawFilter properties, (not sure if ALL of them do), so once you've written your filter, you set the appropriate property of your control to your class name. Something like:

ultraWinGrid1.CreationFilter = myGridCreationFilter;
or
ultraWinGrid1.DrawFilter = myGridDrawFilter;

My UltraWinGrid Customization

First off I'll explain what modifications I needed to make to a grid.


The Offending Grid.
Our grid displays group by's and summaries, with summary values showing in cells in the group by rows as well as in summary footer rows. But the way the grid behaves under these conditions didn't match our specification in two ways:

  1. The totals show twice when the group by row is expanded, in the group by row and the summary footer row, resulting in a busy, hard to read grid. We couldn't eliminate the summaries in the group by row because then there would be no totals when the row is collapsed.
  2. A summary footer is made up of two rows, one for the caption and one for the total values, but our spec showed just one row, containing both the caption and summay values. The grid has a property to remove the caption row, but then caption is eliminated. We wanted to remove the caption row and put the caption text in the total values row, on the left end where there was room.
So, to achive the specified grid behavior we needed to eliminate the summary values in the group by row only when the row is expanded and show them when the row is collapsed. And we needed to eliminate the caption row of the summary footer and move the caption text down to the row containing the summary values.

Creative use of Properties First

Like I mentioned earlier, it's worth a shot to try to think of a way to use control properties to achieve your needs. I never found a way to tweak properties to eliminate the summary values in the group by row when it was expanded but in the Infragistics Forums I found a way to get a single row summary footer. Mike Salzman, an Infragistics employee who monitors the grid forum, had suggested to someone in an old post that they first eliminate the caption row, which is easy as there's a property to do just that:

//Here's the code you'd put in the grid's InitializeLayout event:
e.Layout.Override.SummaryFooterCaptionVisible = DefaultableBoolean.False;

Then, to get the caption in the values row, Mike suggested creating another summary, a dummy one, and set it's format property to the caption text. I could place this dummy summary in the left most column. I played with this idea and it worked fairly well, but I think I still would have needed to use a draw filter to elminate the border around my new caption text. It had a border because it is a summary value afterall and I'd set the appearence of the summary values so they had a border. Maybe there was a way to elminate the border on that one dummy summary value that I didn't pursue. (You'd be surprised how flexible these controls are if you really get to know them, which I don't.) I had to learn about filters anyway, so I decided to go ahead with a filter to see how it would work.

UIElements in Detail

Bear with me a bit here. I'd like to jump right into how to write the filters but as you'll see, a good understanding of UIElements and the structure of a control are important.

As I mentioned before, an Infragistics control is made up of UIElements. I think of them as building blocks of the control, like bricks in a wall. It is in creation and draw filters where you can access and manipulate UIElements to change the look and behavior of the control. The PLF will call methods in your filter class as it draws a control, passing you a UIElement object, giving you the opportunity to make your modifications. Keeping with the brick wall analogy, it's like you're standing next to the mason and he hands you each brick before mortaring it in, giving you an opportunity to change the brick somehow, or throw it away entirely or add another one and pass two bricks back to the mason.

The Inside your filters, you need to be able to make sure the UIElement you've received is the one you need to make your modifications. To do that you need to know how your control is built; what UIElements are involved and in what order and relationship to one another they exist. Sometimes you can identify a UIElement only by it's context; knowing what it's hierachy structure looks like. Using the brick wall analogy again, you need to have the architectural plan in front of you.

To get the plan for your control you use an Infragistics tool called the UIElementViewer, a little winforms application contained in a dll that you download, create a reference to, (add to your Visual Studio toolbox) and drag to the non-visible component tray of your form in the designer to instantiate it. Then you just call the UIElementViewer's Show() method in your form's load event, uiElementViewer1.Show();. It's wierd that you download this dll from a blogging site rather than the Infragistics site:

http://geekswithblogs.net/devin/archive/2005/11/17/60406.aspx

UIElement Viewer in Action


Fire up your application and you'll see the UIElement Viewer appear along with it. Check the "Follow Mouse" checkbox in the UIE Viewer form and watch the display area of the Viewer as you move your mouse over the Infragistics controls on your form in your application. The UIElements that your mouse pointer passes over will show in the UIE Viewer display area, revealing the UIElement structure of the control. I found that dragging the UIElement Viewer form over your application form so that it lies just next to the UIElement you want to investigate works best. That way your mouse goes directly from the control into the Viewer, where you can switch tabs, without moving across other elements that will change the Viewer reporting.

The viewer reveals the UIElements that make up the control and the hierarchy in which they exist. For the grid control, the top position of the hierarcy is occupied by an UltraGridUIElement. Some UIElements may exist on equal levels in the hierarchy, for example, all the RowUIElements would be at the same level and all the CellUIElements for a single row would be at the same level. The entire UIElement structure is revealed along with the hierarchical relationships between UIElements, which as you'll see in a bit, comes in handy to find the particular UIElement you want to manipulate in your filter classes. Also displayed is the X,Y position and size of an element, information you may need if you're adding new UIElements to a control without overlaying existing elements. Here's an example of what the Viewer can show you: In the above screen shot, I had my mouse over a summary value of a summary footer row. The value is a TextUIElement which is inside a SummaryValueUIElement.

See the tab in the UIElementVier UI labeled Hierarchy? Below is an example of what it displays when, for my specific grid, the mouse was on a summary line in a group by row. If the mouse had been over a value, not just whitespace in the summary line, there would be two more UIElements at the bottom of the hierarchy, a FixedSUmmaryValueUIElement and a TextUIElement. This information is similar to the info in the Element Tree Tab, but it seemed to allow copy and paste, which I found handy.

UltraGridUIElement, Location = {X=0,Y=0,Width=1124,Height=683}
  DataAreaUIElement, Location = {X=1,Y=1,Width=1122,Height=681} 
    RowColRegionIntersectionUIElement, Location = {X=1,Y=1,Width=1122,Height=664} 
      GroupByRowUIElement, Location = {X=16,Y=144,Width=1492,Height=21}
        SummaryFooterUIElement, Location = {X=31,Y=146,Width=1477,Height=18} 
          FixedSummaryAreaUIElement, Location = {X=31,Y=146,Width=1477,Height=18}
            FixedSummaryLineUIElement, Location = {X=31,Y=146,Width=1477,Height=18}

When I discuss how to write the filter classes, you'll see that knowledge of a control's UIElement structure is used to determine which particular UIElement object you are dealing with in your filter and therefore whether to enter your modification logic. You'll get the hang of this tool by playing around with it for a bit.

Creation or a Draw Filter?

I wish I could tell you that it's clear to me when to use a creation or draw filer, but frankly, I've not played around with these filters quite enough to understand the nuances involved but I think I have the basics down. If you're removing or adding a UIElement from or to a control, a creation filter is the place to do it. Also if you're changing the size of an existing element. If you're modifying the look of a UIElement, I'd think that would be done in a draw filter, where you have access to a Graphics object and other rendering tools. You might need to experiment a bit to determine where the best place for your code will be. I think it's safe to say that in a creation filter you add or remove elements and in a draw filter, you can change the way an element is drawn or rendered. But if You're changing the size of an element, I think that's best done in a creation filter.

In the example I present here, where I remove the top row of a summary footer, (where the summary caption is displayed), I use a simple property setting. I could have used a creation filter or a draw filter, but had I used a draw filter, I'd still have had a gap in the grid where the row I removed had been. A creation filter would eliminate it entirely. Also in my example, I eliminate the summary values in a group by row when it's expanded, which is a change to the way a UIElement appears depending on user actions. That's work for a draw filter.

I'll go out on a limb and take a stab at a set of guidelines (Sorry I can't be more authoritative.):

Creation Filter Draw Filter
Add an Element X
Remove an Element X
Resize an Element X
Modify an Element X
Respond to User X

Creation Filter

So let's get into how to write the filters, starting with a creation filter. There are two methods you must implement in a creation filter class. Both methods are passed a UIElement object, appropriately called parent. It's this parent's children UIElements that you'll be modifying in a creation filter.

The skeleton for your creation filter class will look something like this, (I call this filter SummaryRowCreationFilter, because it's modifying a summary row of an UltraWinGrid):

class SummaryRowCreationFilter : IUIElementCreationFilter
{
    public bool BeforeCreateChildElements(Infragistics.Win.UIElement parent)
    {
        return false;
    }
    public void AfterCreateChildElements(Infragistics.Win.UIElement parent)
    {
        return false;
    }
}

BeforeCreateChildElements Method

In the BeforeCreateChildElements method, the parent object is in a state where it has no children yet, so you have a chance to intervene and do one of the following:
  • Prevent child element(s) from being created
  • Modify child element(s) - Create the element yourself and then tell the PLF to skip creating it because you've already done it.
If you return false from BeforeCreateChildElements, you're saying, "I don't want to intervene. Go ahead and create the child elements as normal." Returning true says, "Skip any creation code for the child elements for this parent. I either created them myself, in my own way, or I just don't want them created at all."

BeforeCreateChildElements is called if the child elements of a UIElement are marked dirty, but I'm not exactly sure what that means. I put debug statements in my Creation filter which revealed that the method is called when Windows paints my grid for the first time, but also at other times, sometimes even just when switching from one application to another, forcing windows to repaint my Infragistics application. I never detected a firm pattern. You can be sure though, that the creation filter will be called when your control first appears on the screen and again when it's changed by user input to your control, assuming it supports some kind of user input. So, there's stuff going on here beyond my pay grade that I can't explain to you.

Identifying the UIElement Object Passed to Your Method

I mentioned before that when your BeforeCreateChildElements method is called, you need to identify whether it's being called for the UIElement you need to make your modifications; i.e., the parent UIElement object of the UIElement(s) you want to modify. There are a couple of ways of doing this.

In my example, where I wanted to add a caption to a summary value row, I determined from using the UIE Viewer that the UIElement I wanted to modify a FixedSummaryLineUIElement. I wanted to add text to it, so to be more accurate, I want to add a child to a FixedSummaryLineUIElement. In my BeforeCreateChildElements method I'd need to identify that the UIElement object I was passed was a FixedSummaryLineUIElement. One approach I could take is to check it's run type with the "is" operator.

// Checks if the element is a FixedSummaryLineUIElement 
if (parent is FixedSummaryLineUIElement) .......

But there may be many instances of a particular UIElement type in a control and you need to isolate the individual one(s) you're interested in to effect your modifications. In my grid, a FixedSummaryLineUIElement exists in summary rows and in group by rows, (the gird has been initialized with the following property setting: SummaryDisplayArea |= SummaryDisplayAreas.InGroupByRows). But I could distinguish between the two by looking at each element's surroundings or context; it's place in the UIElement hierarchy of the control. For example, consider this hierarchy that the UIElement Viewer produced when the mouse was on a summary value line in a group by row. The hierarchy includes a GroupByRowUIElement, which distinguishes it from a summary line in a summary footer row.

UltraGridUIElement, Location = {X=0,Y=0,Width=1124,Height=683}
  DataAreaUIElement, Location = {X=1,Y=1,Width=1122,Height=681} 
    RowColRegionIntersectionUIElement, Location = {X=1,Y=1,Width=1122,Height=664} 
      GroupByRowUIElement, Location = {X=16,Y=144,Width=1492,Height=21}
        SummaryFooterUIElement, Location = {X=31,Y=146,Width=1477,Height=18} 
          FixedSummaryAreaUIElement, Location = {X=31,Y=146,Width=1477,Height=18}
            FixedSummaryLineUIElement, Location = {X=31,Y=146,Width=1477,Height=18}

Each UIElement class has a GetContext method that you can call to determine if another particular UIElement is in it's hierarchy. The GetContext() method will work it's way up the element's hierarchy looking for the object type it has been passed as a parameter. It returns null if the object isn't found. I used the following line of code to look for a FixedSummaryLineUIElement in a summary footer row, distinguishing it from one in a group by row. First I check if it's a FixedSummaryLineUIElement. If so, I look at it's context; check if it's a child of an UltraGridGroupByRow. If I got a row object back, I'd get out, because I'd know that this FixedSummaryLineUIElement is in a group by row.

if (parent is FixedSummaryLineUIElement)
   UltraGridGroupByRow row = parent.GetContext(typeof(UltraGridGroupByRow)) as UltraGridGroupByRow;

UIElements and Control Objects

Notice too that the GetContext method will give you a reference to the control object associated with the UIElement object. (They are separate objects.) For example, say you want to change some property of a cell. The GetContext method will give you the UltraGridCell object from it's associated CellUIElement object. Or you may need to further identify the UIElement object your filter has received by looking at a property of the underlying control object, it's text, for example. Here's the GetContext() method again, looking for an UltraGridCell object this time:

UltraGridCell cell = parent.GetContext(typeof(UltraGridCell)) as UltraGridCell;

Now, let's say you want to add a button to all cells in a particular column. You can get the cell object with GetContext and then look at it's key property, telling you which column it's in.

My BeforeCreateChildElements method just returned false, as there was nothing I needed to do there:
public bool BeforeCreateChildElements(Infragistics.Win.UIElement parent)
{
    return false;
}

AfterCreateChildElements Method

In AfterCreateChildElements, the parent the parent UIElement object's children objects have already been created. so you have a chance to intervene and do one of the following:
  • Create new child element(s)
  • Modify existing child element(s)
This is where you can add new element(s) to the parent, but you need to be careful not to overlay existing elements by using the location data of the children to make sure you know where to place and size your new element. You can also modify an existing child. So, in the AfterCreateChildElements method, you'll often see code to get the rect of the parent and the location and rects of it's children. Something like this, (code out of an Infragistics example that moves the existing children over a bit to make room for a new button element):
// loop over the child elements and adjust their
// rects so they don't overlap the button
foreach ( UIElement child in parent.ChildElements )
{
    Rectangle childRect = child.Rect;
    if ( childRect.Left < rect.Right )
    {
        childRect.Width -= rect.Right - childRect.Left;
        childRect.X     += rect.Right - childRect.Left;
        child.Rect = childRect;
    }
}

Here's my AfterCreateChildElements method to add a TextUIElement, (which will contain summary caption text), to a FixedSummaryLineUIElement that is part of a summary row. This code is how I got my summary footer caption to appear in the summary footer row that contains the summary values. I've included Debug statements to produce a trace and document the code.

public void AfterCreateChildElements(Infragistics.Win.UIElement parent)
{
    //Debug.WriteLine("UI type is " + parent.GetType().ToString());
    // if the parent element is not a Fixed Summary line element return
    if (!(parent is FixedSummaryLineUIElement))
    {
        //parent is not a FixedSummaryLineUIElement, so return
        return;
    }
    //Debug.WriteLine("Got a FixedSummaryLineUIElement **");
    // If the UIElement has a group by row up it's hierarchy,
    // get out, because that means we're on a group by row.
    // The GetContext method will call up the hierarchy chair of the element
    // looking for the type in the argument passed.
    UltraGridGroupByRow gbrow = parent.GetContext(typeof(UltraGridGroupByRow))
            as UltraGridGroupByRow;
    if (gbrow != null)
    {
        //We're on a group by row, so return
        return;
    }
    // If we've gotten this far, we have a summary row that's not
    // part of a group by row.
    // Two possible types of summary row exist:
    // 1. Associated with a collection of rows which has a parent row of
    // a GroupbyRow type.
    // 2. A summary row not associated with a collection of group by rows
    //    - in other words, the grand summary row for the whole grid.
    string strCaption = "";
    RowsCollection rows = parent.GetContext() as RowsCollection;
    UltraGridGroupByRow row = (UltraGridGroupByRow)rows.ParentRow;
    if (row == null)
    {
        // The grand summary row
        strCaption = "Total Project";
    }
    else 
    {
        //Adding text element to : " + parent.GetType().ToString()
        //Playing with getting the column's key property
        //string strKey = row.Column.Key.ToString();
        //Debug.WriteLine("Key : " + strKey);
        string strDescription = row.Description.ToString();
        int endPos = strDescription.IndexOf(":");
        if (endPos != -1)
            strDescription = strDescription.Substring(0, endPos);
        strCaption = " Total " + strDescription;
    }
    
    // Create a text element.  Constructor accepts the text
    // property of the TextUIElement.
    // This test element will be placed on top of the parentUIE
    // and will contain the caption.
    TextUIElement elementToAdd = new TextUIElement(parent, strCaption);
    
    // get the rect of the parent element inside its borders,
    // so we know where to place the TextUIE
    Rectangle rect = parent.RectInsideBorders;
    
    // set the width of the txt rectangle rect
    //All other members, x,y and height are the same as the parent
    rect.Width = 250;
    
    //  Hopefully this will be long enough
    rect.X += 2;
    rect.Y += 2;
    
    // set the text element's rect
    elementToAdd.Rect = rect;
    
    // append the button element to the
    // child elements collection
    parent.ChildElements.Add(elementToAdd);
}

OK, so far I've eliminated the caption row of the summary footer row, using a property, and put a new caption text in the summary footer values row using a creation filter. I still have to make the summary values on a group by row disappear and reappear as the row is expanded and collapsed. I'll use a draw filter for that.

Draw Filter

As in a creation filter, there are two methods you must implement in a draw filter class, GetPhasesToFilter() and DrawElement(), but that's where the similarities with a Creation Filter end. A UIElement is drawn in phases, such as BeforeDrawElement, BeforeDrawForeground, BeforeDrawBorders, etc. In the GetPhasesToFilter method, you tell the PLF which draw phase and for which UIElement you want to modify. Then in the DrawElement method, you actually do the drawing. (As you'll see though, you can also add or remove elements.) To see all the draw phases, here's a link to the drawPhases Enumeration.

Here's a skeleton of a Draw Filter class:

class GroupByRowSummaryDrawFilter : IUIElementDrawFilter
{
    public Infragistics.Win.DrawPhase GetPhasesToFilter
                 (ref Infragistics.Win.UIElementDrawParams drawParams)
    {
    }
    public Infragistics.Win.DrawPhase DrawElement
                 (Infragistics.Win.DrawPhase drawPhase, 
                 ref Infragistics.Win.UIElementDrawParams drawParams)
    {
    }
}

GetPhasesToFilter Method

The GetPhasesToFilter method is passed a structure of type Infragistics.Win.UIElementDrawParams, which includes a member called Element, the UIElement currently being processed. Using the same techniques as we used in the creation filter to identify which element you've got, you identify your element and return the value of the drawing phase that you want to filter. Something like:
if (drawParams.Element is TextUIElement)
    return Infragistics.Win.DrawPhase.BeforeDrawForeground;

DrawElement Method

The second method you implement, DrawElement, which is also passed a UIElementDrawParams struct, is where you do the actual modification. The UIElementDrawParams structure, besides the UIElement object, also contains the corresponding control object and AppearanceData object for the element, and properties and methods you use to modify the drawing of the element, things like Graphics and DrawBorders.

You can draw the phase, such as drawBorders, yourself and then return the value true to tell the PLF that you've done the drawing and it should skip it, because you've already taken care of it. Or you can just return true if you want to skip the drawing of the phase entirely. As I mentiioned earlier, this will still leave a space in your control where this element would have displayed. If you want to eliminate an element entirely, you'd use a creation filter. In my example, I did the identification of the UIElement I wanted to modify mostly in the DrawElement method, but I probably should have done more of it in the GetPhasesToFilter method. The way I did it adds unnecessary calls to DrawElement.

Here's the UIElement Hierarchy I was looking at for my Draw filter. The last line, the FixedSummaryLineUIElement, is what I was looking for, but only if it was associated with a group by row, so I'd look for the group by row in the drawElement method. (Like I said, I should have looked for the Group By in the GetPhasesToFilter method.) Note that my filter is pretty boring; it doesn't render or draw anything, so it doesn't use the Graphics class and pens and such fun stuff. I just use it to check if a group by row is expanded and if so, tell the PLF to skip the drawing of the FixedSummaryLineUIElement element.

UltraGridUIElement, Location = {X=0,Y=0,Width=1284,Height=559} 
  DataAreaUIElement, Location = {X=1,Y=1,Width=1282,Height=557} 
    RowColRegionIntersectionUIElement, Location = {X=1,Y=1,Width=1282,Height=540}
      GroupByRowUIElement, Location = {X=16,Y=144,Width=1507,Height=21}
        SummaryFooterUIElement, Location = {X=46,Y=146,Width=1477,Height=18}
          FixedSummaryAreaUIElement, Location = {X=46,Y=146,Width=1477,Height=18}
            FixedSummaryLineUIElement, Location = {X=46,Y=146,Width=1477,Height=18}

Here's the draw filter I wrote to make the summary values disappear when the group by row was expanded. Unfortunately, the hierarchy I show above doesn't go quite deep enough and I don't have time to re-create it now. There would have been a SummaryValueUIElement and a SummaryFooterCaptionUIElement at the bottom. Also, I don't have the time now but the GetPhasesToFilter method needs to be revisited to see exactly what UIElement to call DrawElement for. It may well be that SummaryValueUIElement and SummaryFooterCaptionUIElement aren't both needed.

public Infragistics.Win.DrawPhase GetPhasesToFilter
                    (ref Infragistics.Win.UIElementDrawParams drawParams)
{
    // Grab a textUIElement to prevent it's drawing
    if (drawParams.Element is TextUIElement)
        return Infragistics.Win.DrawPhase.BeforeDrawForeground;
    else if (drawParams.Element is SummaryValueUIElement)
        return Infragistics.Win.DrawPhase.BeforeDrawBorders;
    else if (drawParams.Element is SummaryFooterCaptionUIElement)
        return Infragistics.Win.DrawPhase.BeforeDrawElement;
    else
        return Infragistics.Win.DrawPhase.None;
}

public bool DrawElement(Infragistics.Win.DrawPhase drawPhase,
        ref Infragistics.Win.UIElementDrawParams drawParams)
{
    // If the UIElement doesn't have a group by row up it's hierarchy,
    // get out.  The GetContext method will call up the hierarchy
    // chair of the element looking for the type in the argument passed.
    UltraGridGroupByRow row = drawParams.Element.GetContext
        (typeof(UltraGridGroupByRow)) as UltraGridGroupByRow;
    if (row == null)
    {        
        return false;
    }     
    // OK, so we're in the context of a group by row,
    // but we need to deal with expaneded rows only
    if (row.Expanded == false)
    {
        return false;
    }    
    else
    {        
        // Groupby row is in an expanded state.
        // Return true to prevent the element from drawing its borders
        //  normally. Returning true will tell the grid that this
        // particular UIElement has already been drawn here, in the
        // DrawElement method.  In this case however, we don't
        // want the UIElement to be drawn at all, so we just return
        // true without actually drawing anything.
        return true;
    }
}

Before and After

The before, again.
The result: One row summary footer with caption and the summary values in an expanded group by row are gone.
By the way, this customization caused problems when exporting the grid to Excel. The caption text in the groupby values row wasn't showing up in the .xls, so I had to use the SummaryRowExporting event of the excelExporter object to add it.
e.CurrentWorksheet.Rows[e.CurrentRowIndex].Cells[0].Value = " Labor Totals";
e.CurrentWorksheet.Rows[e.CurrentRowIndex].Cells[0].CellFormat.Font.Bold =
                 Infragistics.Excel.ExcelDefaultableBoolean.True;
e.CurrentWorksheet.Rows[e.CurrentRowIndex].Cells[0].CellFormat.Font.Height =
                                                 165;  // in twips

Links

Creation Filter
Draw Filter
DrawPhase Enumeration
howtoCreate Custom Row Expansion Indicators in WinGrid with Creation Filters
IUIElementDrawFilter Interface
Looking to change text appearance in cell in ColumnStyle.URL Column - Infragistics Forums
Summary Section Too Small - Infragistics Forums

Click a star

Comments

Add your comment: