RadGridView - grouping and filtering for N3 numbers

0 Answers 182 Views
GridView
alex
Top achievements
Rank 2
Bronze
Iron
Iron
alex asked on 16 Sep 2023, 08:17 AM | edited on 16 Sep 2023, 08:21 AM

Hi,

I have many RadGridView columns with binding to a Double number with StringFormat: 0:N3.

I configured the grouping header text to show the value and the number of elements (Aggregate Function).

For example:

Frequency Column with the following rows:

123.123

123.123

The group header will be:

Frequency: 123.123 (2)

The problem is with larger numbers  For example:

123.1234

123.1235

On the cell, the user will see:

123.123

123.123

On the grouping headers, the user will see two groups:

Frequency: 123.123 (1)

Frequency: 123.123 (1)

On filtering, if the user selects equal to 123.123, the grid will display 0 rows.

Even if I update the Header Text to show N4 only when having 4 no zero decimals (using a converter), the filtering will not work as the user expects

I think that the easiest solution is to configure the grouping and filtering to apply the logic on the displayed value, how can I do that? (the display value is a string but the filtering operators shall be for number, it is an issue?)

Maybe another option is to write a custom filter/grouping where I can implement the operator logic on Math.Round 3 and then use it on the xaml?

I can't imagine any other simple solution but I am sure that you can :)

Please, I need a simpme solution that I can apply on the xaml styles to the whole application. I am not working with code behind at all to avoid copiying logic everywhere.

 

alex
Top achievements
Rank 2
Bronze
Iron
Iron
commented on 16 Sep 2023, 09:01 AM

I expect for the same behavior as Excel (I put the same values in both columns with a different display format)

 

 

alex
Top achievements
Rank 2
Bronze
Iron
Iron
commented on 19 Sep 2023, 06:22 PM | edited

Update:

I would like to remark that the problem is not only for N3 numbers, it is everywhere we used StringFormat or  CellTemplate AND the display value is different than the Raw value. I mentioned N3 just as en example of the issue. 

I am an advanced WPF developer with a lot of experience on custom controls, attached properties and Telerik controls. In our company we added massive functionality to Telerik controls. Consequently, it is very strange for us that something so simple is not possible (or we couldn't override it).

I tried different things like using converters, injecting different IFilterDescritors, overriding the GridViewDataColumn and overriding the FilteringControls.

Every possible solution only fixed the issue of displaying the correct "UI Value" on the ListBox of the FilteringControl. But even after trying to manupilate the value that the user types in the FilteringControl (inside my new FilteringControl) we stopped in front of the same wall: Telerik filtering implementation.

I tried to convert back the "user filter value" (tested with Double) to the same type and format as the Raw Value, but I can't use it because your logical operators are designed to a very specific logic. 

 

But, even if somehow we make this work, it will not solve the problem for other objects and/or complex types.

I expected from Telerik to expose some dependency property like: OnColumnFilteringFunction that will be called when the user clicks on Apply.

The function can receive the GridViewColumnBase, the user input values, selected operators, and the DataContext, cell value of each row, etc.

The function can be invoked for every row and return boolean.

With this simple solution, I can implement a simple predicate for every column where the UI value is not equal to RAW value (like we do easily with Linq).  It will be my responsabiliy to taking into consideration every user input and look for it in the objects.

In addition, you avoid the duplicates in the FilteringControl by exposing other function that I implement. It can't be based on IComparable since the UI value can be the same for different values (for example two doubles eith N3).

 

Again, I have read ALL your tutorials and answers since 2011 about this topic. In addition, my company pays a license for a lot of applications. In the past, I always used the Telerik forum without a ticket because your answered are fast and well explained (please check all my questions, I am very active on this forum).

I accepeted answers in the past like NOT performing Live Refresh due to performance (even if you could implement it and offer a propert to activate it).

I worked hard to perform an auto refresh mechanism combinened with your lightweight templates and it works :)

But, in this case using the RAW value IS NOT ACCEPTABLE. My users are complaining a lot because of this. I can't duplicate properties and use FilterMemberType as you suggested (I have thousands of objects refreshing every second and more than 10 columns out of 40 to duplicate for row DataContext for each grid!!!). I will not maintain additional columns for the UI. I know the MVVM concept but is not okay to do thiw for a missing functionality in your side. If you take me back few month ago, I could disable your filtering but my client already saw it and he wants it.

I underdtand why you are filtering on raw values by default (since you can't know how to filter an object or complex types compares to the input value) but I don't understand why you didn't expose a function or something else like you did in other controls or features. 

Please, take a look again on the full question description. I am sure that you can think on something to help me (and all your customers). Even if you need to add code to a future version, please consider this.

I can open a ticket for tracking this topic if needed but please let me know if you actually can fix that. I can't accept a generic response or reference to another tutorial that will not solve the problem.

We will release our application in one month and we need a solution soon as possible.

It is a lot of work for us to upgrade all our WPF Core Code and test it accross 15 applications but it will worth it. Upgrading Telerik nugets is the best option as I can see it.

Thank you,

Alex.

Martin Ivanov
Telerik team
commented on 26 Sep 2023, 09:26 AM

Hi Alex,

RadGridView always works with the raw value provided to the DataMemberBinding of the column. Any additional converter applied to the binding won't be taken into account. There is an item in the feedback portal to allow this.

alex
Top achievements
Rank 2
Bronze
Iron
Iron
commented on 26 Sep 2023, 07:05 PM | edited

Hello Martin,

Thank you for your reply. As I mentioned, it is not logical to don't implement this feature since with your current implementation we can say that you don't support filtering at all. Filtering on display value is not a requirement of my client, it is a common behavior in all applications (like Excel in the example).

Can you ask your team about my solution? maybe this solution is simple and not requires a lot of changes.

Just to expose a predicate to the column. This is a requirement of a lot of customers in the forum.

I can open with our license a ticket if needed. 

Martin Ivanov
Telerik team
commented on 27 Sep 2023, 07:25 AM

There is no need to open a support ticket if your idea is only to try raising the priority of this. I already forwarded your feedback to the team and increased the priority of the feature in the internal backlog. However, I can't give any specific promises for the implementation. You can follow the feedback item in order to get notified when its status changes.

As for the complexity of the feature, I am afraid that this won't be an easy solution, because it is coupled with the data operations in the RadGridView component. To allow converters, changes in the data engine of the control should be introduced and this should be tested extensively since it is going to bring kind of a breaking change. The breaking change will come from users that are already using a converter so that their display value is changed, but rely on the raw value for the data operations (sorting, grouping, filtering). 

One way to avoid the usage of converters is to use calculated properties in your view model, which are bound to the DataMemberBinding. For example:

public class RowInfo
{
	public string OriginalValue { get; set; }

	public string FormattedValue
	{
		get
		{
			// return OriginaValue formatted
		}
		set
		{
			// set a field for FormattedValue
			// or assign the OriginalValue to a value formatted back to its original form, based on your exact needs
		}
	}
}

<telerik:GridViewDataColumn DataMemberBinding="{Binding FormattedValue}" />

As a side note, I have noticed that you are posting questions in the forum frequently, but you mentioned you already have a license. I am bringing this up as a chance to note that the Telerik UI for WPF forums are a great place to exchange knowledge with the people using Telerik, but if you need a timely reply I recommend you to use the support ticketing system. The Telerik staff is trying to help in the forums, but we don't guarantee to provide answers here. If you use the ticketing system, you will take advantage of the corresponding response time (usually 24h or 72h, based on your license) and you will get in touch directly with the team responsible for Telerik's UI for WPF product.

alex
Top achievements
Rank 2
Bronze
Iron
Iron
commented on 28 Sep 2023, 07:44 PM | edited

Thank you Martin,

I will try to receive the company license/account to open tickets from there. Regarding my solution, it should not cause breaking changes if you offer expose an event where I can perform my filtering. By default the event will be null and your current logic will be executed.

It defenitely requires tests and further discussion, but I think that maybe is easiest than you think.

I don't know your internal logic but it seems easy to execute your filtering based on the Raw value + Converter OR an external code if was preconfigured.

At the end, you need a bool result for each item and then filter the CollectionView.

I hope your team will consider to implement it after 7 years it is open :)

I can't add the Row Info because I have more than 40 properties on many objects. These objects are refreshed múltiple times and duplicating properties can cause to performance issue and additional maintanance.

Thank you again!

Martin Ivanov
Telerik team
commented on 03 Oct 2023, 10:08 AM

This is already available. You can cancel the default filtering via the Filtering event and then implement custom logic.

private void RadGridView_Filtering(object sender, Telerik.Windows.Controls.GridView.GridViewFilteringEventArgs e)
{
	e.Cancel = true;
	// implement custom filtering here
}

If you don't want to use this in code behind, you can wrap it in a custom behavior or an attached property that can be assigned through a Style.

Note that there is the same event also for Grouping and Sorting.

Alternatively, you can consider implementing custom filtering control.

Currently, there is no easier solution. The easiest one would be to use a converter which as discussed is not supported yet. Other than that, custom filtering should be implemented, especially if you use CellTemplate to replace the value in the DataMemberBinding. RadGridView is using the DataMemberBinding in order to know what value should be used for the data operations. The CellTemplate can contain anything so there is no reliable way for the GridView to know what part of the UI there should be used for filtering, sorting or grouping.

alex
Top achievements
Rank 2
Bronze
Iron
Iron
commented on 03 Oct 2023, 04:54 PM | edited

Thank you Martin,

I know this event but the problem is that this event allows to cancel the filtering. The Removed and Added properties haven't any setter. I want to override the logic, which means telling to Telerik grid which items passed the filter or not (it will be easier to have a pre-filtering event where you pass the data context and I return the value to filter on, but this is the change that you are not going to implement...).

Can you share the source code where the Telerik grid iterates the collection items and executes the filtering with the converter? I would like to override this code and put my own logic (using reflection). I can decompile the dll for deep learning, but please guide me which classes should I look for and which nuget?

I know the problems and risks that my solution may cause but I don't see any other choise. I must deliver the applicaton and we would like to encapsulate the logic on the grid itself without touching the view model or model code.

Just to clarify, as far as I understood this is the filtering steps:

1. The grid receives the filter's values and operators (two operators). Currently, the grid receives the information from the default control (or my new custom control).

2. The grid filters the source collection (current items and new items that where added after the filter).

3. The filter is made on the RAW value after converter.

4. After having the items that passed the filter you redraw the grid.

If you show me the source code where step 3 is made, I will try to adapt it on my needs. The purpose is to filter on the displayed values. Then, I will create a new Filtering Control to show the ListBox with the display values. But to use the new filtering control I should override the filtering itself.

Thank you.

Martin Ivanov
Telerik team
commented on 06 Oct 2023, 12:10 PM

The filtering cannot be altered using reflection. That is because the filtering is not a simple method that changes the original data. It is not even part RadGridView. What RadGridView does is only to prepare the corresponding FilterDescriptor objects. These are then passed to the internal QueryableCollectionView class which knows how to filter data. The filtering itself is part of the Telerik's data engine (placed in Telerik.Windows.Data.dll). The engine is relatively complex and it works with .NET expressions to create the corresponding functions that filter the data.

When preparing the corresponding FilterDescriptor the RadGridView component is taking the Path of the DataMemberBinding of the column in order to provide it as a property path for the data engine, that is using this information to create the corresponding member access expression. There is no mean in the data engine to use an IValueConverter which is another major factor why this is not supported. 

If you want to explore the source code and make modifications, you can download it from a telerik.account with valid license for Telerik UI for WPF.

However, in my opinion it will be much easier to implement custom filtering from scratch for the columns with formatted values, using the currently available API, then modifying the Telerik's data engine. And idea that you can explore is to create a custom FilteringControl. This will allow you to define the same UI as the default one (you can use the default ControlTemplate of FilteringControl as a base) and implement C# code related to the new UI. To be more flexible when it comes to filtering, you can collect the values of the fields in the UI and then on Filter button click to create a generic filter descriptor where you can implement whatever filtering logic you need.

alex
Top achievements
Rank 2
Bronze
Iron
Iron
commented on 06 Oct 2023, 08:12 PM

Thank you Martin again for your detailed response.

We will try to implement it and let you know.

alex
Top achievements
Rank 2
Bronze
Iron
Iron
commented on 09 Oct 2023, 02:28 PM

Martin,

I've download the code. Can you guide me in which class, the filtering is made on the Telerik.Windows.Data.dll?

Martin Ivanov
Telerik team
commented on 10 Oct 2023, 08:26 AM

The filtering is relatively complex and it is not done in a single class. If you download the source code and open the Data_WPF.csproj project, you can find the main filtering infrastructure in the Filtering folder. However, these are the filtering models only (the FilterDescriptors). The models are used along with the expressions and expression builders in the Expressions folder. Additional to this, parts of the other code in Data project are involved in this action. If you want to modify the default behavior of the filtering in Data_WPF.csproj, you will need to take some time to explore the source and and modify it wherever you decide meaningful.
Motti
Top achievements
Rank 1
commented on 24 Oct 2023, 07:15 AM

Hello Martin, I downloaded the code and I opened the XCore_WPF.sln.

Controls_WPF and Data_WPF can't be loaded because I receive the following error:

Filter/Build/Tools/StyleCop.MsBuild.5.0.0\build\StyleCop.MSBuild.targetss was not found

Verify that file exists on disk:

Filter\Build\Imports\WPFImportsAtEnd.targets

The file doesn't exists.

Martin Ivanov
Telerik team
commented on 24 Oct 2023, 07:57 AM

Hi Motti, 

Please check the instructions for building the source code at the following directory:

\Telerik_UI_for_WPF_Source_2023_3_1010\Build\BuildInstructions\

Note that these instructions were updated and re-uploaded with the latest official release (R3 2023)

Basiaclly, you will need to open the following file and comment the StyleCop import:

\Telerik_UI_for_WPF_Source_2023_3_1010\Build\Imports\WPFImportsAtEnd.targets

 <!-- Source Analysis -->
 <!-- <Import Project="..\Tools\StyleCop.MSBuild.5.0.0\build\StyleCop.MSBuild.targets" Condition=" '$(NoSA)' == '' " /> -->

No answers yet. Maybe you can help?

Tags
GridView
Asked by
alex
Top achievements
Rank 2
Bronze
Iron
Iron
Share this question
or