I have a derived grid that has number formatting applied to the columns to prevent them from showing decimal places.
I set the grid to do its default Copying:
base.DisplayLayout.Override.AllowMultiCellOperations = AllowMultiCellOperation.CopyWithHeaders;
When it copies to the clipboard, it copies as text exactly what is displayed in the grid, which means it truncates the decimals (just like I do in the grid). However, since the grid knows what the full value is, i would like the copy behavior to essentially copy the data in a manner to not lose any of the decimal places when I paste the data elsewhere.
How can I do this? Thank you.
Hi Robert,
The grid (usually) copies what the user sees. It would probably be confusing for a user to copy from the grid and paste it only to find that what he pasted doesn't match what he copied.
I took a look at the code to see if I could find a solution for you, and it looks like what the grid does is it fires the BeforeMultiCellOperation, which gives you a chance to change the values being written to the clipboard. But it applies to Formatting to the values immediately after the event fires and there's no way to prevent it.
So there are two ways you can achieve what you want.
Method 1:
Change the value that is being sent to the clipboard to a string representation of the value. The string data type doesn't support any formatting. So if you change the value to a string, you will get what you put in.
private void ultraGrid1_BeforeMultiCellOperation(object sender, BeforeMultiCellOperationEventArgs e) { if (e.Operation == MultiCellOperation.Copy) { foreach (UltraGridCell cell in e.Cells) { if (cell.Column.Key == "Decimal 1") { e.NewValues[cell].Value = cell.Value.ToString(); } } } }
Method 2
Temporarily remove the formatting from the column while the copy operation is occurring.
string cachedFormat = null; private void ultraGrid1_BeforeMultiCellOperation(object sender, BeforeMultiCellOperationEventArgs e) { if (e.Operation == MultiCellOperation.Copy) { foreach (UltraGridCell cell in e.Cells) { if (cell.Column.Key == "Decimal 1") { this.cachedFormat = cell.Column.Format; cell.Column.ResetFormat(); } } } } private void ultraGrid1_AfterPerformAction(object sender, AfterUltraGridPerformActionEventArgs e) { UltraGrid grid = (UltraGrid)sender; if (cachedFormat != null && e.UltraGridAction == UltraGridAction.Copy) { grid.DisplayLayout.Bands[0].Columns["Decimal 1"].Format = this.cachedFormat; this.cachedFormat = null; } }
I just threw this code together quickly, so its assuming that there is only one column that you need to deal with here. If you have more than one, then it would probably be wise to create a better caching structure that holds the formats for each column and keys them on the column object itself in a dictionary.
The advantage of Method 1 is that it's much easier to implement. The down side is that if you are copying to Excel, you will end up copying a numeric value as a string. Excel will give you a warning and you won't be able to use the value in a formula, since it will be a string.
Method 2 maintains the numeric value, but it's more code and also I'm not thrilled about the idea of changing the format of the column dynamically like this. It's probably not very efficient and there's a risk that there might be a case where BeforeMultiCellOperation fires and AfterPerformAction doesn't and then you could end up losing the formatting on the on-screen grid.
Your solutions are good, but not quite good enough. I do need the paste in excel to be pasted as the actual numbers, not as a text string which the users then have to format differently.
And, i need to retain the flexibility to have different cell formats on a per cell basis, and writing a caching script to keep all that in memory, seems pretty heavy-weight...
I'll probably go with the second method, but I was hoping that this was a problem that other users had raised before and there was an established light-weight solution (although I couldn't find one when searching thru the forums).
Anyway, please let me know if you think of anything else! Thank you.
I fear this will get too heavyweight for when I have a grid with hundreds of thousands of rows, where each cell can have its own format, but for now your solution 2 is working for me since my grids are smaller and simpler. Here is my slightly altered code below. We can mark this thread as answered unless anyone can think of a better solution.
Dictionary<UltraGridColumn, string> _CopyPasteCachedColumnFormats = new Dictionary<UltraGridColumn, string>();
void AveryGrid_AfterPerformAction(object sender, AfterUltraGridPerformActionEventArgs e) { UltraGrid grid = (UltraGrid)sender;
if (_CopyPasteCachedColumnFormats.Count > 0 && e.UltraGridAction == UltraGridAction.Copy) { foreach (UltraGridColumn dc in _CopyPasteCachedColumnFormats.Keys) { dc.Format = _CopyPasteCachedColumnFormats[dc]; }
_CopyPasteCachedColumnFormats.Clear(); }
}
void AveryGrid_BeforeMultiCellOperation(object sender, BeforeMultiCellOperationEventArgs e) { if (e.Operation == MultiCellOperation.Copy) { foreach (UltraGridCell cell in e.Cells) { if (!_CopyPasteCachedColumnFormats.ContainsKey(cell.Column)) { _CopyPasteCachedColumnFormats.Add(cell.Column, cell.Column.Format); cell.Column.ResetFormat(); } } }