This is a migrated thread and some comments may be shown as answers.

CellValueChanged not firing with pasted value

16 Answers 1885 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Tim R
Top achievements
Rank 1
Tim R asked on 04 Dec 2012, 06:13 PM
In the following thread I received help on creating a subclassed TimePicker bound to a TimeSpan CLR type:

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

Sort by
0
Svett
Telerik team
answered on 07 Dec 2012, 11:38 AM
Hello Tim,

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
Q3’12 of RadControls for WinForms is available for download (see what's new). Get it today.
0
Tim R
Top achievements
Rank 1
answered on 07 Dec 2012, 03:38 PM
Thanks, I will try it out.  BTW, the tooltip descriptions of these events in Visual Studio imply the opposite of the actual behavior.

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.

0
Tim R
Top achievements
Rank 1
answered on 07 Dec 2012, 03:59 PM
What is the proper method signature for ValueChanged?  Mine is not compiling.
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
0
Svett
Telerik team
answered on 12 Dec 2012, 05:16 PM
Hi Tim,

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
Q3’12 of RadControls for WinForms is available for download (see what's new). Get it today.
0
fbi
Top achievements
Rank 1
answered on 28 Jun 2013, 02:29 PM
Hello Svett,

the ValueChanged Event does not fire, if I paste the value to a TextBoxColumn.

What is the problem.

Best regards
Fritz
0
Ivan Petrov
Telerik team
answered on 03 Jul 2013, 02:04 PM
Hi 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
TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for WINFORMS.
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 >>
0
John
Top achievements
Rank 1
answered on 04 Apr 2014, 04:44 PM
Hi Ivan,

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
0
Ivan Petrov
Telerik team
answered on 09 Apr 2014, 03:02 PM
Hello 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.

 
0
John
Top achievements
Rank 1
answered on 09 Apr 2014, 09:58 PM
Hi Ivan,

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
0
Ivan Petrov
Telerik team
answered on 14 Apr 2014, 03:08 PM
Hi 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.

 
0
John
Top achievements
Rank 1
answered on 16 Apr 2014, 08:30 PM
Hi Ivan,  

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
0
Ivan Todorov
Telerik team
answered on 18 Apr 2014, 02:38 PM
Hi 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.

 
0
John
Top achievements
Rank 1
answered on 18 Apr 2014, 09:45 PM
Hi Ivan,

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
0
Dess | Tech Support Engineer, Principal
Telerik team
answered on 22 Apr 2014, 02:29 PM
Hello 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
 
Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
 
0
Chad
Top achievements
Rank 1
answered on 29 Jun 2020, 02:19 PM
I agree that it is reasonable to expect that the CellValueChanged event should fire when the user changes the value of a cell through a paste. I see that the solution was to use the On Paste events but I am puzzled that the event does not tell you what cell has changed. The "e" parameter does not contain this info. 
0
Todor
Telerik team
answered on 02 Jul 2020, 06:46 AM

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);
}
More information about the Pasting event is available in our help article: https://docs.telerik.com/devtools/winforms/controls/gridview/copy-paste-cut#pasting

 

I hope this information is useful.

Regards,
Todor Vyagov
Progress Telerik

Progress is here for your business, like always. Read more about the measures we are taking to ensure business continuity and help fight the COVID-19 pandemic.
Our thoughts here at Progress are with those affected by the outbreak.
Tags
GridView
Asked by
Tim R
Top achievements
Rank 1
Answers by
Svett
Telerik team
Tim R
Top achievements
Rank 1
fbi
Top achievements
Rank 1
Ivan Petrov
Telerik team
John
Top achievements
Rank 1
Ivan Todorov
Telerik team
Dess | Tech Support Engineer, Principal
Telerik team
Chad
Top achievements
Rank 1
Todor
Telerik team
Share this question
or