Hi,
I have a confusion over the timing of populating an UltraDataSource.
What is the exact purpose or extra that a UltraDataSource provides over the other collections like DataSets, DataTables or ValueLists? Simply stating, why would anyone need an UltraDataSource, when one can simply bind these other objects to the ultragrid?
What is the difference between populating a ultradatasource in a custom method call and in a InitializeDataRowCollection? What is the difference between populating the ultradatasource in a InitializeDataRowCollection versus IntializeDataRow?
What do the ISupportInitialize calls for BeginInit and EndInit implemented by UltraDataSource do in specific?
What is the most efficient way to populate an ultradatasource? Does Ultradatasource allow being accessed from a back ground thread?
Thanks,
Bhushan.
Hi Bushan,
There are a number of different situations in which you might want to use an UltraDataSource.
If you are using a data source like SQL Server, then a DataSet/DataTable is designed to allow you to retrieve and update your data to the back end.
But maybe you have a very simple app where you need a grid to display some local data to the user and don't want to set up a complex DataSet/DataTable. You could use an UltraDataSource in this case and define the data right in code.
You could also do this with more complex data in a case where you don't need relational data. For example, if you have data where the parent are child rows are simply hard-coded and don't change, as opposed to relational data where the parent and child data are based on a value within the data. This also make the UltraDataSource a little faster when working with hierarchical data, since it doesn't have to calculate the relationships.
Bhushan Inamdar said:What is the difference between populating a ultradatasource in a custom method call and in a InitializeDataRowCollection? What is the difference between populating the ultradatasource in a InitializeDataRowCollection versus IntializeDataRow?
These events are for loading data on-demand. This is for efficiency and performance where you have a large set of data to show and you don't want to load it all at once. There are samples included with the suite called the "Virtual Mode sample" which demonstrates using the UltraDataSource to show 1 million rows in an UltraWinGrid in an efficient way without loading all of the data up front.
Bhushan Inamdar said:What do the ISupportInitialize calls for BeginInit and EndInit implemented by UltraDataSource do in specific?
ISupportInitialize is for design-time serialization and deserialization. It''s not really something you need to worry about, it's all handled by the designer.
Bhushan Inamdar said:What is the most efficient way to populate an ultradatasource? Does Ultradatasource allow being accessed from a back ground thread?
Using threading with DataBinding is generally not a good idea. When you use multiple threads, you need to marshal the communucation between those threads and in the case of data binding, you are not in control of that communication. So while it might, in theory, be possible to populate an UltraDataSource on a separate thread, you cannot do it while it's bound to a control in the UI, which would probably defeat the purpose of using another thread, so there wouldn't be much point in it.
The most efficient way depends a lot on what your requirements are and what your app needs to do. As I mentioned you can use load-on-demand if you can efficiently load your data from wherever it's stored a piece at a time in an efficient way. Generally speaking, I think the most common use case is to just populate the data up front - which will work fine as long as your data set is of a reasonable size.
Hi Mike,
Thanks for the detailed response to my rather vague queries. The reason for me to ask such queries was to get a general understanding of whether or not there is a general rule of thumb working with the infragistics controls to take care of the minimalistic performance related gotchas. For instance, quite often we see in winforms applications, that the how events get triggered when not needed and unnecessary repetition of loading of the data on the form appears. Let us say Tab changed event. Firstly, in the form load we often load the default data and then set the tab index to a tab page. Now there is some code in the tab changed event, that is exactly similar to the code that we wrote in the form load. So to avoid this, I usually call the Tab Changed event handler in between the statements to unsubscribe and subscribe to the tab changed event. This saves the coding effort as well as prevents the same code getting executed a number of times. Also, in the case of data binding, when the data source is assigned to a winforms gridview, then the Datasourcechanged and related events are fired. If there are handlers attached to these events, they would get executed multiple times. In complex winforms, a lot of exceptions can be attributed to these kind of scenarios. I usually analyze the winform and find out the sequence of firing of events and then code accordingly.
Coming to our Infragistics case. I know that there would be some issues in marshalling if I use separate threads to populate the infragistics ultradatasource. But nonetheless, people have used separate threads to fetch the data in the background, and then populate the data on the main thread using the Control.InvokeRequired property and Control.Invoke methods. Also, a proper way to use multi threading is to use auto / manual reset events and wait handles for signalling. Well, that is for the case where we are dealing with substantial volume of data. In my case, I have been able achieve without multi threading as it was fairly simple as far as data is concerned. The data rows in a grid would not exceed a few thousands and hence I use preloaded option instead of LoadonDemand.
As of now, I do not have any performance issues. But I would love to avoid repetitive coding. The thing is, there are about 15 ultra grids with similar columns, column styles, cell formatting, grid borders, location, etc. However, the UI for a single grid is much comples and I am using IntiailizeRow event to do custom value based formatting. Also, I have applied conditional appearances to column headers. Also, I am using creation filter for allowing column expand and collapse feature. I am also currently trying to implement custom expand/collapse indicators for the rows. For that I am not using child bands and child rows, but simple indentation and I intend to insert a (+/-) image in the Left most column using either creation filter or a draw filter (...if that is possible). I would like you to comment upon this as to if it is possible to handle this is feature along with the existing column expand and collapse indicators. For columns, I am using HeaderUIElement from the Parent in the AfterCreateChildElement(...) method and intend to extract CellUIElement for the 0th row. Or is there a better way using a drawfilter? So going back to what I would like to have is to know if there is an UltraGrid extensibility sample application for winforms, that allows me to implement abstract and virtual methods that have the functionality common to all the grids. I had started trying this out, but gave up soon as I did not find any resources. Further, I wanted to use that extended control, and implement an MVC architecture to invoke the controller from the said 15 places to invoke the respective grids. But, sadly, I have ended up repeating the code in few places. That is not bad altogether from the performance perspective, but it is not good from the maintenance perspective. Request you to comment upon this as well.
Going back to the performance related tips, I would like to know, as to what know if in the Infragistics UltraGrid or UltraDataSource, is there a need to make a call to call an Update(), Invalidate(), Refresh() calls and what are the scenarios to call them? Also, there are 2 overloads of the UltraDataSource constructor, one is default parameter less constructor and the other takes in the Container type as a parameter to which usually the parent container is passed as (this.Container). What is purpose of passing it and how shall it be sued?
Although not very critical for my on going implementation, it would be great if I could get some answers to these long pending questions...
Whew, that's a lot of stuff... :)
Bhushan Inamdar said:Thanks for the detailed response to my rather vague queries. The reason for me to ask such queries was to get a general understanding of whether or not there is a general rule of thumb working with the infragistics controls to take care of the minimalistic performance related gotchas. For instance, quite often we see in winforms applications, that the how events get triggered when not needed and unnecessary repetition of loading of the data on the form appears. Let us say Tab changed event. Firstly, in the form load we often load the default data and then set the tab index to a tab page. Now there is some code in the tab changed event, that is exactly similar to the code that we wrote in the form load. So to avoid this, I usually call the Tab Changed event handler in between the statements to unsubscribe and subscribe to the tab changed event. This saves the coding effort as well as prevents the same code getting executed a number of times. Also, in the case of data binding, when the data source is assigned to a winforms gridview, then the Datasourcechanged and related events are fired. If there are handlers attached to these events, they would get executed multiple times. In complex winforms, a lot of exceptions can be attributed to these kind of scenarios. I usually analyze the winform and find out the sequence of firing of events and then code accordingly.
I understand what you are saying here, but this is not limited to Infragistics controls, this would be true of any controls. If you are concerned about events firing before you have initialized your form, then one simple solution would be not to hook the events until after you are done with the Form_Load and any other initialization you need.
Another option, which you already mentioned, is to unhook and re-hook the events surrounding some code.
Many of the Infragistics controls also expose an EventManager which can be used to turn the events on or off - which is essentially the same as hooking/unhooking the event, but can be easier if you are disabling several events at once.
Bhushan Inamdar said:Coming to our Infragistics case. I know that there would be some issues in marshalling if I use separate threads to populate the infragistics ultradatasource. But nonetheless, people have used separate threads to fetch the data in the background, and then populate the data on the main thread using the Control.InvokeRequired property and Control.Invoke methods. Also, a proper way to use multi threading is to use auto / manual reset events and wait handles for signalling. Well, that is for the case where we are dealing with substantial volume of data. In my case, I have been able achieve without multi threading as it was fairly simple as far as data is concerned. The data rows in a grid would not exceed a few thousands and hence I use preloaded option instead of LoadonDemand.
It may be possible, under some very limited circumstances, to make this work. But it's extremely tricky and dangerous and if there is a problem, it probably won't be very obvious. It's most likely to manifest itself as seemingly random crashes in areas of the code that have nothing to do with the data binding or the the threading.
There is a long, detailed discussion of threading and the problems involved here: Work with a dataset bound to a grid on a separate thread - Infragistics Community
Ultimately, marshaling the data is NOT POSSIBLE in many cases, because you are not in control of the communication. For example, when the user moves the mouse over a grid cell, the grid asks the data source for the value of that cell. There's no way you can marshal that communication properly, because the communication is between the grid and the data source and no event or method will fire that you could intercept it (unless maybe if you wrote your own DataSource entirely from scratch).
Bhushan Inamdar said:As of now, I do not have any performance issues. But I would love to avoid repetitive coding. The thing is, there are about 15 ultra grids with similar columns, column styles, cell formatting, grid borders, location, etc. However, the UI for a single grid is much comples and I am using IntiailizeRow event to do custom value based formatting. Also, I have applied conditional appearances to column headers. Also, I am using creation filter for allowing column expand and collapse feature. I am also currently trying to implement custom expand/collapse indicators for the rows. For that I am not using child bands and child rows, but simple indentation and I intend to insert a (+/-) image in the Left most column using either creation filter or a draw filter (...if that is possible). I would like you to comment upon this as to if it is possible to handle this is feature along with the existing column expand and collapse indicators. For columns, I am using HeaderUIElement from the Parent in the AfterCreateChildElement(...) method and intend to extract CellUIElement for the 0th row. Or is there a better way using a drawfilter? So going back to what I would like to have is to know if there is an UltraGrid extensibility sample application for winforms, that allows me to implement abstract and virtual methods that have the functionality common to all the grids. I had started trying this out, but gave up soon as I did not find any resources. Further, I wanted to use that extended control, and implement an MVC architecture to invoke the controller from the said 15 places to invoke the respective grids. But, sadly, I have ended up repeating the code in few places. That is not bad altogether from the performance perspective, but it is not good from the maintenance perspective. Request you to comment upon this as well.
Again... a lot of this seems to more of a general programming question than specific to the Infragistcs controls. If you are using a relatively recent version of Visual Studio and the latest CLR, you could make use of Extension methods to allow you to attach a method to a control.
Regarding repeating code, the obvious solution to that is to consolidate your code into method and call those methods from all the places you need them instead or writing the same code twice.
Another option might be for you to create a utilities class with static method that take in a grid control and then perform some operations on the specified grid. Then you could call the same method on as many grids as you want.
Regarding the collapsing columns, v2016.1 will have a collapsible groups feature that you might want to check out when it's released. But if you can't wait or you need collapsing columns, then it seems like a CreationFilter would be a good way to go. You could use the CreationFilter to embed an ExpansionIndicatorUIElement into the header and then presumably adjust the width of the column based on whether it's expanded or collapsed.
For collapsing rows, once again, I think a CreationFilter would probably be better than a DrawFilter. What I would do, to make things simpler, it add an unbound column to the grid and put the ExpansionIndicator inside the cell. Then what you would do is hide or show the "child" rows based on the state of the expansion indicator in the parent row (which could be stored as the value of the cell). This is, in fact, pretty much what we do for the UltraGanttView control whose left side is essentially a WinGrid.
Bhushan Inamdar said:Going back to the performance related tips, I would like to know, as to what know if in the Infragistics UltraGrid or UltraDataSource, is there a need to make a call to call an Update(), Invalidate(), Refresh() calls and what are the scenarios to call them? Also, there are 2 overloads of the UltraDataSource constructor, one is default parameter less constructor and the other takes in the Container type as a parameter to which usually the parent container is passed as (this.Container). What is purpose of passing it and how shall it be sued?
UltraDataSource supports IBindingList, which means it calls all of the proper notifications that the grid needs in order to update the display. So I can't see any reason why you would ever need to call Update, Invalidate, or Refresh on the grid - unless there is a bug or something that you need to work around, or perhaps in some rare instances where there's some kind of timing issue.
The Container is essentially used by many components. If you place the control on the form at design-time, the container will be set for you automatically. Again, this is one of those design-time things that you probably don't need to worry too much about. To be perfectly honest, I'm not 100% sure what the container is used for. It might just be needed for the designer and not needed at run-time at all. But I think it's basically a way for the component to get a reference to the form. Controls can get a reference to the form easily via their Parent property, but components generally cannot.