📜 ⬆️ ⬇️

Difficult grid selection for WPF projects

Our team was faced with the task of choosing for future projects a library of WPF components for the rapid development of the user interface of business applications. The promise to consider is that the standard grid (and this is usually most of the functionality of the user interface of a business application) does not suit in many ways. Many things have to finish file, inventing another bike. I'm tired! We decided to compare grids from each library and make an informed choice.

Competitors


I think that the list of participants in the comparison will surprise no one:

Who cares how it happened, please under the cat.

It is worth saying that our team already has experience with the WPF components from Telerik and DevExpress. There is also experience with a 10-year WinForms grid from ComponentOne. I myself have been using WPF for commercial projects since 2009 and, of course, I managed to write my grid-bike and MVVM framework.
')

As compared


At once I will say that a comparison of such matters as “development convenience”, “feature implementation speed”, etc. is to a certain extent subjective. Therefore, in some subjective judgments, I do not claim to be the ultimate truth and express my vision of this issue.

Initially, there was no clear list of the required functionality, because comparing all 5 grids on a large list of functionality would be very resource-intensive. Therefore, the first stage was a superficial subjective view of the grid itself in a patterned task and impressions in the “like” / “dislike” subjective categories.

At the first stage, the first two candidates disappeared, and we began to look in detail at the three remaining ones, after making a list of the necessary functionality. Next, I will describe the research process and my impressions of each grid.

DevExpress


Grid impressions are very negative. It seems that it is entirely copied from WinForms with changing namespaces. The style of the components is repeated by WinForms, which on the one hand is good for those who are just switching to WPF from WinForms, and on the other hand there is no transition to a new technology. Subjectively, after 4 years of development on WPF, it is difficult to change to this grid. We have to look for a description of each property and method (although the documentation is good). For example, the selected row in the grid is not a SelectedItem , as many WPF developers will think, but attention, FocusedRow . Obviously, I do not argue, but it is very unusual.

Binding in columns, customization of columns

Binding speakers works well. Like the original WPF. Editing in does not strain and everything just works. Customization is also done at a high level: there are styles, patterns and selectors of patterns for cells.

Coloring lines through one

But then it began. The simplest operations, which in the original WPF grid are performed by setting one property, in the grid from DevExpress entail kilometer sheets of code. For example, what could be simpler than coloring the lines of a grid through one: odd - white, even - gray. For those who are not familiar with WPF, I will say that in the original out-of-the-box grid of the .NET Framework, this is done like this:
<DataGrid AlternatingRowBackground="LightGray"/> 

But DevExpress developers have a different outlook on life and they don’t have this property. The official example from the developers says that you need to do this :
 <!--    --> <SolidColorBrush x:Key="EvenRowBrush" Color="LightGray" /> <!--    --> <SolidColorBrush x:Key="OddRowBrush" Color=" Transparent" /> <!--      --> <Style BasedOn="{StaticResource {dxgt:GridRowThemeKey ThemeName=Seven, ResourceKey=RowStyle}}" TargetType="{x:Type dxg:GridRowContent}"> <Style.Triggers> <MultiDataTrigger> <MultiDataTrigger.Conditions> <Condition Binding="{Binding Path=EvenRow}" Value="False"/> <Condition Binding="{Binding Path=SelectionState}" Value="None"/> </MultiDataTrigger.Conditions> <Setter Property="Background" Value="{StaticResource EvenRowBrush}" /> </MultiDataTrigger> <MultiDataTrigger> <MultiDataTrigger.Conditions> <Condition Binding="{Binding Path=EvenRow}" Value="True"/> <Condition Binding="{Binding Path=SelectionState}" Value="None"/> </MultiDataTrigger.Conditions> <Setter Property="Background" Value="{StaticResource OddRowBrush}" /> </MultiDataTrigger> </Style.Triggers> </Style> 

Strange, not clear and annoying that you have to google such simple things and get such non-trivial solutions.

Master part

The next scenario, which we looked at, was the creation of a bundle of master parts with an embedded grid. Those. I want the table to have pluses, on click in which nested tables with related entities will open. For example, orders and order lines.

Several examples of the implementation of such a functional were found, each of which had its own advantages and disadvantages. For example, this example limits the height of parts to 300 pixels. And if I have more lines? Then there will be a second, next to the main one? Ugly and uncomfortable.

There is another implementation variant for the master part using DataControlDetailDescriptor . The code looks like this:
 <dxg:GridControl.DetailDescriptor> <dxg:DataControlDetailDescriptor ItemsSourcePath="Children"> <dxg:DataControlDetailDescriptor.DataControl> <dxg:GridControl> <dxg:GridControl.View > <dxg:TableView> </dxg:TableView> </dxg:GridControl.View> <dxg:GridControl.Columns> </dxg:GridControl.Columns> </dxg:GridControl> </dxg:DataControlDetailDescriptor.DataControl> </dxg:DataControlDetailDescriptor> </dxg:GridControl.DetailDescriptor> 

Where does such wild tag nesting come from? I understand that xml is a poor, never compact format, but not to the same extent! Looking ahead to say that competitors in this regard are more concise.

Moreover, the second option leads to the fact that the nested grid with details is practically not separated from the master row, more precisely, the last row of the grid part is not separated from the next row of the master grid. This may confuse the user. At the same time, an explicit setting of the boundaries of the part of the grid did not produce any results.

Also, with this approach, the binding of the FocusedRow property of the grid part does not work! It is also impossible to simply determine which grid is in focus in order to change the availability of commands on the toolbar. I had to play with a variety of related events changing the focus of two grids and deriving from this sequence which grid is actually in focus and which commands should be available.

Binding the context menu commands

Binding of commands in the context menu is just disgusting. Inheritance of the DataContext property during the formation of the context menu at the grid is violated. In the DataContext of the context menu item, there is an instance of some service class and to bind a command from the ViewModel, you need to write the following line:
 Command="{Binding Path=View.DataContext.CancelCommand}" 

And in the process of finding such a correct sequence of properties there were so many different options. This option was not found after one hour of searching.

Verdict

To the above disadvantages, you can add freezes and crashes of the studio's visual editor when the DevExpress components are open.

At this our experiments with DevExpress ended. But I must say that all of the above problems with the grid from DevExpress is almost completely a subjective assessment, and for a person who has developed using WinForms components from DevExpress, everything will be more rosy and familiar.

It is also impossible not to mention such a cool functionality as editing the location of components on the form by the user while preserving the settings between launches. This is really useful functionality, especially in large projects with which advanced users work.

Infragistics NetAdvantage


The next experimental was a grid from Infragistics. To my surprise, I immediately found two grids : XamGrid and XamDataGrid . The functional saturation of each of the grids is strange and is described here .

And if the application will require the functionality of both grids in one? Strange, but oh well, we will try. For example, take the XamDataGrid , which seems to be richer in functionality and customization features.

Binding in speakers

The first thing that confused was the fact that the grid does not have the Columns property. There is some property FieldLayouts , which is declared like this :
 <igDP:XamDataGrid AutoFit="True" DataSource="{Binding Constituents}"> <igDP:XamDataGrid.FieldLayouts> <igDP:FieldLayout> <igDP:FieldLayout.Fields> <igDP:Field Label="Name" Name="Name" /> <igDP:Field Label="Photo" Name="ImageUri">…</igDP:Field> <igDP:Field Label="Age" Name="Age" /> </igDP:FieldLayout.Fields> </igDP:FieldLayout> </igDP:XamDataGrid.FieldLayouts> </igDP:XamDataGrid> 

Strange. It is also impossible to simply take and set the binding. Only the name of the field. And if we want to refer to the field of a related object, then we need to do this :
 <igDP:UnboundField Name="StreetDesc" Label="Security Description"> <igDP:Field.Settings> <igDP:FieldSettings> <igDP:FieldSettings.CellValuePresenterStyle> <Style TargetType="igDP:CellValuePresenter"> <Setter Property="Template"> <Setter.Value> <ControlTemplate> <TextBlock DataContext="{Binding DataItem.Security}" Text="{Binding StreetDesc}"/> </ControlTemplate> </Setter.Value> </Setter> </Style> </igDP:FieldSettings.CellValuePresenterStyle> </igDP:FieldSettings> </igDP:Field.Settings> </igDP:UnboundField> 


Verdict

No, this is not WPF! We decided not to waste time on exploring this monster and postponed it.

Xceed


Then everything is more interesting. If the first two grids are negative impressions, then this cannot be said so. On the one hand, the grid is well written, there is a lot of interesting, really fast with large amounts of data. On the other hand, developers are not steamed such issues as localization of applications. But let's order.

Lazy loading records and support WCF DataServices

For some reason, I started looking at this grid with performance and integration capabilities with WCF DataServices (because it is this technology that we have chosen to communicate with the application server). A strange choice of functionality for a first look at the grid, I agree, but by that moment I was tired of looking at primitives and decided to have some fun. Surprisingly, the grid is fast, there is built-in support for WCF DataServices. It is possible to slip into the data source IQueryable and the grid itself implements a primitive server filtering and sorting with a lazy daughter of records per client when scrolling. It works amazingly. I was delighted that this is possible, exhibiting one property.

But then came the disappointment. Yes, the filters work, but only for the fields of the object that is directly shown in the grid. According to the fields of related objects, he can neither filter nor sort. And if the automatic filter field is simply blocked, then when sorting it falls with a strange exception. And indeed the standard components for filtering in the grid were disappointing. For comparison, Infragistics has pumped it much better and more correctly. But filters can be customized and therefore not so critical.

Binding in speakers

Here came the disappointment. It turns out that you cannot set a binding expression for a grid column. You can specify the value of the FieldName property. In addition to it, there is the DisplayMemberBindingInfo property, in which you can set the usual binding properties (but not all), but it is not reducible from the markup extension (you can not just take and write DisplayMemberBindingInfo = "{Binding ...}" ). In this case, the cell's DataContext will receive not an instance of the data object, but an instance of the associated property of the data object. It seems logical, but how then in the style / pattern of the cell to reach the adjacent columns or other properties of the data object? It turns out you can, dancing with this tambourine:
 <xcdg:Column FieldName="Product.Name" Title="" CellContentTemplateSelector="{StaticResource ProductTemplateSelector}"> <xcdg:Column.DisplayMemberBindingInfo> <xcdg:DataGridBindingInfo ReadOnly="True" Path="."/> </xcdg:Column.DisplayMemberBindingInfo> </xcdg:Column> 

The important thing here is that when setting the value Path = "." Be sure to specify ReadOnly = "True" . This will allow placing an instance of a data object ( Order ) in the DataContext of a cell, rather than its properties ( Product.Name ).

I do not understand why it was necessary to do so. Anyway. One could live with this, but then I was confronted with amazing behavior. An inquisitive reader is probably already indignant and writes a comment in the style “in the example of the column, the assignment of the FieldName =“ Product.Name ”property is superfluous, it makes no sense.” I agree, let's remove. As a result, we get the following error from the compiler:
Value cannot be null. Parameter name: key
What value, what parameter is key? Unclear. At the same time, an attempt to create two columns with the same value of the FieldName property gives the following error:
A column with the same field name already exists in collection.
Yeah, it's warmer. Then curiosity disassembled me, and I went to the source with a reflector. It turns out that the Columns collection itself is a descendant of ObservableCollection , but inside (apparently for optimizing access) it contains a private field:
 Dictionary<string, ColumnBase> m_fieldNameToColumns; 

It turns out that we have to invent a mythical, non-existent data field name. And what will be there with binding? Strange, but not so critical.

Localization

Honestly, I did not expect that in 2013 I would read the following recommendations on the localization of a specific line in the companent:
For the group headers, you can create a customized group.
 <DataTemplate DataType="{x:Type xcdg:Group}"> <TextBlock Text="Voici mon DataTemplate français!" /> </DataTemplate> 

You can start the installation of a folder for the WPFG installation folder (for the ResourceDictionary).

Free translation:
For the text of the grouping clause in the grid, use the following code snippet:
untranslatable code snippet
Then you can start watching the templates for overriding here: “themes \ Common \ Common.Resources.xaml” in the installation path of the DataGrid For WPF (3rd resource from the top)
Should I override all the templates of all the text messaging components? Wow localization in the 21st century.

But this forum thread has excluded Xceed from further consideration:
Unfortunately, it is not currently possible to change the language of the ShowPrintPreviewWindow or the ShowPrintPreviewPopup.

The print preview is not implemented using resource files (that preserves some language settings). Also, the control is private and the control is private.

Short translation:
Unfortunately, now it is impossible to change the language of messages of these windows, because this text is not included in the resource files, and the component is private.
Bravo, Xceed developers! The whole non-English world applauds you.

Verdict

Beautiful, fast, much is convenient, but as in the old joke "... there is one small nuance."

ComponentOne


The impression is positive. Everything is done beautifully and neatly. By marking the grid in basic things we are practically indistinguishable from the standard grid. All bindings work, as expected, columns are customized by styles or templates, there are different types of columns with corresponding editors. But let's go in order.

Two grids instead of one. Choose again?

There are two grids in the delivery: C1DataGrid and C1FlexGrid. After I saw this fact, I immediately wanted to forget about these components, but I overpowered myself and read an article explaining this fact in sufficient detail and understandable, unlike Infragistics. Here the functionality is clearly decomposed into two grids: the first with a rich possibility of customization, filtering, grouping, master part, etc. And the second is lightweight, simple for quick work with large flat tables. So in this case, this separation can even be called an advantage.

Binding in columns, customization of columns

Everything is fine here: we set the Binding property of the column and rejoice at the developer’s genius. Only in order to be able to edit the values ​​in the grid, you must explicitly set the bidirectional binding. Editing the properties of related entities works just fine, but by default the binding in the edit textbox does not work when the focus is lost, but instantly. Unexpectedly, but these are trifles and, moreover, are configured in the expression of binding.

Customization of speakers at a high enough level. There are 9 standard column types + TemplateColumn . All columns can be set cell style. In TemplateColumn , as the name implies, you can specify a template. At the same time, there are two properties CellStyle and CellContentStyle to set the style. If you set the style of the cell content, then inside the style you need to write strange binding, for example, you had to write a trigger like this to change the background color of the cell depending on the order status:
 <Style x:Key="SateCellStyle" TargetType="TextBlock"> <Setter Property="Background" Value="Transparent"/> <Style.Triggers> <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=c1:DataGridRowPresenter}, Path=Row.DataItem.State.Code}" Value="new"> <Setter Property="Background" Value="Wheat"/> </DataTrigger> <DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=c1:DataGridRowPresenter}, Path=Row.DataItem.State.Code}" Value="confirmed"> <Setter Property="Background" Value="LightGreen"/> </DataTrigger> </Style.Triggers> </Style> 

Well, okay, this is unpleasant, but not so critical.

Grieved that you can not set CellTemplateSelector . Of course, in a real application, you can always rephrase the task in order to do without the selector, but this is alarming.

Master part

Everything is beautiful here. The default style is perfectly drawn, the details are good, the marking suffers minimally, without requiring additional intermediate tags, like in DevExpress:
 <c1:C1DataGrid.RowDetailsTemplate> <DataTemplate> <c1:C1DataGrid x:Name="gridOrderItems" IsReadOnly="False" AutoGenerateColumns="False" ItemsSource="{Binding Path=SalesOrderItems}"> <c1:C1DataGrid.Columns> <c1:DataGridTextColumn Binding="{Binding Path=SalesOrderItemId, Mode=TwoWay}" Header="Item Id" /> <c1:DataGridTextColumn Binding="{Binding Path=Product.Name, Mode=TwoWay}" Header="Product name" /> </c1:C1DataGrid.Columns> </c1:C1DataGrid> </DataTemplate> </c1:C1DataGrid.RowDetailsTemplate> 

In the nested grid, everything is still perfectly edited, including the fields of related objects. Validation by default is not intrusive or annoying when editing.

Tree Grid

The task is simple: it is necessary to show a conditionally infinite hierarchy of objects of the same type. The main requirements for the interface: columns are announced and shown once, on the left side of each line there is a button to switch the visibility of the child records, the levels are shown with a visible indentation from the left edge.

“Out of the box” there is no such functionality, but in the examples there is a similar one:

Implemented by the visibility of the rows, which is switched in the trigger of the ToggleButton button, which lies in the row header pattern. The example is interesting, it works quite quickly and nicely. But sorting does not work, because the data must be pushed in a certain order, according to the inheritance hierarchy (the grid continues to work with a flat list). This is only the appearance of a hierarchy and is not suitable for real projects. Conclusion - a beautiful advertising chip, in the application system of little use.

Combining column headers.

The business task is to make a multi-level table header with a union, of the form:

It must be said that the considered grid is the best in terms of the functional of combining not only the headers, but also the cells with data and row headers. As expected, this is all implemented with the help of one functionality.

The C1FlexGrid component has an AllowMerging property ; you can also set it separately for rows and / or columns. This property enables the mode of automatic merging of adjacent cells, if they have the same values. It works cool, but there is a suspicion that it will slow down on large volumes (we had problems with this in the ancient WinForms grid of the same manufacturer).

The C1DataGrid component is a bit more complicated, but tolerable. There is no such simple property. But you can intercept the MergingCells event, in the handler of which you can implement your logic of merging cells. It sounds scary, but in the examples there are two static classes with extensible methods for grid cells that reduce this logic to a minimum. As a result, if you don’t go into the guts of these helpers, the handler code for combining the headers looked like this:
  public ComponentOneComparision() { InitializeComponent(); _headerColumnRows = new[] { TopColumnHeaderRow, BottomColumnHeaderRow }; } private DataGridRow[] _headerColumnRows; private void dataGrid_MergingCells(object sender, C1.WPF.DataGrid.DataGridMergingCellsEventArgs e) { //      var nonHeadersViewportCols = dataGrid.Viewport.Columns.ToArray(); var nonHeadersViewportRows = dataGrid.Viewport.Rows.Where(r => !_headerColumnRows.Contains(r)).ToArray(); //    foreach (var range in MergingHelper.Merge(Orientation.Vertical, _headerColumnRows, nonHeadersViewportCols, true)) { e.Merge(range); } } 

At the same time, the column headers in xaml looked like this:
 <c1:DataGridTemplateColumn Header="[, ]" /> <c1:DataGridTemplateColumn Header="[, ]"/> <c1:DataGridTextColumn Header="[, ]"/> 

Just had to add two custom strings?
 <c1:C1DataGrid.TopRows> <c1:DataGridColumnHeaderRow x:Name="TopColumnHeaderRow"/> <c1:DataGridColumnHeaderRow x:Name="BottomColumnHeaderRow"/> </c1:C1DataGrid.TopRows> 

And you need to disable the standard column headers by setting the grid property:
 <c1:C1DataGrid HeadersVisibility="Row" 

As a result, after the launch we get a grid, with the title shown in the figure above. On the one hand, the code turned out to be quite a lot: two auxiliary classes, an event handler, forced creation of custom rows, columns headers, ceased sorting, filtering and grouping, because we turned off the standard column headers. On the other hand, it uses a unified cell merging mechanism, which allows not only to combine column or row headers, but also beautifully show reports in which data in columns will be combined, for example, by company status or company name.

Lazy loading records and support WCF DataServices

Unfortunately, lazy loading of records is claimed only for Silverlight, and for WPF even in the demo it is not. Declared support for WCF Ria Services, well described in this article

The forum has an open ticket for the implementation of support for WCF DataServices, but so far it's quiet there. It can be expected that this functionality, if it is implemented, will be very good.

Copy to clipboard and export to Excel

It works. It just works without dancing with a tambourine. But only for flat tables. Does not export merged column headers. For the master part of the grid, the lines that are in focus (master or part) are copied to the buffer; only the lines of the master grid are exported to Excel. For template columns, empty strings are copied to the buffer; the result of the ToString () method of the string data object is exported to Excel.

Print the contents of the grid

The grid has the Print (string docName) method , which opens a dialog to select a printer for printing the whole grid. Also there is a method:
 List<FrameworkElement> GetPageImages(…) 

which returns a paginated grid. Then the resulting collection can be packaged in a PrintDocument and printed as a xps document, showing it in a preview.

Localization

Here, too, everything is beautiful. Out of the box there is localization in 21 languages, including those necessary for our project (Russian and Chinese).

UI Automation Support

Recently, I studied the question of automating UI testing a bit and could not help but go through the Coded UI Test Builder tool on highlights. I was disappointed. A grid for a testing tool is seen as a single component with no content. This is unfortunate, because if we want to test, we will have to expand the components, embedding support for UI Automation. But I would not say that it is a blocking functionality.

Verdict

The patient is more alive than dead. Nice, fairly fast grid with good support for basic WPF principles. Mostly there are flaws, like the lack of CellTemplateSelector 's or not implemented by UI Automation, but they are not so critical.

Telerik


We already had a positive experience with these components, so here it was interesting to compare specific features with others. It should be noted that the default style of the grid always scares me from it. But the taste and color of all the markers are different, and the theme can be changed in one line of code.

Binding in columns, customization of columns

Here everything is better than the previous subjects. Binding works as expected, the data in the cells are well edited. Validation is by default, it does not bother. Binding (and, of course, validation) is triggered when the textbox loses focus (as in the original WPF TextBox ).

You can set a style, a template, a template selector and even a style selector for a column. Everything, as it should be. Binding style expected. This is how the style with datatrigger on the background color looks like, depending on the order status (compare it with the style for the ComponentOne grid):
 <Style x:Key="SatetCellStyle" TargetType="telerik:GridViewCell"> <Setter Property="Background" Value="Transparent"/> <Style.Triggers> <DataTrigger Binding="{Binding Path=State.Code}" Value="new"> <Setter Property="Background" Value="Wheat"/> </DataTrigger> <DataTrigger Binding="{Binding Path=State.Code}" Value="confirmed"> <Setter Property="Background" Value="LightGreen"/> </DataTrigger> </Style.Triggers> </Style> 


Master part

Here everything is expected and good, but you need to add a special tag. The detail grid declaration looks like this:
 <telerik:RadGridView.ChildTableDefinitions> <telerik:GridViewTableDefinition /> </telerik:RadGridView.ChildTableDefinitions> <telerik:RadGridView.HierarchyChildTemplate> <DataTemplate> <telerik:RadGridView ItemsSource="{Binding Path=SalesOrderItems}" AutoGenerateColumns="False"> <telerik:RadGridView.Columns> <telerik:GridViewDataColumn DataMemberBinding="{Binding Path=SalesOrderItemId}" /> <telerik:GridViewDataColumn DataMemberBinding="{Binding Path=Product.Name}" /> </telerik:RadGridView.Columns> </telerik:RadGridView> </DataTemplate> </telerik:RadGridView.HierarchyChildTemplate> 

Slightly more than ComponentOne, but a multi-level structure, like DevExpress, is still far away.

The detail of the line is perfectly edited in the detail, the grid looks nice.

Tree Grid

Initially I tried to implement this in the grid itself, changing the GridViewTableDefinition to TreeListViewTableDefinition . The interface has not changed. At first I was upset and in my comparison table I wrote down a fat minus, but I found that there is such a component RadTreeListView , which, together with RadGridView, have a common ancestor GridViewDataControl , and works exactly as the user expects.

This is how the markup is set:
 <telerik:RadTreeListView ItemsSource="{Binding Path=Departments}" AutoGenerateColumns="False" IsReadOnly="True" SelectionMode="Extended" ClipboardCopyMode="All"> <telerik:RadTreeListView.Columns> <telerik:GridViewDataColumn DataMemberBinding="{Binding Path=DepartmentId}" Header="" /> <telerik:GridViewDataColumn DataMemberBinding="{Binding Path=Name}" Header="" /> <telerik:GridViewDataColumn DataMemberBinding="{Binding Path=Head.Name}" Header=""/> </telerik:RadTreeListView.Columns> <telerik:RadTreeListView.ChildTableDefinitions> <telerik:TreeListViewTableDefinition ItemsSource="{Binding Children}"/> </telerik:RadTreeListView.ChildTableDefinitions> </telerik:RadTreeListView> 

At start it turns out such a grid:


Combining column headers. Multi-level column headers.

Here, too, everything is not bad. The combined column headers are set in the markup as follows:
 <telerik:RadGridView.ColumnGroups> <telerik:GridViewColumnGroup Header="" Name="StateGroup"/> </telerik:RadGridView.ColumnGroups> <telerik:RadGridView.Columns> <telerik:GridViewDataColumn Header="" ColumnGroupName="StateGroup"/> <telerik:GridViewDataColumn Header="" ColumnGroupName="StateGroup"/> <telerik:GridViewDataColumn Header="" ColumnGroupName="StateGroup"/> </telerik:RadGridView.Columns> 

It looks like this:

At the same time, unlike ComponentOne, all the functionality of the column headings remains:

But for Telerik, you cannot combine data cells, row headers and create truly multi-level column headers (more than 2 levels). Sad but tolerable.

Lazy loading records and support WCF DataServices

Telerik libraries have support for lazy loading records while scrolling in the grid. If you put a VirtualQueryableCollectionView into the grid's data source and implement the ItemsLoading event handler , then when scrolling the grid itself will request the download of the next piece of data. Also in the library there are extensible methods for System.Linq.IQueryable , which allow you to create such a query:
 VirtualQueryableCollectionView EntityList; … var query = (DataServiceQuery) _dataContext.SalesOrders .IncludeTotalCount() .Sort(EntityList.SortDescriptors) .Where(EntityList.FilterDescriptors) .Skip(start) .Take(count); 

As a result, in several movements we get a lazy grid with server filtering and sorting.

Copy to clipboard and export to Excel

It works similarly to the ComponentOne grid, except that the resulting Excel adds filters to the column headers. Merged column headers are great in Excel. The master part grid will export only the contents of the master table, the tree grid will export a flat table without hierarchy. In general, it is tolerable, but for more complex scenarios it is necessary to customize.

Copying to the buffer is customized, by intercepting the CopyingCellClipboardContent event, in the handler of which you can do everything your heart desires.

Print the contents of the grid

In the WPF grid, this functionality is not and is not expected. The official forum suggests using Telerik Reporting for this.

Localization

There is localization in 5 languages, but there is no Russian and Chinese. The site has a list of resources necessary for the localization of each of the controls. So this is solved by hiring a translator.

UI Automation Support

It's better here than ComponentOne - grid cells are still recognized as grid cells, but their RowIndex and ColumnIndex values ​​are zero. In general, in this aspect the grid from Xceed was the best.

Verdict

There are shortcomings, but not very critical. Yes, the scroller moves with jerks when there is a large number of entries (Xceed has this behavior best of all). Yes, it is impossible to print the contents of a grid by calling one method and you need to correct exporting multi-level lists to Excel. But overall, the grid is not bad.

findings


In the process of writing this article, I came across an interesting review , dated August 2008. The author comes to the disappointing conclusion that, despite the fact that all the 5 companies represented are leaders, none of them at that time provided enough quality grid.

It has been 4.5 years. It can be said that everything except Infragistics has made great strides and the choice is still difficult to make.


If we summarize the comparison and make recommendations by choice, then I would say so. If localization into several languages ​​is necessary, the data cells are merged and IQueryable support is not critical and there is no hierarchical grid in explicit business requirements, then ComponentOne will be a good choice. Otherwise, I would stop at the Telerik grid.

If we talk about the requirements of our project, we are torn between the last two. We need support for Russian and Chinese languages ​​(in the future and others), but at the same time we need a hierarchical grid and support for WCF DataServices. We have not yet come to the final choice and are weighing what will be more expensive: to translate all resources into two languages ​​(does not affect the performance of the system) or our own implementation of the hierarchical grid and support for WCF DataServices (potentially, there may be errors in implementation).

Source: https://habr.com/ru/post/167751/


All Articles