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,
I must be missing something.
The Format property of a cell only applies when that cell/control is not in edit mode. So it seems to me that if you use a format that limits the number of decimal places displayed and also shows the digit grouping separators (commas), then that's all you need to do. When the cell/control enters edit mode, the user will see the raw data without the separators and including all of the digits.
So... what's giving you trouble here?
Hi Mike, thanks for the speedy response. There are a couple of issues I'm having:
First, there is no Format property on a vanilla UltraTextEditor is there? (I got that from here http://news.infragistics.com/forums/p/6063/26556.aspx )
To get round that I have set the format via Properties Pane->Data Bindings->Advanced. That formatting then gets applied to both the View and Edit state - presumably because this is being done before the control gets the data? That's not the behaviour I need because it means that the reduced number of decimal places and comma separators are still there when the user edits.
(That only works at all if I bind the UltraTextEditor's Text property rather than its Value property.)
Obviously the UltraNumericEditor has a FormatString property, but the UltraNumericEditor requires you to define a fixed number of decimal places via the mask I believe, so I can't use it.
I also really want to define a view format that says "If there are two or less decimal places, then show 2dp, if there are more then show them all" which is something that can be done with .net formatting, but I don't think that can be done with the Infragistics style formatting strings? I think the Infragistics formatting strings are different to the .net ones?
Second: The value I'm binding to is a Decimal with 18 decimal places. Depending on how I bind the control and which control I use I keep getting all 18 of the decimal places when I start editing the data (this only occurs after I have round-tripped the data to and from SQL Server). That was what made me think I need to be able to format the edit mode as well as the view mode as I could use a format to knock off the superfluous trailing zeros.
redox said:First, there is no Format property on a vanilla UltraTextEditor is there? (I got that from here http://news.infragistics.com/forums/p/6063/26556.aspx )
Oh, yes, you are correct. The UltraTextEditor deals with strings, which don't support any formatting in DotNet, so it cannot format for you.
You have a lot of very specific requirements here, so it seems to me that you will have to use a DataFilter to achieve what you want, since that's the only way you will have enough control over the behavior.
redox said:I also really want to define a view format that says "If there are two or less decimal places, then show 2dp, if there are more then show them all" which is something that can be done with .net formatting, but I don't think that can be done with the Infragistics style formatting strings? I think the Infragistics formatting strings are different to the .net ones?
Generally, we don't do any formatting. When you apply a format to something, the Infragistics controls just call the ToString method of the value and pass in the Format. So the Infragistics format strings are exactly the same as the DotNet format string. But it's probably a moot point, since there's no Format property on UltraTextEditor and you want finer control over the behavior anyway.
redox said:Second: The value I'm binding to is a Decimal with 18 decimal places. Depending on how I bind the control and which control I use I keep getting all 18 of the decimal places when I start editing the data (this only occurs after I have round-tripped the data to and from SQL Server). That was what made me think I need to be able to format the edit mode as well as the view mode as I could use a format to knock off the superfluous trailing zeros.
You lost me a little bit here. If round-tripping the data to SQL Server is changing how it displays, then something is wrong. What's the data type of the field in SQL Server you are binding to? The only way I can see this happening is if you are binding the Text property of the control to a string field and using a DataFilter to change the string ends up updating your data source to include the zeroes.
It's generally not a good idea to store numeric values are strings, since this will cause all sorts of problems with sorting, filtering, and formatting.
Assuming your field in SQL Server is a decimal field, then you should be able to achieve what you want using the DataFilter and handling only the EditorToOwner and OwnerToEditor transitions.
In EditorToOwner you will have to take the string and convert it to a decimal. In OwnerToEditor, you reverse it, converting the decimal value into a formatted string in whatever format you like.
The only tricky part is using a different format based on whether the control is in edit mode or not. So your DataFilter will have to know this. You could just create a property on the DataFilter class and set this property when the UltraTextEditor enters or exits edit mode, then you use that property to determine which format to use whenever the OwnerToEditor transition fires.
Hi Mike
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.
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. :)
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")
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
Success! The hybrid version works a treat. Thanks for all of your help on this.