Hi all,
I am working on a piece of code that should be able to display a set of data which is unknown on compile time: meaning I want to execute SQL statements, without knowing the model before execution.
Since the rows are in my case returned as object arrays (due to a generic transport model), I have to bind them at runtime.
This is the code I use for the moment:
List<UltraGridColumn> columns = new List<UltraGridColumn>(); int i = 0;
foreach (string entityField in actionTable.FieldDefinitions) {UltraGridColumn column = new UltraGridColumn(entityField, i++); column.Header.VisiblePosition = i;ultraGrid1.DisplayLayout.Bands[0].Columns.Add(column);}
this.ultraGrid1.DataSource = actionTable.Result; // this is an object array.
In the InitializeLayout event I try the following:
UltraGridColumn column = this.ultraGrid1.DisplayLayout.Bands[0].Columns["fieldName1"];
if (column.Editor == null){//execute some code}
Then at the line with the "if (column.Editor == null)" a NullReferenceException is thrown. Does anyone have a clue why?
There are a couple of issues here.
First, the Add method on the Columns collection is not intended to take a column object. If you look at the intellisense for ultraGrid1.DisplayLayout.Bands[0].Columns.Add, you will not see an overload that takes a Column object. There actually is an overload for this - which is why your code compiles, but you are not supposed to use that overload. It's only there for internal use for serialization purposes.
The grid columns are created based on the DataSource you assign to the grid. So you are adding some columns to the grid (which, as I said, you should not do), and then when you set the DataSource property on the grid, the entire layout of the grid (including all of the columns) are thrown away in favor of the data source's structure.
Does the object array you are binding to contain objects that are all the same type? If so, then I think the grid will pick up the type of the first item in the array and use the properties of that object as the columns in the grid. Although... I'm not sure this will work for a list of objects. The grid has no control over that, though, it's all up to the BindingManager class in DotNet.
So if this is not working and you are not getting any columns, you will have to use something else as the grid's DataSource. You could copy the data into a strongly-typed List<T> or BindingList<T>, for example. Or, you could copy the data into an UltraDataSource. Or... you could use the UltraDataSource as a sort've intermediary between the grid and the real data source in On-demand mode. There's a sample of this list technique in the WinGrid Samples Explorer called the Virtual Mode Sample.
Hi Mike,
Thanks for this useful suggestion. It works the way I want it now, so that is great. I use the CellDataRequested event to get the data from the List<object[]> to the grid.
Yet, another question pops up: Is there an event which occurs after databinding the grid. I had like to call the PerformAutoResizeColumns method after every time I bind to the object, but that does not seem possible.
Can you suggest any event?
Thanks,
Patrick
Hi Patrick,
I would use the InitializeLayout event. Make sure you pass in the right options to PerformAutoResizeColumns - you need to make sure it sizes based on all rows. This will force all of the rows to be loaded into the grid, but that's unavoidable if you want to autosize the column, anyway.
This event never gets raised when I use a BindingSource to bind to the Grid, when binding directly to the grid using the DataSource property it does get raised.
Can you explain how to get this method raised when using an intermediate datasource?
Regards,
Hi Patrick.
patrickhofman said: This event never gets raised when I use a BindingSource to bind to the Grid, when binding directly to the grid using the DataSource property it does get raised. Can you explain how to get this method raised when using an intermediate datasource?
This is simply not true. The InitializeLayout event of the grid fires any time the grid's DataSource or DataMember property is set, or when you call SetDataBinding. The event may not fire if you set the property to what it was already set to, of course.
If the event is not firing, then something else is wrong. Perhaps you are not hooking the event at the property time, before the DataSource is being set.
When you say: "it updates every time the grid's DataSource ... property is set" you are right, and that is the whole problem, because when you use an intermediate datasource object, such as the BindingSource, it gets called once, at the time the assignment the BindingSource is called.
I guess you can fix this when you hook on the DataSourceChanged property at the time you assign a BindingSource to the DataSource of a grid. You can unregister at the moment the DataSource is being set to something else. When you handle the event, just raise the InitializeLayout event, just like you do when setting the DataSource property of your Grid.
Does this sound like a appropriate enhancement request?
The grid doesn't always deal with a BindingSource, it typically only deals with IList or IBindingList and neither of these have a DataSourceChanged method or event. I suppose that the grid could special-case for the BindingSource, though. So if you would like to submit a feature request for this, I encourage you to do so:
Submit a feature request to Infragistics
Thanks Mike, I reported the feature request. Thanks for your help.