This article shows how to implement filtering in TRichViewEdit column of TcxGrid (a grid VCL control by DevExpress).
Let’s take the demo in DevExpress\VCL\Demos\ExpressQuantumGrid\Delphi\FilterDemo as a base.
At the first step, we change the type of “Product” column to TRichViewEdit, and value type to Markdown.
In the Object Inspector, we select TableViewProduct.Properties = “TRichViewEdit”, and set TableViewProduct.Properties.EditValueSaveFormat = cxrvvfUnicodeMarkdown.
Also, we set TableView.OptionsView.CellAutoHeight = True.
Now we have “Product” column displayed and edited using TRichViewEdit. Initially, values are stored as plain text, but if you edit some value, it will be saved back as Markdown.
The demo does not have user interface for formatting text, but you can paste text from another rich text editor (such as our RichViewActions demo, or WordPad, or Microsoft Word)
You can see the filter “Express*” (that is created in code), and it works for plain text values. But if you paste a formatted text in some row, like “ExpressFlowChart”, it will not match.
Filtering by display text
The filter is not matched because the grid compares the filter string not with the display text, but with the raw value. In our case, with Markdown code.
How to match filter with a display text instead of a raw value?
We need to assign
TableView.DataController.Filter.CompareByDisplayValues := True;
This property is public, not published, so we assign it in code, in TfrmMain.FormCreate.
You can see, the filter works now:
How to activate filtering
However, we only started making progress. Actually, filtering is not enabled in TRichViewEdit columns by default, and only a filter created by code works.
You can see:
- there is no a filter icon in “Product” header
- the filter string is in the filter row (the top grid row) is read-only
- if you click the filter customization button (“Customize”, bottom right corner), you will not see the condition for “Product”.
To enable filtering, assign TableViewProduct.Properties.AllowFilteriing = True.
Why is it not enabled by default?
Because it makes sense to use TRichViewEdit for non-plain-text date, and it should be filtered by display text, and it requires Filter.CompareByDisplayValues := True.
But this setting affects the whole grid, not only our column. It may cause problems with filtering other, non-text, columns
(I think this is the reason why CompareByDisplayValues is not published, and why a built-in DevExpress rich edit column does not implement filtering).
Nevertheless, let’s proceed.
Filter Builder dialog
Now we can modify the filter in the Filter Builder dialog:
And it works for Markdown data:
Custom Filter dialog
Let’s try another dialog: Custom filter.
To display it, we need to remove a date-related condition (to make a filter simpler), to click on the filter icon in “Product” header, and select the “(Custom…)” item.
And it works for Markdown data:
Filtering using a check list box
Let’s try to check items in the list that is shown when you click a filter icon.
You can see two “ExpressFlowChart” items. Let’s check one of them:
Oops. Nothing is matched.
It happens because CompareByDisplayValues setting does not affect content of this list box.
As a result:
- you can see two “ExpressFlowChart” in the list; they have the same display string, but different raw values (one is Markdown, another one is a plain text)
- the grid compares the raw value of the item (Markdown) with the display text of data, and they are not equal.
I think this is a flaw of CompareByDisplayValues implementation in the grid.
But there is a workaround: we can use OnGetFilterValues event for our column to update values of items in this list: to make raw values equal to their display text, and to remove possible duplicates.
To do it, we can use UpdateFilterValues procedure from the new cxTRichViewFilter.pas unit:
uses cxTRichViewFilter;
procedure TfrmMain.TableViewProductGetFilterValues(
Sender: TcxCustomGridTableItem; AValueList: TcxDataFilterValueList);
begin
UpdateFilterValues(AValueList,
fcoCaseInsensitive in TableView.DataController.Filter.Options);
end;
We did it!
Filter row
And the last problem is a filtering row (an optional top row in the grid where you can enter filter values).
If you try to type something above the product values, nothing is matched the updated filter string.
The reason is similar to the problem with the check list items. The grid creates TRichViewEdit to type the filter condition, and compares its raw data (Markdown in our case) with display text of data. One more problem with CompareByDisplayValues implementation!
Fortunately, OnGetProperties event can help us: we can create a plain text editor for filtering row of our column.
Let’s add cxTextEdit in uses, and FilterProps field to our form:
FilterProps: TcxTextEditProperties;
The code for OnGetProperties is
procedure TfrmMain.TableViewProductGetProperties(
Sender: TcxCustomGridTableItem; ARecord: TcxCustomGridRecord;
var AProperties: TcxCustomEditProperties);
begin
if (ARecord is TcxGridFilterRow) and (AProperties is TcxRVProperties) then
begin
if FilterProps = nil then
begin
FilterProps := TcxTextEditProperties.Create(nil);
FilterProps.Assign(AProperties);
end;
AProperties := FilterProps;
end;
end;
We can destroy FilterProps when the form is freed:
procedure TfrmMain.FormDestroy(Sender: TObject);
begin
inherited;
FilterProps.Free;
end;
Result:
Sorting
That’s all about filtering. This information can be found (in a compact form) in the comments at the beginning of cxTRichViewFilter.pas.
PS: by the way, you can see one more new feature: sorting.
Unlike filtering, it just works. TRichViewEdit columns are sorted by display text (by default).