Hi,
I have a use case which is explained as follows:
"I have a UltragGrid which has some 10 column. But I need two types of sorts for these columns. i.e Some columns need default sorting provided by UltraGrid, and some other columns requires Three Way Sorting."
Three Way Sorting in my point of view is:
a. Ascendiing -Indicated by default ascending SortIndicator.
b. Descending- Indicated by default descending SortIndicator.
c. Absolute Descending: shoudl be indicated by a + sign.
I am new to the Infragistics. Can anyone help me in getting this with a nice example.
Thanks very much in advance.
Sanjeev.
Hi Sanjeev,
There's nothing like this built-in to the grid.
There are basically three issues here:
1) Sorting the grid in a custom order - this is very easy to do. You just need to write a custom IComparer class and assign it to the SortComparer property of the column.
2) Showing a plus sign - this is a little more difficult. You would have to use a CreationFilter or a DrawFilter to replace the existing sort indicator in the column header with a different image.
3) Toggling the sorting three ways - To do this, you would have to handle the events of the grid like BeforeSortChanged. When going from Ascending to Descending, there would be no problem - you can just do nothing and let the grid handle it. But the transition from Descending to Absolute Descending would require you to prevent the SortIndicator property on the column from changing and instead just attach the SortComparer. You would also have to handle the transition from Absolute Descending to Ascending and remove the SortComparer.
None of this is trivial, especially if you are new to the grid, but it should all be possible, I think.
Hi Mike, I tried out this. Unfortunately I haven't succeeded. 1. Sorting the grid in a Custom order I wrote following Comparer where it is valid only for absolute descending sorting. But I found that this is not at all called even if I set SortComaparer to the column. private class MySortComparer : IComparer { internal MySortComparer() { } int IComparer.Compare(object x, object y) { UltraGridCell xCell = (UltraGridCell)x; UltraGridCell yCell = (UltraGridCell)y; double value1 = Double.Parse(xCell.Value.ToString()); double value2 = Double.Parse(yCell.Value.ToString()); return (Int32)(Math.Abs(value1) - Math.Abs(value2)); }}3. Toggling the sort:Here is the code for setting this sort comparer.private void ultraGrid_BeforeSortChange(object sender, Infragistics.Win.UltraWinGrid.BeforeSortChangeEventArgs e){ if (!(e.SortedColumns[0].Key.Equals("Value"))) { // // I want this kind of sorting for only "Value" column. // return; } // // I am sure that I have single column sorting // UltraGridColumn column = e.SortedColumns[0]; SortIndicator indicator = column.SortIndicator; // // Moving from Descending to Ascending. Here we need to move to AbsoluteDescending. // if (indicator == SortIndicator.Ascending) { MySortComparer sortComparer = new MySortComparer(); column.SortComparer = sortComparer; //column.SortIndicator = SortIndicator.None; // // If I uncomment the above statement, I am getting Exception where it is saying that we can't change // SortIndicator in BeforeSortChage Event // } // // Moving from Ascending to descending. We won't need any customization here // else if (indicator == SortIndicator.Descending) { Console.WriteLine("going from ascending to descending "); } // // Assuming that we should come from absolute descending to ascending. // else { // // Need to remove SortComparer. // column.SortComparisonType = SortComparisonType.Default; //column.SortIndicator = SortIndicator.Ascending; }}2. Showing a Plus Sign: I have written a DrwaFilter class to draw + Symbol. Instead of getting through an image, I am just drawing the + symbol. But I have obderved that it is drawing every time even if column is in ascending mode or descending mode. public class Sort_Order_Indicator_DrawFilter : IUIElementDrawFilter { #region IUIElementDrawFilter Members bool IUIElementDrawFilter.DrawElement(DrawPhase drawPhase, ref UIElementDrawParams drawParams) { if (drawPhase == DrawPhase.AfterDrawElement) { HeaderUIElement headerUIElement = drawParams.Element as HeaderUIElement; if (headerUIElement != null) { UltraGridColumn column = drawParams.Element.GetContext(typeof(UltraGridColumn)) as UltraGridColumn; using (Font font = new Font("Arial", 14)) { using (SolidBrush solidBrush = new SolidBrush(Color.Black)) { StringFormat stringFormat = new StringFormat(); stringFormat.Alignment = StringAlignment.Far; stringFormat.LineAlignment = StringAlignment.Near; DrawStringParameters drawStringParameters = new DrawStringParameters( drawParams.Graphics, "+", font, solidBrush, headerUIElement.Rect, stringFormat, GdiDrawStringFlags.GDIPlus, TextOrientationInfo.Horizontal); // Draw the string. DrawUtility.DrawString(ref drawStringParameters); } } } } return false; } DrawPhase IUIElementDrawFilter.GetPhasesToFilter(ref UIElementDrawParams drawParams) { // Trap for a HeaderUIElement if (drawParams.Element is HeaderUIElement) { UltraGridColumn column = drawParams.Element.GetContext(typeof(UltraGridColumn)) as UltraGridColumn; if (column != null && (column.SortIndicator == SortIndicator.Ascending || column.SortIndicator == SortIndicator.Descending)) { return DrawPhase.AfterDrawElement; } } // Do nothing. return DrawPhase.None; } But I am thinking that I should have one more value for SortIndicator enum which tells about the status of absolute sorting. With the help of this, in GetPhasesToFilter we will return true only incase of Absolute Sorting mode so that it will draw + sign. I tried alot to get this. Can you please tell me (if possible a small example) to get this done. Thanks very much. Sanjeev.
I'm not sure I understand your question.
The SortComparer only gets called if the SortIndicator on the column is Ascending or Descending. So you need to set the SortIndicator to Descending regardless of whether you want Descending or Absolute Descending (or whatever custom order you want).
You will need to keep track of what kind of sorting you want and then sort accordingly with some member variable or your own, whether that be on the column or the SortComparer or wherever. So to programmatically set the sort order to you would set the SortIndicator and then also set whatever member variable that you are using and then you may have to call band.SortedColumns.Refresh to tell the grid to re-sort, since the SortIndicator may not have changed.
Hi Mike,
I have requirement as follows:
1. I have two different types columns based on sorting. Three way sorting columns, and normal sorting columns.
Three way sorting columns: Absolute descending(+ Custom Icon), descending and ascending order.
Normal sorting columns: Descending and ascending.
2. Sortindicator should be displayed on left hand side of the columns.
3. Sorting order should be for
a. normal columns: Descending and followed by ascending.
b. Three way sorting columns: Absolute descending and descending and ascending.
I have done all the tasks expect 3 b. Where I am getting descending order first followed by absolute descending and ascending order.
Please have a look at the code(Removed some piece of code) and suggest me how should I get this done. Please let me know if didn't understand the requirement.
namespace Test{ public partial class GridPanel : UltraGridBagLayoutPanel { /// <summary> /// An enum which represents the different states of /// three way sorting /// </summary> public enum SORT_STATE { NONE = 0, ASCENDING, DESCENDING, CUSTOM }; #region Static Variables /// <summary> /// Represents the last cached state of a three way sort /// </summary> private static SORT_STATE mySortState; private delegate void SortColumnDescendingDelegate(UltraGridColumn column); #endregion #region Member Variables private GridDataModel myGridModel; private string myLastSortedColumn = null; private List<string> myThreeWaySortColumns; private Map<String, ColumnInfo> myColumnNameToColumnInfoMap; private Map<ColumnInfo, UltraGridColumn> myColumnInfoToGridColumnMap; private UltraGridColumn myFilterColumn = null; #endregion #region Internal classes /// <summary> /// Implements the sort specific to the sort state /// </summary> private class GridSortComparer : IComparer { /// <summary> /// CTOR /// </summary> internal GridSortComparer() { } int IComparer.Compare(object x, object y) { UltraGridCell xCell = (UltraGridCell) x; UltraGridCell yCell = (UltraGridCell) y; double text1 = Convert.ToDouble(xCell.Value.ToString()); double text2 = Convert.ToDouble(yCell.Value.ToString()); if (mySortState == SORT_STATE.CUSTOM) { text1 = Math.Abs(text1); text2 = Math.Abs(text2); if (text2 < text1) { return -1; } else if (text2 > text1) { return 1; } return 0; } if (text1 > text2) { return 1; } else if (text1 < text2) { return -1; } else { return 0; } } } /// <summary> /// Draws the SortIndicator icon to the left of the column name /// </summary> public class SortIndicatorOnLeftCreationFilter : IUIElementCreationFilter { #region IUIElementCreationFilter Members void IUIElementCreationFilter.AfterCreateChildElements(UIElement parent) { HeaderUIElement headerUIElement = parent as HeaderUIElement; if (headerUIElement != null) { SortIndicatorUIElement sortIndicatorUIElement = headerUIElement.GetDescendant(typeof(SortIndicatorUIElement)) as SortIndicatorUIElement; if (sortIndicatorUIElement != null) { // // Change the location of the sortIndicatorUIElement so that it's // on the left side of the headerUIElement. // sortIndicatorUIElement.Rect = new Rectangle( headerUIElement.RectInsideBorders.Left, sortIndicatorUIElement.Rect.Top, sortIndicatorUIElement.Rect.Width, sortIndicatorUIElement.Rect.Height); TextUIElement textUIElement = headerUIElement.GetDescendant(typeof(TextUIElement)) as TextUIElement; if (textUIElement != null) { // // Move The TextUIelement to the right of the sortIndicatorUIElement. // textUIElement.Rect = new Rectangle( sortIndicatorUIElement.Rect.Right, textUIElement.Rect.Top, textUIElement.Rect.Width, textUIElement.Rect.Height); } } } } bool IUIElementCreationFilter.BeforeCreateChildElements(UIElement parent) { // Do nothing. return false; } #endregion } /// <summary> /// Used a DrawFilter for table to draw /// a + Icon for absolute sort /// </summary> public class AbsoluteSortIndicatorDrawFilter : IUIElementDrawFilter { private GridPanel myGridPanel; /// <summary> /// CTOR /// </summary> public AbsoluteSortIndicatorDrawFilter(GridPanel gridPanel) { myGridPanel = gridPanel; } #region IUIElementDrawFilter Members bool IUIElementDrawFilter.DrawElement(DrawPhase drawPhase, ref UIElementDrawParams drawParams) { if (drawPhase == DrawPhase.AfterDrawElement) { HeaderUIElement headerUIElement = drawParams.Element as HeaderUIElement; if (headerUIElement != null) { UltraGridColumn column = drawParams.Element.GetContext(typeof(UltraGridColumn)) as UltraGridColumn; // // If it is not a threey way sort column // if (!(myGridPanel.IsThreeWaySortColumn(column.Key))) { return false; } if (mySortState == SORT_STATE.CUSTOM) { column.SortIndicator = SortIndicator.None; Rectangle rect = headerUIElement.Rect; rect.Inflate(+1, -1); rect.Offset(-2, 0); // // Creating a new rectangle // with some size to draw this icon // Rectangle newRect = new Rectangle( new Point(headerUIElement.Rect.Left, (rect.Y + rect.Height / 3)), new Size((rect.Width / 2 + rect.Width / 4), (rect.Height / 2 + rect.Height / 4))); ImageAttributes imageAttr = new ImageAttributes(); ColorMap[] colorMap = new ColorMap[1]; colorMap[0] = new ColorMap(); colorMap[0].OldColor = Color.White; colorMap[0].NewColor = Color.White; imageAttr.SetRemapTable(colorMap); System.Resources.ResourceManager RM = new System.Resources.ResourceManager("UI.Resources", GetType().Assembly); Object obj = RM.GetObject("plusIcon"); using (Bitmap bmp = (Bitmap) obj) { drawParams.Graphics.DrawImage( bmp, newRect, 0, 0, newRect.Width, newRect.Height, GraphicsUnit.Pixel, imageAttr ); } return true; } } } return false; } DrawPhase IUIElementDrawFilter.GetPhasesToFilter(ref UIElementDrawParams drawParams) { if (drawParams.Element is HeaderUIElement) { // // Get the column. // UltraGridColumn column = drawParams.Element.GetContext(typeof(UltraGridColumn)) as UltraGridColumn; if (!myGridPanel.IsThreeWaySortColumn(column.Key) || myGridPanel.myLastSortedColumn == null || !myGridPanel.myLastSortedColumn.Equals(column.Key)) { return DrawPhase.None; } return DrawPhase.AfterDrawElement; } return DrawPhase.None; } #endregion } #endregion /// <summary> /// CTOR /// </summary> public GridPanel() : base(TITLE) { Initializae(); } private void Initialize() { myThreeWaySortColumns = new List<string>(); InitializeComponent(); myGridModel = new PositionDataModel(); this.myUltraGrid.DataSource = myGridModel; this.myUltraGrid.BeforeSortChange += new BeforeSortChangeEventHandler(HandleBeforeSortChange); this.myUltraGrid.CreationFilter = new SortIndicatorOnLeftCreationFilter(); } #region Public Methods /// <summary> /// Handles this event to set descending order first /// </summary> private void HandleBeforeSortChange(object sender, BeforeSortChangeEventArgs e) { if (e.SortedColumns.Count == 0) { return; } UltraGridColumn sortetColumn = e.SortedColumns[0]; if (myLastSortedColumn == null || !myLastSortedColumn.Equals(sortetColumn.Key)) { myLastSortedColumn = sortetColumn.Key; mySortState = SORT_STATE.NONE; } if (IsThreeWaySortColumn(e.SortedColumns[0].Key)) { SortIndicator indicator = sortetColumn.SortIndicator; if (mySortState == SORT_STATE.NONE) { mySortState = SORT_STATE.CUSTOM; } else if (mySortState == SORT_STATE.CUSTOM) { mySortState = SORT_STATE.DESCENDING; } else if (mySortState == SORT_STATE.DESCENDING) { mySortState = SORT_STATE.ASCENDING; } else if (mySortState == SORT_STATE.ASCENDING) { mySortState = SORT_STATE.CUSTOM; } } // // Iterate through the new SortedColumns and see if there is a new column in there // that did not exist in the original sorted columns. This will tell us if a // column is being sorted for the first time. // foreach (UltraGridColumn column in e.SortedColumns) { if (e.Band.SortedColumns.Exists(column.Key) == false) { // // We found a new column. Cancel the change. // e.Cancel = true; // // Now we want to sort the column descending. But we cannot change the // SortedColumns collection inside this event. So we will do it // by invoking another method. // this.BeginInvoke( new SortColumnDescendingDelegate( this.SortColumnDescending), new object[] { e.Band.Columns[column.Key] }); } } } /// <summary> /// This will clear old sort apply new sort /// </summary> private void SortColumnDescending(UltraGridColumn column) { // // Disable the BeforeSortChange event to avoid recursion. // this.myUltraGrid.EventManager.SetEnabled(GridEventIds.BeforeSortChange, false); try { // // Sort the specific column descending. // column.Band.SortedColumns.Clear(); column.Band.SortedColumns.Add(column, true); } finally { // //Re-enabled the BeforeSortChange event. // this.myUltraGrid.EventManager.SetEnabled(GridEventIds.BeforeSortChange, true); } } #endregion private bool IsThreeWaySortColumn(string columnName) { return myThreeWaySortColumns.Contains(columnName); } #endregion }}
Thanks,
Sanjeev
I'm still not sure what you are asking. The code you posted here seems to already be handling the 3-way sorting.
Of course, it's impossible to tell from a code snippet like this whether this is actually working correctly or not - especially such a long code snippet.
If it's not working, then what exactly is the problem? What part of this is giving you trouble?
Yes you are right, I had already implemented Three Way sorting. But the problem here is I need to get AbsoluteDescending order for the first time I click on the column header.
Instead I am getting descending order first then followed by AbsoluteDescening order.
Is there a way to get Absolute descending order first with out either ascending or descending.I know that by default it will be set to ascending and a there is another way to set descending order first as well. But I didn't find any way to set our own sort for the first time.
I think what you will have to do is trap the BeforeSortChange event and trap for when the column goes from no sorting to some sorting. Then you can cancel the event and set the SortIndicator to whatever you want, and also set up your CreationFilter and SortComparer to do that it needs to do to sort AbsoluteDescending.