http://www.telerik.com/community/forums/winforms/gridview/timepicker-column-in-radgridview-at-runtime.aspx
The app is using this custom editor to enter default personnel schedules. It would be very labor-saving to copy the ArriveTime and/or DepartTime on Monday and simply paste it into the corresponding cell in the rows below. That is my goal, and the users' wish, but it is not working for the following series of reasons:
I am marking the row as "dirty" (i.e. needs to be persisted) in the CellValueChanged event and then later testing to see if the row is dirty in the RowValidating event, and if so, I save it to the database. The aim here is to avoid much unnecessary database i/o; only "dirty" rows are written to the database. However, the paste operation does not cause the CellValueChanged event to fire, and so the row is never marked as having been changed.
QUESTION: Is there a code change I can make to the TimePicker that would cause a paste operation to fire the CellValueChanged event?
void
DFGRID_CellValueChanged(
object
sender, Telerik.WinControls.UI.GridViewCellEventArgs e)
{
e.Row.Tag =
"dirty"
;
}
16 Answers, 1 is accepted
Thank you for writing.
The CellValueChanged event is fired when the value of the cell is changed. This happens when end edit operation is performed and the current editor is closed. You can use the ValueChanged event to handle the case when the value of the editor is changed by paste operation.
I hope this helps.
All the best,
Svett
the Telerik team
CellValueChanged
Fires when the value of a cell changes
ValueChanged
Fires when the value of an editor changes
Since I wasn't invoking the editor when I pasted the value, it was reasonable to assume, from these descriptions, that CellValueChanged was the appropriate choice.
What is the best way to find, in Visual Studio, the method signature for a given Telerik event?
When I explore the object hierarchy in the Object Browser, I see:
Telerik.WinControls.UI.Data
-- ValueChangedEventHandler
Invoke(object, Telerik.WinControls.UI.Data.ValueChangedEventArgs)
but this does not compile:
void grid_ValueChanged(object sender, Telerik.WinControls.UI.Data.ValueChangedEventArgs e)
{
....
}
I also tried ValueChanging event but it does not fire when a value is pasted into the editor:
void grid_ValueChanging(object sender, Telerik.WinControls.UI.ValueChangingEventArgs e)
{
grid.CurrentRow.Tag = true; // does not fire with paste
}
Thanks
You should subscribe to the events in the following manner:
grid.ValueChanging +=
new
ValueChangingEventHandler(grid_ValueChanging);
grid.ValueChanged +=
new
EventHandler(grid_ValueChanged);
void
grid_ValueChanging(
object
sender, ValueChangingEventArgs e)
{
}
void
grid_ValueChanged(
object
sender, EventArgs e)
{
}
I hope this helps.
Greetings,Svett
the Telerik team
the ValueChanged Event does not fire, if I paste the value to a TextBoxColumn.
What is the problem.
Best regards
Fritz
Thank you for writing.
You can use the Pasting event of RadGridView (introduced Q1 2013) to detect pasting of data in a cell.
I hope this will be useful. Should you have further questions, I would be glad to help.
Regards,
Ivan Petrov
Telerik
Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
Sign up for Free application insights >>
How can I detect what cells are changing from the Pasting event. My goal is to change the backcolor whenever a cell value changes. Would be nice if CellValueChanged fired during paste.
Thanks a lot,
John
Thank you for writing.
The CellValueChanged event is not fired because the template in which you are pasting is in a Begin-EndUpdate block. This is done with performance in mind because if you try to paste, say 10 000 rows of data in several columns and the grid is updated on every cell value change it would seriously impact the duration of the operation.
You can use the following code snippet to get the cells whose values will be changed in the Pasting event:
List<GridViewCellInfo> cells =
new
List<GridViewCellInfo>();
private
void
radGridView1_Pasting(
object
sender, GridViewClipboardEventArgs e)
{
if
(e.Format ==
"Text"
)
{
object
obj = e.DataObject.GetData(DataFormats.UnicodeText);
string
str = obj
as
string
;
this
.cells.Clear();
StringTokenizer rowTokenizer =
new
StringTokenizer(str, Environment.NewLine);
int
rowTokens = rowTokenizer.Count();
StringTokenizer columnTokenizer =
new
StringTokenizer(rowTokenizer.NextToken(),
"\t"
);
int
colTokens = columnTokenizer.Count();
for
(
int
i = 0; i < rowTokens && i < e.Template.Rows.Count; i++)
{
for
(
int
j = 0; j < colTokens && j < e.Template.Columns.Count; j++)
{
cells.Add(e.Template.Rows[
this
.radGridView1.CurrentRow.Index + i].Cells[e.Template.CurrentColumn.Index + j]);
}
}
}
}
Then you can use the list populated inside the Pasting event inside the CellFormatting event:
private
void
radGridView1_CellFormatting(
object
sender, CellFormattingEventArgs e)
{
GridViewCellInfo cellInfo = e.Row.Cells[e.Column.Index];
if
(
this
.cells.Contains(cellInfo))
{
e.CellElement.BackColor = Color.Yellow;
e.CellElement.DrawFill =
true
;
e.CellElement.GradientStyle = GradientStyles.Solid;
}
else
{
e.CellElement.ResetValue(LightVisualElement.BackColorProperty);
e.CellElement.ResetValue(LightVisualElement.DrawFillProperty);
e.CellElement.ResetValue(LightVisualElement.GradientStyleProperty);
}
}
I hope this will help. Feel free to write back with further questions.
Regards,
Ivan Petrov
Telerik
Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.
Thanks for your response. This is now working.
But I have one othe pasting issue. Some of my columns are Combobox columns (with DropDownStype = DropdownList) and some are Datetime columns. I would like to prevent values which are not in the list or are not dates from being pasted into those columns. What's the best way to accomplish this.
Thanks again,
John
Thank you for writing back.
When a user tries to paste invalid data into a RadGridView's column the pasting operation is aborted before this value is stored. The cells before such a mismatch occurs are saved and the rest of the cells, that should be pasted over, remain intact.
If I understand your requirement correctly you want to skip over these columns/cells and perform the paste operation only on the cells for which a correct value is in the clipboard. If this is the case you will have to handle the whole paste operation. What you have to do is use the data object provided in the Pasting event arguments to get the clipboard data and store it in the appropriate cells. In the end you should cancel the default paste operation through the Cancel property of the Pasting event arguments. You can use the helper classes from my previous post to get the data from the data object.
I hope this will give you an idea where to start. If you need help in the implementation, feel free to write back.
Regards,
Ivan Petrov
Telerik
Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.
Thanks for your reply. But when I paste invalid data into a gridview the pasting operation is NOT aborted - everything is pasted. Is there a property that needs to be set to cause pasting to terminate? Actually I would prefer to trap the error before any cells are modified - even the cells before a mismatch occurs - if this is an option.
Thanks,
John
To achieve this, you should handle the Pasting event and place your validation logic there. If the validation fails, you can just the cancel the event and nothing will be pasted. To be able to run a validation logic though you would need to be able to parse the raw data into rows. I am attaching a sample project which demonstrates how you can achieve this.
I hope you find this useful. Let me know if you have any additional questions.
Regards,
Ivan Todorov
Telerik
Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.
Thanks for your reply. As you suggested I put validation logic in the pasing event and am setting Cancel=True if validation fails. (btw I did not find any attachment). It works fine except that the pasting event seems to be invoked multiple time (3 or 4) for each paste and since I am displaying an error message in a MsgBox when validation fails the MsgBox is displayed multiple times. Any ideas why this is happening and how to prevent it.
Thanks,
John
Thank you for writing back.
Here is the sample code snippet from the project, provided by my colleague, Ivan Todorov:
List<DayOfWeek> comboColumnSource =
new
List<DayOfWeek>() { DayOfWeek.Monday, DayOfWeek.Tuesday, DayOfWeek.Wednesday };
//When you add a single row and try to paste from the first cell values from Excel
//Using there values the validation will cancel the pasting event: text1 text2 123 qwe
//Using there values the validation will pass and allow pasting: text1 text2 Monday 4/4/2014
public
Form55()
{
InitializeComponent();
(
this
.radGridView1.Columns[2]
as
GridViewComboBoxColumn).DataSource = comboColumnSource;
this
.radGridView1.Pasting += radGridView1_Pasting;
}
void
radGridView1_Pasting(
object
sender, GridViewClipboardEventArgs e)
{
List<List<
string
>> rows =
new
List<List<
string
>>();
if
(e.Format == DataFormats.Html)
{
rows = GetHtmlData(e.DataObject.GetData(DataFormats.Html).ToString());
}
if
(rows.Count == 0 && e.Format == DataFormats.Text)
{
rows = GetTextData(e.DataObject.GetData(DataFormats.Text).ToString());
}
if
(rows.Count == 0 && e.Format == DataFormats.CommaSeparatedValue)
{
rows = GetCsvData(e.DataObject.GetData(DataFormats.CommaSeparatedValue).ToString());
}
if
(rows.Count > 0)
{
e.Cancel = !ValidateRows(rows);
}
}
private
bool
ValidateRows(List<List<
string
>> rows)
{
try
{
foreach
(List<
string
> row
in
rows)
{
DateTime value;
if
(!DateTime.TryParse(row[3],
out
value))
{
return
false
;
}
DayOfWeek day = (DayOfWeek)Enum.Parse(
typeof
(DayOfWeek), row[2]);
}
}
catch
{
return
false
;
}
return
true
;
}
private
List<List<
string
>> GetTextData(
string
data)
{
List<List<
string
>> rows =
new
List<List<
string
>>();
StringTokenizer rowTokenizer =
new
StringTokenizer(data,
"\n"
);
int
rowTokens = rowTokenizer.Count();
while
(rowTokens > 0)
{
List<
string
> current =
new
List<
string
>();
rows.Add(current);
string
token = rowTokenizer.NextToken();
foreach
(
string
item
in
token.Split(
'\t'
))
{
current.Add(item.Trim());
}
rowTokens--;
}
return
rows;
}
private
List<List<
string
>> GetHtmlData(
string
data)
{
List<List<
string
>> rows =
new
List<List<
string
>>();
List<
string
> current =
new
List<
string
>();
StringTokenizer tokenizer =
new
StringTokenizer(data,
"<"
);
int
tokens = tokenizer.Count();
while
(tokens > 0)
{
string
token = tokenizer.NextToken();
bool
newRow = (token.Equals(
"tr>"
, StringComparison.InvariantCultureIgnoreCase));
if
(newRow)
{
current =
new
List<
string
>();
rows.Add(current);
}
if
(token.StartsWith(
"td>"
, StringComparison.InvariantCultureIgnoreCase))
{
int
index = token.IndexOf(
'>'
);
if
(index > 0)
{
token = token.Remove(0, index + 1);
token = token.Replace(
" "
,
" "
);
token = token.Replace(
"""
,
"\""
);
token = token.Replace(
"&"
,
"&"
);
token = token.Replace(
"<"
,
"<"
);
token = token.Replace(
">"
,
">"
);
current.Add(token);
}
}
tokens--;
}
return
rows;
}
private
List<List<
string
>> GetCsvData(
string
data)
{
List<List<
string
>> rows =
new
List<List<
string
>>();
StringTokenizer rowTokenizer =
new
StringTokenizer(data,
"\n"
);
int
rowTokens = rowTokenizer.Count();
while
(rowTokens > 0)
{
List<
string
> current =
new
List<
string
>();
rows.Add(current);
string
token = rowTokenizer.NextToken();
StringTokenizer colTokenizer =
new
StringTokenizer(token,
","
);
int
colTokens = colTokenizer.Count();
while
(colTokens > 0)
{
string
value = colTokenizer.NextToken();
value = value.Trim();
current.Add(value);
colTokens--;
}
rowTokens--;
}
return
rows;
}
Please refer to the attached picture, illustrating better where the attached file is displayed in the forum post.
The Pasting event is fired with different GridViewClipboardEventArgs: DataFormats.Html/DataFormats.Text/DataFormats.CommaSeparatedValue. If your requirement is to implement some custom logic and prevent the default one, it is necessary to create custom RadGridView and override the MasterGridViewTemplate.Paste event:
public
class
CustomGrid : RadGridView
{
protected
override
RadGridViewElement CreateGridViewElement()
{
return
new
CustomRadGridViewElement();
}
}
public
class
CustomRadGridViewElement : RadGridViewElement
{
protected
override
MasterGridViewTemplate CreateTemplate()
{
return
new
CustomMasterGridViewTemplate();
}
}
public
class
CustomMasterGridViewTemplate : MasterGridViewTemplate
{
public
override
void
Paste()
{
//base.Paste();
//implement the custom paste logic here
}
}
I hope this information helps. If you have any additional questions, please let me know.
Regards,
Desislava
Telerik
Hello Chad,
To get the cell with pasted value, you just need to access the CurrentCell property of RadGridView, illustrated in the code snippet below:
private void RadGridView1_Pasting(object sender, GridViewClipboardEventArgs e)
{
GridDataCellElement currentCell = this.radGridView1.CurrentCell;
// Your business logic
Console.WriteLine(currentCell.ColumnInfo.Name);
Console.WriteLine(currentCell.RowIndex);
}
I hope this information is useful.
Regards,
Todor Vyagov
Progress Telerik
Our thoughts here at Progress are with those affected by the outbreak.