Is it possible to use different formatting settings for the data displayed by a bound UltraTextEditor when it is being viewed and when it is being edited?
The behaviour I am particularly looking for in this instance is similar to Excel, where a number is shown with a pre-configured number of decimal places with comma separators when it isn't being edited, but switches to show all of the decimal places and no commas when the user is editing the value.
I suppose what I really want to be able to do is to set the .Net String.Format property for the data in the control separately depending on whether the control is in View or Edit state.
I have worked through this post http://forums.infragistics.com/forums/t/6140.aspx, but like that guy I don't really want to use a masked control as I don't want a fixed number of decimal places when editing (just when viewing). I tried the suggestion there of creating a data filter, but that only works on what is displayed when you are viewing, the mask takes over when you are editing and so you are stuck with a fixed number of decimal places again.
I suppose one option is to roll my own control based on two UltraTextEditors inside a UltraControlContainerEditor; that would allow me to use two datafilters, one for the Edit text editor and one for the view text editor, and to set the different formats for data in the text editors via those datafilters.
That might work, but it seems a long way round, is there an easier way?
Hi Mike
Success! The hybrid version works a treat. Thanks for all of your help on this.
Hi,
redox said:As far as I can tell the OwnerToEdit conversion doesn't fire again after the control switches to Edit mode, so there doesn't seem to be a point at which I can change the formatting in response to editing starting?
Hm, that's unfortunate.
I guess the alternative is - don't bind the control and then use the BeforeEnterEditMode and AfterExitEditMode events to change the Value of the UltraTextEditor directly. And then you will have to manually handle the getting and setting of the value from the data source.
I guess you could also take sort've a hybrid approach. You could use the DataFilter to format the value only when the control is not in edit mode. When it enters edit mode, you can use the AfterEnterEditMode event to modify the text in the child TextBox control that UltraTextEditor uses. Something like this:
Private Sub UltraTextEditor1_AfterEnterEditMode(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles UltraTextEditor1.AfterEnterEditMode Dim ute As UltraTextEditor = CType(sender, UltraTextEditor) Dim tb As TextBox = CType(ute.Controls(0), TextBox) Dim d As Decimal Dim success As Boolean = Decimal.TryParse(ute.Value, d) If (success) Then tb.Text = d.ToString("0.#######") Else tb.Text = d.ToString("Not Numeric") End If End Sub
We didn't believe it either, but as you say, once you are aware it happens there is documentation out there that shows that this is the expected .net behaviour for a decimal.
I've now tried your suggestion above, but am having no luck. As far as I can tell the OwnerToEdit conversion doesn't fire again after the control switches to Edit mode, so there doesn't seem to be a point at which I can change the formatting in response to editing starting?
This is the code for my converter and events:
Public Class DecimalDataFilter Implements Infragistics.Win.IEditorDataFilter Private Property FormatString As String Private _inEditMode As Boolean Public Property InEditMode As Boolean Get Return _inEditMode End Get Set(value As Boolean) _inEditMode = value Debug.Print("InEditMode Property set to: " + _inEditMode.ToString()) End Set End Property Public Function Convert(ByVal args As Infragistics.Win.EditorDataFilterConvertArgs) _ As Object Implements Infragistics.Win.IEditorDataFilter.Convert Select Case args.Direction Case ConversionDirection.EditorToOwner args.Handled = True Debug.Print("Editor to owner, in edit " + InEditMode.ToString()) If IsNumeric(args.Value) Then 'Debug.Print("E2O, is numeric") Return Decimal.Parse(args.Value.ToString()) Else 'Debug.Print("E2O, NOT numeric") Return 0 End If Case ConversionDirection.OwnerToEditor args.Handled = True Debug.Print("Owner to editor, in edit " + InEditMode.ToString()) If Me.InEditMode Then ' Debug.Print("O2E, in edit mode, FormatString = 0.#######") Me.FormatString = "0.#######" Else 'Debug.Print("O2E, in edit mode FormatString = #,0.00") Me.FormatString = "#,0.0" End If If IsNumeric(args.Value) Then Dim valueToFormat As Decimal = Decimal.Parse(args.Value) Return valueToFormat.ToString(Me.FormatString) 'Debug.Print("O2E, is numeric, valAsString = " & valAsString) Else Return "NOT NUMERIC!!" End If Case Else 'this case can never happen Return Nothing End Select End Function End Class Private Sub CapacityInUnitsUltraTextEditor_AfterEnterEditMode(sender As Object, e As System.EventArgs) Handles CapacityInUnitsUltraTextEditor.AfterEnterEditMode Debug.Print("UTE After enter edit") Dim decFilter As DecimalDataFilter = DirectCast(Me.CapacityInUnitsUltraTextEditor.DataFilter, DecimalDataFilter) decFilter.InEditMode = True End Sub Private Sub CapacityInUnitsUltraTextEditor_AfterExitEditMode(sender As Object, e As System.EventArgs) Handles CapacityInUnitsUltraTextEditor.AfterExitEditMode Debug.Print("UTE After exit edit") Dim decFilter As DecimalDataFilter = DirectCast(Me.CapacityInUnitsUltraTextEditor.DataFilter, DecimalDataFilter) decFilter.InEditMode = False End Sub Private Sub CapacityInUnitsUltraTextEditor_BeforeEnterEditMode(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles CapacityInUnitsUltraTextEditor.BeforeEnterEditMode Debug.Print("UTE Before enter edit") Dim decFilter As DecimalDataFilter = DirectCast(Me.CapacityInUnitsUltraTextEditor.DataFilter, DecimalDataFilter) decFilter.InEditMode = True End Sub
Public Class DecimalDataFilter
Implements Infragistics.Win.IEditorDataFilter
Private Property FormatString As String
Private _inEditMode As Boolean
Public Property InEditMode As Boolean
Get
Return _inEditMode
End Get
Set(value As Boolean)
_inEditMode = value
Debug.Print("InEditMode Property set to: " + _inEditMode.ToString())
End Set
End Property
Public Function Convert(ByVal args As Infragistics.Win.EditorDataFilterConvertArgs) _
As Object Implements Infragistics.Win.IEditorDataFilter.Convert
Select Case args.Direction
Case ConversionDirection.EditorToOwner
args.Handled = True
Debug.Print("Editor to owner, in edit " + InEditMode.ToString())
If IsNumeric(args.Value) Then
'Debug.Print("E2O, is numeric")
Return Decimal.Parse(args.Value.ToString())
Else
'Debug.Print("E2O, NOT numeric")
Return 0
End If
Case ConversionDirection.OwnerToEditor
Debug.Print("Owner to editor, in edit " + InEditMode.ToString())
If Me.InEditMode Then
' Debug.Print("O2E, in edit mode, FormatString = 0.#######")
Me.FormatString = "0.#######"
'Debug.Print("O2E, in edit mode FormatString = #,0.00")
Me.FormatString = "#,0.0"
Dim valueToFormat As Decimal = Decimal.Parse(args.Value)
Return valueToFormat.ToString(Me.FormatString)
'Debug.Print("O2E, is numeric, valAsString = " & valAsString)
Return "NOT NUMERIC!!"
Case Else
'this case can never happen
Return Nothing
End Select
End Function
End Class
Private Sub CapacityInUnitsUltraTextEditor_AfterEnterEditMode(sender As Object, e As System.EventArgs) Handles CapacityInUnitsUltraTextEditor.AfterEnterEditMode
Debug.Print("UTE After enter edit")
Dim decFilter As DecimalDataFilter = DirectCast(Me.CapacityInUnitsUltraTextEditor.DataFilter, DecimalDataFilter)
decFilter.InEditMode = True
End Sub
Private Sub CapacityInUnitsUltraTextEditor_AfterExitEditMode(sender As Object, e As System.EventArgs) Handles CapacityInUnitsUltraTextEditor.AfterExitEditMode
Debug.Print("UTE After exit edit")
decFilter.InEditMode = False
Private Sub CapacityInUnitsUltraTextEditor_BeforeEnterEditMode(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles CapacityInUnitsUltraTextEditor.BeforeEnterEditMode
Debug.Print("UTE Before enter edit")
Hmm, very interesting. I didn't think this was possible, but I did a little research and apparently, the decimal data type has a scale factor which retains trailing zeroes.
So if you do this:
decimal d = 21.2000m; Debug.WriteLine(d);
You get this:
21.2000
Live and learn. :)
That looks like a potentially great solution, I hadn't thought of looking for enter/exit edit mode properties on the text editor - that sounds like it could be the missing piece. I will give it a go.
Re SQL changing the data:
We are using a decimal in both the code and in SQL Server (2008 R2). When we assign a value to the decimal property in code it gets just the number of decimal places the user entered. When we save and reload the data from the database it then has the number of decimal places defined on the database.
So, if the user enters 21.1 in a control bound to a user class then that value will stay as 21.1 until the data in the class is reloaded from the database. As soon as that happens then the value will show as 21.1000 (if the value was defined as say Decimal(10.4) in SQL, i.e. with 4DP). This happens on both UltraTextEdtiors and in grid columns.
I'm guessing that the reason is that .net holds the decimal value as a literal in memory, so if the value is set to 21.1000 then .net doesn't knock off the trailing zeros, it just holds it in memory like that. When the infragistics controls then access the ToString property 21.1000 is returned, rather than the 21.1 I would have expected.
If you create a Decimal(10,4) column in a table in SQL and enter 21.1 into that field via the editor SQL will save and display that value as 21.1000. I guess it also reports the value back to our code as 21.1000 and so this is the value that gets put in the class's property and consequently into the control.