We are facing performance issue in the xamdatagrid (version 14.2). We found that the 'UpdateLayout' and the 'PerformAutosize' methods that we have used take lot of time, the time taken to load the grid is even more when the grid has large data.
For resizing the columns we have used PerformAutosize for each field/column. Just wanted to know is there any way to do resize all the columns of the grid in one go without having to call the PerformAutosize for each column?
We also have another requirement according to which we want to change the color of the cells depending on the value of the cell. For achieving this, in the code behind we have created a style and trigger and have applied the same on each cell. Following is the code snippet that we have used for creating the style and the trigger. In our grid we have more than 1000 columns (number of columns displayed in the grid may vary, as these columns are generated dynamically). Depending on the number of columns the grid loading performance goes down considerably. We wanted to know is there any other way we can dynamically change the color of the cell without applying the trigger or if you can suggest any change in the below code that could help minimize the time of loading the grid.
foreach (Field f in xamDataGrid1.FieldLayouts[0].Fields)
{
f.DataType = typeof(decimal);
f.ToolTip = "FY: " + f.Name.Replace("-", "");
Style myStyle = new Style(typeof(CellValuePresenter), objBasedOnStyle);
int k = (f.Index + (iFieldCount / 2));
Binding b = new Binding("Cells[" + k + "].Value");
DataTrigger dtgr = new DataTrigger();
dtgr.Binding = b;
dtgr.Value = "TRUE";
dtgr.Setters.Add(new Setter(CellValuePresenter.BackgroundProperty, Brushes.Aqua));
myStyle.Triggers.Add(dtgr);
f.Settings.CellValuePresenterStyle = myStyle;
}
Hi rhealsoftTakeoff,
In what cases are you calling PerformAutoSize? At the moment you have to call this method on each of the fields separately. Even if we did have a single method that performed the operation on all fields, I don't think the performance would be that much better than if you manually iterated the Fields collection and called PerformAutoSize on each one yourself. In the end we'd still have to iterate and perform the auto size. One thing you have to keep in mind is that auto-size operations are expensive. The grid has to iterate through the rows and cells and calculate the sizes of the content to assign the width of the column accordingly. If your AutoSizeScope is set to AllRecords it's even worse. Best performance would be to turn off auto-sizing completely and next best would be to set AutoSizeScope to RecordsInView. With 1000 columns though this may still take some time.
As for the data triggers, when you have a lot of these they are also fairly expensive to use. Probably the ideal situation would be to have the color stored in your business object and then just set a binding on the CellValuePresenter.Background to this color property. You can access the business object from the cell through it's DataContext. The Path would be "DataItem.MyBrushProperty". Then in your business object, you can change the color property based on what the value is.
1000 columns is a lot of columns. Since column headers are not virtualized, this means that there are 1000 LabelPresenter objects each that must be measured and arranged at load time. The good part is that cell and record UI components are virtualized so only the cells in view should be the ones loaded into memory. This depends on the width and height of your XamDataGrid though. If you allow for users to see a lot of columns at once and you have a lot of space to display many rows, all of those cells need to be created, measured and arranged and their bindings need to be updated.
Have you seen the following blog post about optimizing the XamDataGrid? http://www.infragistics.com/community/blogs/kiril_matev/archive/2010/10/26/optimizing-xamdatagrid-performance.aspx
Hi Rob,
Thank you for your reply.
Regarding setting the CellValuePresenter.Background to this color property based on the cell value, the cell values can be edited by the user i.e. these are changed dynamically. So to set the background color dynamically we have to use the trigger.
Can you please suggest or provide a sample application showing us how changing the background color can be achieved without using a trigger.
Regarding the PerformAutoSize, this is done only when the grid is initialized, also we the AutoSizeScope is set to "RecordsInView", however still the performance of the grid is very low. Let us know if there is any other workaround or solution that can help us achieve this.
One issue with your current setup is that you have a separate unique style per field. This means that the grid can't share the cell elements between other cells in different fields. It would be better if we came up with a different way to handle changing the color per cell that still allows us to share 1 style between all fields. Obviously this is a bit tricky because we need to write this style as generically as possible so that it works with all cells. Even my previous approach of adding a property to your business object that defined the color will not work for this.
To make this as generic as possible, I created a multi-value converter which takes in the field's name, and the value of the cell. This converter is attached to a MultiBinding in the CellValuePresenter style. Inside the converter, it looks at the value and depending on what the value is for the given field, it returns a specific background color. The downside to this approach is that the converter now needs to check each field name and value combination that requires a color change. Unfortunately I couldn't really figure out a way around this. We can't use a color inside the business object because the converter fires before the underlying business object is updated. Since the business object hasn't updated, the color is still an older value and it does us no good. (I've attached a basic sample illustrating this approach)
For PerformAutoSize, rather than manually calling this function, why not just set the Width property on the Field object to InitialAuto? If you are only performing the auto size during initialization, InitialAuto should be good enough. Auto/InitialAuto should work well in conjunction with RecordsInView since it will happen for the cells in view and only for other columns as they come into view.
Thank you for your help.
We have another requirement according to which we have to change the color of the cell based on a option selected by the user. In our application we have a toggle button (Multiply/Divide) to set the multiply/divide flag for each cell.. Selecting the cells if the user clicks on the “Multiply” button, the backcolor of the selected cells should be set to ‘Blue’ color; and selecting the “Divide” button the cell backcolor should be reverted back (i.e. to white).
For achieving the above functionality we store the flag value (i.e. Multiply or divide) in the grid’s hidden columns. We have created a data trigger and based on flag set in these hidden columns we are applying the style for each field (the code snippet for the same is provide in our earlier email) . On the user’s selection these values are changed and accordingly the style is implemented. However since the number of columns displayed in the grid are dynamic, if there are more than 1000 columns the performance of the grid would go down further.
So we tried another approach to achieve this functionality, as per this new approach we tried setting the flag values in the Cells’s ‘Tag’ property and tried applying the MultiValueConverter based on the Cell.Tag property changes. However with this approach we did not get the value of Cell.Tag property in the Conveter class as the converter is not fired when the tag property changes.
As the Converter class is not fired on the tag property change, we tried creating a data trigger targeting type “CellValuePresenter” at the XAML level. However we are unable to set the tag property at the xaml level. Can you please help us know how to set value to Tag property for each cell from dataset at XAML level (the columns in dataset are dynamic.). Also please let us know if there is any other cell’s property/workaround to achive this functionality?
We have modified the sample you have provided and added our code to set Tag property of the cell (please find attached the same herewith). Can you please review the same and let us know if there is any way we can achieve the functionality required by us.
There were a number of things wrong with the sample that caused it to not work. The main one was that the Tag property being set was not the same Tag property in the CellValuePresenter. The Tag property used is for a normal Cell object (((DataRecord)xamDataGrid1.Records[0]).Cells[0].Tag). This cell is not a CellValuePresenter so your DataTrigger isn't going to pick up on it. And CellValuePresenters do not have any knowledge about the cell they are referring to so it's not possible to bind to the Cell.Tag. They do not have any knowledge of the cell because at any moment they could be reused for a different cell somewhere else. CellValuePresenters are the UI component of a cell and these are virtualized.
Basically, the only way for you to perform this type of requirement is to have some property present in your underlying business object and bind to that from your CellValuePresenter. The DataContext for a CellValuePresenter is a DataRecord so you can get the underlying business object through the DataRecord.DataItem property ("Path=DataItem.MyProperty"). The issue with this is, you will have to create multiple styles for each of the Fields where you want the color to change so that the binding is to the correct property in each style. If you create multiple styles however, the CellValuePresenters cannot be shared between Fields as I described in my last post. I'm not really sure you can get around this however, you could create a multi-binding converter and pass in a bunch of properties that will help you determine what Field you are in, then in the converter perform some logic to return the correct color. But if you want to have that color determined by some hidden property, one of the bindings in the multi-binding converter will need to be that property so that when you change it in code, a property changed notification will fire and update the multi-binding. So in this case, I don't think you will be able to get away from creating a style for each field separately.