View previous topic :: View next topic |
Author |
Message |
Mrdec
Joined: 04 May 2006 Posts: 7
|
Posted: Thu Apr 30, 2009 7:51 am Post subject: UniversalEditBox in spanned row flickers |
|
|
Hello,
I need to show a little button with ellipsis [...] in a spanned row and I want the button to be allways visible. So I created a UITypeEditor and assigned it to CellData (of the spanned row) and I also set CellData.DisplayMode to Always visible.
It works, but... when I'm clicking on rows (changing focused row) the editor in the spanned row flickers. It's because there is invoked the UniversalEditBox.OnLayout two-times. First with the width of the first column (bad) and for second with the width of the spanned row (good).
Is it possible to fix it? This is simple example, which demonstrates the situation:
Code: |
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Width = 250;
Height = 300;
// create tree
VirtualTree tree = new VirtualTree();
Controls.Add(tree);
tree.Dock = DockStyle.Fill;
tree.AutoFitColumns = true;
// add two columns
tree.Columns.Add(new Column());
tree.Columns[0].Caption = "Name";
tree.Columns.Add(new Column());
tree.Columns[1].Caption = "Value";
// binding for spanning row (to span root row)
ObjectRowBinding stringBinding = new ObjectRowBinding(typeof(string));
stringBinding.SpanningRow = true;
tree.RowBindings.Add(stringBinding);
// create editor
UITypeEditor uiTypeEditor = new StandardValueEditor();
UniversalEditBox universalEditBox = new UniversalEditBox();
CellEditor cellEditor = new CellEditor(universalEditBox);
cellEditor.DisplayMode = CellEditorDisplayMode.Always;
// add handlers
tree.GetChildren += delegate(object sender, GetChildrenEventArgs e)
{
if (e.Row.Item.ToString() == "root")
{
e.Children = new List<int>();
for (int i = 0; i < 10; i++)
e.Children.Add(i);
}
};
tree.GetCellData += delegate(object sender, GetCellDataEventArgs e)
{
if (e.Column == tree.Columns[0])
{
e.CellData.Value = "name-" + e.Row.Item.ToString();
// assign editor
if (e.Row.Item.ToString() == "root")
{
e.CellData.Editor = cellEditor;
e.CellData.TypeEditor = uiTypeEditor;
}
}
else if (e.Column == tree.Columns[1])
e.CellData.Value = "value-" + e.Row.Item.ToString();
};
// assign data source
tree.DataSource = "root";
}
}
|
|
|
Back to top |
|
|
Mrdec
Joined: 04 May 2006 Posts: 7
|
Posted: Thu Apr 30, 2009 7:56 am Post subject: UniversalEditBox in spanned row flickers |
|
|
I'm using VirtualTree version 3.12.0.0. |
|
Back to top |
|
|
Infralution
Joined: 28 Feb 2005 Posts: 5027
|
Posted: Thu Apr 30, 2009 10:50 pm Post subject: |
|
|
Thanks we will take a look at the issue and get back to you. _________________ Infralution Support |
|
Back to top |
|
|
Infralution
Joined: 28 Feb 2005 Posts: 5027
|
Posted: Mon May 04, 2009 12:38 am Post subject: |
|
|
The flicker is related to the way the SpanningWidget does layout. It calls the base RowWidget.OnLayout method to create the CellWidgets then adjusts CellWidget bounds. With some work it is possible to write the SpanningWidget.OnLayout method so that it does the layout from scratch and so doesn't have to call the base class OnLayout method.
We will include this modification in the next release (this may be a few weeks away since we have just released). In the meantime you can fix the issue by deriving your own custom SpanningWidget class and overriding the OnLayout method with the following code:
Code: | public class MySpanningRowWidget : SpanningRowWidget
{
public SpanningRowWidget(PanelWidget panelWidget, Row row)
: base(panelWidget, row)
{
}
private bool inLayout = false;
public override void OnLayout()
{
Rectangle cellBounds = Bounds;
ChildWidgets.Clear();
// add the row header if any
//
if (ShowRowHeader)
{
cellBounds.Width = Tree.RowHeaderWidth;
RowHeaderWidget.Bounds = RtlTranslateRect(cellBounds);
ChildWidgets.Add(RowHeaderWidget);
cellBounds.X += cellBounds.Width;
}
if (Columns.Contains(MainColumn))
{
Rectangle rowBounds = Bounds;
int rowWidth = SpanningRowWidth;
if (RightToLeft == RightToLeft.Yes)
{
rowBounds.X += rowBounds.Width - rowWidth;
}
rowBounds.Width = rowWidth;
if (!inLayout)
{
inLayout = true;
Bounds = rowBounds;
inLayout = false;
}
if (this.RightToLeft == RightToLeft.Yes)
{
cellBounds.Width = rowBounds.Width - (rowBounds.Right - cellBounds.Right);
cellBounds.X = rowBounds.X;
}
else
{
cellBounds.Width = rowBounds.Width - cellBounds.X;
}
CellWidget cellWidget = GetCellWidget(MainColumn);
cellWidget.Bounds = cellBounds;
ChildWidgets.Add(cellWidget);
// add the prefix cell widget if any
//
Column prefixColumn = Tree.PrefixColumn;
if (RowData.ShowPrefixColumn && prefixColumn != null && prefixColumn.Visible)
{
Rectangle prefixBounds = cellWidget.GetPrefixBounds(prefixColumn);
// check the widget is visible before adding it
//
if (prefixBounds.Width > 0)
{
CellWidget prefixWidget = GetCellWidget(prefixColumn);
// if both the cell editor and value are null then don't display
// the prefix
//
CellData cellData = prefixWidget.CellData;
if (cellData.Editor != null || cellData.Value != null)
{
prefixWidget.Bounds = prefixBounds;
ChildWidgets.Add(prefixWidget);
// set the width to reserve for the prefix widget
//
cellWidget.PrefixWidth = prefixBounds.Width;
}
}
}
}
}
} |
You then would need to override VirtualTree.CreateRowWidget (or set the RowWidgetCreator delegate) to return an instance of this RowWidget when the Row should be spanning. _________________ Infralution Support |
|
Back to top |
|
|
Mrdec
Joined: 04 May 2006 Posts: 7
|
Posted: Mon May 04, 2009 10:51 am Post subject: Still not perfect :-) |
|
|
Thank you for your reply, it's much better, but it still flickers..
I used the MySpanningRowWidget in the example above and now it don't flicker because of Width, but it flickers because of Height. The OnLaout is still called two-times, ones with Bounds.Height = 18 and for second with Bounds.Height = 20. You can see it when you resize the form. |
|
Back to top |
|
|
Infralution
Joined: 28 Feb 2005 Posts: 5027
|
Posted: Mon May 04, 2009 10:29 pm Post subject: |
|
|
The OnLayout does get called twice (to handle auto fit height rows) but each time the bounds.height is set to 18. The problem is in this case that the editor control (a UniversalEditBox) has AutoSize set to true. This means that when VirtualTree attempts to set the height of the control to 18 it immediately resets to 20 (to fit the size font). There are two possible solutions:
1. Set UniversalEditBox.AutoSize to false.
2. Set CellEditor.UseCellHeight to false.
Both of these solutions eliminate the vertical flicker _________________ Infralution Support |
|
Back to top |
|
|
Infralution
Joined: 28 Feb 2005 Posts: 5027
|
Posted: Mon May 04, 2009 11:09 pm Post subject: |
|
|
There was still an issue in the code I posted earlier which would show up if you pinned and unpinned the main column. The code below for the SpanningRowWidget.OnLayout fixes this:
Code: | public override void OnLayout()
{
if (inLayout) return;
inLayout = true;
Rectangle cellBounds = Bounds;
ChildWidgets.Clear();
// add the row header if any
//
if (ShowRowHeader)
{
cellBounds.Width = Tree.RowHeaderWidth;
RowHeaderWidget.Bounds = RtlTranslateRect(cellBounds);
ChildWidgets.Add(RowHeaderWidget);
cellBounds.X += cellBounds.Width;
}
if (Columns.Contains(MainColumn))
{
Rectangle rowBounds = Bounds;
int rowWidth = SpanningRowWidth;
if (RightToLeft == RightToLeft.Yes)
{
rowBounds.X += rowBounds.Width - rowWidth;
}
rowBounds.Width = rowWidth;
Bounds = rowBounds;
if (this.RightToLeft == RightToLeft.Yes)
{
cellBounds.Width = rowBounds.Width - (rowBounds.Right - cellBounds.Right);
cellBounds.X = rowBounds.X;
}
else
{
cellBounds.Width = rowBounds.Width - cellBounds.X;
}
CellWidget cellWidget = GetCellWidget(MainColumn);
cellWidget.Bounds = cellBounds;
ChildWidgets.Add(cellWidget);
// add the prefix cell widget if any
//
Column prefixColumn = Tree.PrefixColumn;
if (RowData.ShowPrefixColumn && prefixColumn != null && prefixColumn.Visible)
{
Rectangle prefixBounds = cellWidget.GetPrefixBounds(prefixColumn);
// check the widget is visible before adding it
//
if (prefixBounds.Width > 0)
{
CellWidget prefixWidget = GetCellWidget(prefixColumn);
// if both the cell editor and value are null then don't display
// the prefix
//
CellData cellData = prefixWidget.CellData;
if (cellData.Editor != null || cellData.Value != null)
{
prefixWidget.Bounds = prefixBounds;
ChildWidgets.Add(prefixWidget);
// set the width to reserve for the prefix widget
//
cellWidget.PrefixWidth = prefixBounds.Width;
}
}
}
}
else
{
// Park widgets that are not active so that their editor (if any) is hidden
//
foreach (CellWidget cW in CellWidgets)
{
cW.Bounds = Rectangle.Empty;
}
}
inLayout = false;
} // OnLayout |
_________________ Infralution Support |
|
Back to top |
|
|
Infralution
Joined: 28 Feb 2005 Posts: 5027
|
Posted: Tue May 12, 2009 4:23 am Post subject: |
|
|
Version 3.12.1 of Virtual Tree has now been released and incorporates this fix. _________________ Infralution Support |
|
Back to top |
|
|
|