Reputation: 491
I have a need to create a custom version of the UWP DataGridNumericalColumn
that allows customization of the RadNumericBox
properties (ValueFormat
, ButtonsVisibility
, SmallChange
, LargeChange
, Value
) as well as the ability to edit the value as cents (199) without decimal place while editing, but display as normal dollars with decimal cents (1.99) while not editing. I've tried two different approaches to extend existing controls, neither of which I can seem to get to work fully for me.
1) Tried deriving from DataGridNumericalColumn
- impossible due to inaccessible internal members down the line, even with full source code from GitHub available.
2) Tried deriving from DataGridTemplateColumn
- somewhat workable for initial display, but everything relating to inline edit mode vs display mode and validation message display on the cell seems beyond reach (not override-able) and I can't seem to use CellContentTemplateSelector
to choose between the inline Edit mode RadNumericBox
display and the normal TextBlock
display because I can't seem to detect when Edit mode is applied to the cell.
It is starting to seem like the only way I can achieve what I need is to fork the GitHub code-base so I can derive from DataGridNumericalColumn
with access to internal code.
What approach could I take to achieve my desired customizations?
(I am using Telerik UI For Universal Windows Platform, version 2017.1.301.45, at the time of this writing.)
Upvotes: 0
Views: 297
Reputation: 491
I eventually worked out workarounds that let me get past the main difficulties in extending this functionality using the derive from DataGridTemplateColumn
approach. Here are the updates and customizations I made - they are described mostly at the conceptual level, but it should be enough for others to duplicate this sort of customization for themselves.
UPDATE1:
An update as I've been working on this:
Continuing along with the approach of deriving from DataGridTemplateColumn
, I found that I can successfully change my displayed markup for edit mode vs display mode by creating custom commands for editing operations in the grid (CustomBeginEditCommand
, CustomCancelEditCommand
, and CustomCommitEditCommand
very similar to the ones in http://docs.telerik.com/devtools/universal-windows-platform/controls/raddatagrid/features/commands/editing-commands/datagrid-editingcommands-begineditcommand ) along with an interface IItemAwareOfEditMode
, applied to the ViewModel items for the Grid's data, that has a single bool property IsInEditMode
that I set to true
or false
appropriately in the custom commands, which is then used in a custom DataTemplateSelector
to decide when to apply my edit markup vs my display markup. This uses (DataTemplate)XamlReader.LoadWithInitialTemplateValidation(editControlMarkup)
for translating dynamically created markup strings to DataTemplate
s. For my implementation, I create the markup in a PropertyChangedCallback
for my custom column's PropertyNameProperty
dependency property.
However, I still am having issues with validation and displaying the validation messages, and reverting values when the user cancels edit. I have the ViewModel for the grid row items implemented such that they derive from ValidateViewModelBase
, and so they add/remove errors appropriately according to the documentation on validation at http://docs.telerik.com/devtools/universal-windows-platform/controls/raddatagrid/features/validation . If I use the DataGridNumericalColumn
(not customized) with the same data, the validation messages do appear pointing to the cell when the data is invalid, but with my custom column, HasErrors
is true on the items, but the validation messages don't appear. Looking at the validation code in https://github.com/telerik/UI-For-UWP/blob/master/Controls/Grid/Grid.UWP/View/Columns/TypedColumns/DataGridTypedColumn.cs in the CreateEditorContainer
function, it seems there is an EditRowHostPanel
and ValidationControl
involved along with the editor content, but I don't have access to pieces needed to implement the container exactly as is done there.
What can I do to get the validation messages to appear as they do in the DataGridNumericalColumn
?
Also, what can I do to make cancelling an edit (clicking the blue X for the row when in edit mode) actually revert my custom column's value to what it was prior to entering edit mode?
UPDATE2:
Another update as I've been working on this:
Continuing along with the approach of deriving from DataGridTemplateColumn
, I've managed to successfully display validation messages for the edit mode by including a ValidationControl
in the edit mode template markup, which references the RadNumericBox
from the template (by Name) using the ControlPeer
property, and giving its DataItem
property a value of "{Binding}"
, and appropriately populating its PropertyName
.
This is getting close to what I need, but it seems that my CustomCancelEditCommand
, which uses
Owner.CommandService.ExecuteDefaultCommand(CommandId.CancelEdit, context);
, does not appropriately update the display of the cell to its previous value. It correctly doesn't call the CustomCommitEditCommand
when the inline row edit is cancelled; however, it displays as the modified value (not reverted to the value prior to edit). Even if you edit again, the value remains as the modified value when displayed in the grid.
I see that in https://github.com/telerik/UI-For-UWP/blob/master/Controls/Grid/Grid.UWP/View/Services/Commands/Editing/CancelEditCommand.cs in the Execute
method, that it executes its base implementation, followed by
Owner.editService.CancelEdit(context.TriggerAction)
, which I don't understand (RadDataGrid
does not contain a definition for editService
and I can't derive from that CancelEditCommand
class because it is internal).
What can I do to make cancelling an edit (clicking the blue X for the row when in edit mode) actually revert my custom column's value to what it was prior to entering edit mode?
UPDATE3: I have finally managed an EXTENSIVE workaround that does revert my custom columns' value on cancel.
My workaround for the cancel functionality involved:
1) Created a CustomRadDataGrid
, which derives from RadDataGrid
.
2) Gave my CustomRadDataGrid
class a CustomEditingService
property, which is a CustomEditingService
, which is copied and modified code from EditingService
(mostly commenting out unneeded parts, but also changing InitializeEditOperation
's implementation and changing CancelEdit
to have an out parameter of the operation's OriginalValues
dictionary), and which derives from CustomServiceBase<RadDataGrid>
, which is copied and modified code from ServiceBase
(changed IsOperational
to return Owner.DataContext != null
), which derives from CustomAttachableObject<T> where T : RadControl
, which is copied code from AttachableObject
.
3) Added GetActualValueForInstance
function and SetActualValueForInstance
method to my custom column, which uses reflection to get/set the data row instance's value for this column (based on using my PropertyName
Dependency Property's value), and made the InitializeEditOperation
of my CustomEditingService
just save original values of my custom columns, and made the CancelEdit
of my CustomEditingService
return that dictionary of original values in an out variable.
4) Made my CustomBeginEditCommand
call BeginEdit
on the grid's CustomEditingService
after calling Owner.CommandService.ExecuteDefaultCommand(CommandId.BeginEdit, context)
- that allows my custom column original values to be stored.
5) Made my CustomCommitEditCommand
call CommitEdit
on the grid's CustomEditingService
after calling Owner.CommandService.ExecuteDefaultCommand(CommandId.CommitEdit, context)
- that allows my custom editing service to properly track its editing state.
6) Made my CustomCancelEditCommand
call CancelEdit
on the grid's CustomEditingService
AND for each original value dictionary item, use the Key
(column, as my custom column) SetActualValueForInstance
passing in context.CellInfo.Item
and the Value
(previously stored original value), BEFORE calling Owner.CommandService.ExecuteDefaultCommand(CommandId.CancelEdit, context)
- that restores my custom column original values prior to the standard cancel actions occurring.
Done! Whew... It seems that this library needs a lot of changes to allow for better extend-ability. This has been logged as a feature request at Telerik according to a reply to my support ticket with them on this subject.
I think other people will want to be able to extend Telerik's various DataGridColumn
controls too, so I shared my struggle and (eventually) successful customization here.
Upvotes: 1