CellValueChanged not firing with pasted value

17 posts, 0 answers
  1. Tim R
    Tim R avatar
    133 posts
    Member since:
    Feb 2006

    Posted 04 Dec 2012 Link to this post

    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";
            }


  2. Svett
    Admin
    Svett avatar
    728 posts

    Posted 07 Dec 2012 Link to this post

    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.
  3. Tim R
    Tim R avatar
    133 posts
    Member since:
    Feb 2006

    Posted 07 Dec 2012 Link to this post

    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.

  4. Tim R
    Tim R avatar
    133 posts
    Member since:
    Feb 2006

    Posted 07 Dec 2012 Link to this post

    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
  5. Svett
    Admin
    Svett avatar
    728 posts

    Posted 12 Dec 2012 Link to this post

    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.
  6. fbi
    fbi avatar
    4 posts
    Member since:
    Oct 2009

    Posted 28 Jun 2013 Link to this post

    Hello Svett,

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

    What is the problem.

    Best regards
    Fritz
  7. Ivan Petrov
    Admin
    Ivan Petrov avatar
    717 posts

    Posted 03 Jul 2013 Link to this post

    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 >>
  8. John
    John avatar
    28 posts
    Member since:
    Sep 2013

    Posted 04 Apr 2014 in reply to Ivan Petrov Link to this post

    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
  9. Ivan Petrov
    Admin
    Ivan Petrov avatar
    717 posts

    Posted 09 Apr 2014 Link to this post

    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.

     
  10. John
    John avatar
    28 posts
    Member since:
    Sep 2013

    Posted 09 Apr 2014 in reply to Ivan Petrov Link to this post

    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
  11. Ivan Petrov
    Admin
    Ivan Petrov avatar
    717 posts

    Posted 14 Apr 2014 Link to this post

    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.

     
  12. John
    John avatar
    28 posts
    Member since:
    Sep 2013

    Posted 16 Apr 2014 in reply to Ivan Petrov Link to this post

    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
  13. Ivan Todorov
    Admin
    Ivan Todorov avatar
    688 posts

    Posted 18 Apr 2014 Link to this post

    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.

     
  14. John
    John avatar
    28 posts
    Member since:
    Sep 2013

    Posted 18 Apr 2014 in reply to Ivan Todorov Link to this post

    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
  15. Dess | Tech Support Engineer, Sr.
    Admin
    Dess | Tech Support Engineer, Sr.  avatar
    3894 posts

    Posted 22 Apr 2014 Link to this post

    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.
     
  16. Chad
    Chad avatar
    1 posts
    Member since:
    Mar 2019

    Posted 29 Jun in reply to Tim R Link to this post

    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. 
  17. Todor Vyagov
    Admin
    Todor Vyagov avatar
    44 posts

    Posted 02 Jul Link to this post

    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.
Back to Top