In my previous post I have asked for excel-like functionlity for column grouping and hiding (not possible). Below there is a solution which almost works, problems are described at the bottom. NA2010 vol 3 was used.
Step 1: Create and assign creation filter
MyGridFilter filter = new MyGridFilter();
private void Form1_Load(object sender, EventArgs e){ m_gridVariant.CreationFilter = filter;}
Step 2 : filter implementation
public class MyGridFilter : IUIElementCreationFilter { public void AfterCreateChildElements(UIElement parent) { HeaderUIElement header = parent as HeaderUIElement; if (header != null && header.Header.Column == null) //this will ensure its a group header { //region remove old instances (if present) foreach (UIElement e in header.ChildElements) { if (e is MyCheckboxUIElement) header.ChildElements.Remove(e); } //create new element MyCheckboxUIElement ele = new MyCheckboxUIElement(header); //gather group columns so that you know what to hide foreach (UltraGridColumn col in header.Header.Group.Columns) ele.AddColumn(col); //add to child elements header.ChildElements.Add(ele); } }
public bool BeforeCreateChildElements(UIElement parent){ return false; } }
Step 3 : Implement my checkbox so that it could do the hiding job
public class MyCheckboxUIElement : CheckBoxUIElement { public MyCheckboxUIElement(UIElement parent) : base(parent) { //set checkbox rectangle int x, y, w, h; w = 20; h = parent.RectInsideBorders.Height - 2; x = parent.RectInsideBorders.Right - 22; y = parent.RectInsideBorders.Y + 2; this.Rect = new Rectangle(x, y, w, h); //base.ButtonStyle = UIElementButtonStyle.WindowsVistaButton; //how? base.CheckState = System.Windows.Forms.CheckState.Unchecked; base.ThreeState = false; base.ButtonType = UIElementButtonType.Toggle; //have no effect on appearance } protected override void OnCheckStateChange() { base.OnCheckStateChange(); if (base.CheckState == System.Windows.Forms.CheckState.Checked) foreach (UltraGridColumn col in myColumns) col.Hidden = true; else foreach (UltraGridColumn col in myColumns) col.Hidden = false; }
}
Problems/Questions:
#1 When using base.IsChecked instead of base.CheckState it always returns false value. Checkbox acts properly - one mouse click makes it "checked", why IsChecked doe not work?
#2 Implementation above works, but following things are happening:
a.) when user clicks checkbox for the first time columns become hidden, but checkbox is turned back to unchecked state after it was handled. OnCheckStateChange is not triggered
b.) When columns are still hidden, checkbox is still unchecked, user clicks on it it changes from unchecked to checked (code has no effect, columns are already hidden)
c.) unchecking the checkbox causes column to appear just fine.
What and why is happenning in 2a, that causes checkbox to uncheck on it's own after columns are hidden. Are there any events I could handle?
dynacon8 said:Any hints what should I change to make my checkbox not to cover header text after column removal:
Well, the group doesn't know about your CreationFilter or the CheckBox, so it looks like it is auto-sizing it's width based on the caption.
There's no MininumWidth on a Group, but there is a Width property. So you could set it to some reasonable value that will fit any of your group's text with the checkbox added in.
It works as a charm MIke, thanks a lot!!!
Complete implementation below for future use by others :)
public class MyGridFilter : IUIElementCreationFilter { public void AfterCreateChildElements(UIElement parent) { HeaderUIElement header = parent as HeaderUIElement; if (header != null && header.Header.Column == null) //this will ensure its a group header { #region remove old instances (if present) foreach (UIElement e in header.ChildElements) { if (e is MyCheckboxUIElement) header.ChildElements.Remove(e); } #endregion //create new element and copy columns MyCheckboxUIElement ele = new MyCheckboxUIElement(header, header.Header.Group.Columns); //add it to child elements header.ChildElements.Add(ele); } } public bool BeforeCreateChildElements(UIElement parent) { //nothing to do in here return false; } } public class MyCheckboxUIElement : CheckBoxUIElement { private List<UltraGridColumn> myColumns = new List<UltraGridColumn>(); public MyCheckboxUIElement(UIElement parent, GroupColumnsCollection col) : base(parent) { //set checkbox rectangle at the right side int x, y, w, h; w = 15; h = parent.RectInsideBorders.Height - 2; x = parent.RectInsideBorders.Right - 17; y = parent.RectInsideBorders.Y + 2; this.Rect = new Rectangle(x, y, w, h); this.ButtonState = UIElementButtonState.MouseDown; base.ThreeState = false; //keep the colums (used tag, because some of the colums are already hidden) myColumns.AddRange( col.Where(column => column.Tag != null) ); if (myColumns.Count > 0 && myColumns[0].Hidden == true) //hidden, uncheck base.CheckState = System.Windows.Forms.CheckState.Unchecked; else base.CheckState = System.Windows.Forms.CheckState.Checked; } protected override void OnCheckStateChange() { base.OnCheckStateChange(); if (base.CheckState == System.Windows.Forms.CheckState.Checked) { foreach (UltraGridColumn col in myColumns) col.Hidden = false; } else if (base.CheckState == System.Windows.Forms.CheckState.Unchecked) { foreach (UltraGridColumn col in myColumns) col.Hidden = true; } } }
Any hints what should I change to make my checkbox not to cover header text after column removal:
Hi,
I'm not sure why IsChecked it not working. But it's not a good idea to rely on the checked state of the UIElement, anyway.
A UIElement is a transitory object, so you should never use it to store information that needs to persist. In this case, you should really be setting the CheckState of your derived CheckBoxUIElement based on the current state of the columns in the group rather than the other way around.
So, in the constructor for your derived element, you have this line of code:
base.CheckState = System.Windows.Forms.CheckState.Unchecked;
This makes the assumption that the checkbox is unchecked and that all of the columns are currently visible. You appear to be assuming that the CreationFilter only fires the first time the grid is displayed and then you are relying on the check state to determine whether to make the columns visible or not. But this is a bad assumption. The CreationFilter will get called many many time for all sorts of reasons. And it is almost certainly getting called at some point after the columns have been hidden and then you are setting it's CheckState back to Unchecked.
Anyway... what you should be doing, instead, is to set the CheckState based on the current visibility of the columns. So check the first column in the collection (if there is one) and use it's Hidden property to determine whether the UIElement's CheckState should be checked or unchecked.