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

ExtractValues - IBindableTemplate Delete error

4 Answers 60 Views
Grid
This is a migrated thread and some comments may be shown as answers.
archimede
Top achievements
Rank 1
archimede asked on 23 Sep 2011, 09:59 AM
Hi,
I create a server control that inherits the grid, I create the templatecolumn dinamically with ItemTemplate and EditItemTemplate
AutoPostBackOnFilter = true;
                      CurrentFilterFunction = Telerik.Web.UI.GridKnownFunction.Contains;
                      ShowFilterIcon = false;
                        
                      HeaderStyle.Width = _width;
                      ItemStyle.Width = _width;
                      ItemStyle.HorizontalAlign = System.Web.UI.WebControls.HorizontalAlign.Right;
                      HeaderTemplate = new MyHeaderTemplate(_type, DataField, _width.Value - CommonParameters.GridFilterWidthDistances, LabelText);                        
                      ItemTemplate = new MyTemplateText(new GridTemplateColumnParameter()
                          .SetColumnType(CommonParameters.RadGridTemplateColumnType.ItemTemplate)
                          .SetDataField(DataField)
                          .SetDataFieldItem(DataFieldItem)
                          .SetWidth(_width.Value - CommonParameters.GridFilterWidthDistances)
                          .SetReadOnlyOn(_readOnlyOn)
                          );
                      EditItemTemplate = new MyTemplateText(new GridTemplateColumnParameter()
                          .SetColumnType(CommonParameters.RadGridTemplateColumnType.EditItemTemplate)
                          .SetDataField(DataField)
                          .SetDataFieldItem(DataFieldItem)
                          .SetWidth(_width.Value - CommonParameters.GridFilterWidthDistances)
                          .SetReadOnlyOn(_readOnlyOn)
                          .SetRequired(_required)
                          .SetCodice(_codice)
                          .SetMaxLength(_maxLength)
                          .SetLabelText(LabelText)
                          );

The code that create the MyTemplateText is:
private class MyTemplateText : IBindableTemplate
       {
           private TextBox _txb;
           private Label _lbl;
           private GridTemplateColumnParameter _gtcp;
           public MyTemplateText(GridTemplateColumnParameter pGtcp)
           { // Parametert to create label ant text box of the template column
               _gtcp = pGtcp;
           }
           #region IBindableTemplate Members
           public System.Collections.Specialized.IOrderedDictionary ExtractValues(System.Web.UI.Control pContainer)
           {
               OrderedDictionary data = new OrderedDictionary();
               switch (_gtcp.ColumnType)
               {
                     
                   case CommonParameters.RadGridTemplateColumnType.ItemTemplate:
                                           data.Add(_gtcp.DataField, _lbl.Text);
                        break;
                   case CommonParameters.RadGridTemplateColumnType.EditItemTemplate: data.Add(_gtcp.DataField, _txb.Text); break;
               }
               return data;
           }
           #endregion
           #region ITemplate Members
           public void InstantiateIn(System.Web.UI.Control pContainer)
           {
               switch (_gtcp.ColumnType)
               {
                   case CommonParameters.RadGridTemplateColumnType.ItemTemplate:
                       {
                           _lbl = new Label();
                                                     _lbl.CssClass = "ColumnText";
                           _lbl.Width = new System.Web.UI.WebControls.Unit(_gtcp.Width);
                           _lbl.ParentType = CommonParameters.BloccoParentType.RadGrid;
                           _lbl.DataBinding += new EventHandler(Lbl_DataBinding);
                           pContainer.Controls.Add(_lbl);
                       }
                       break;
                   case CommonParameters.RadGridTemplateColumnType.EditItemTemplate:
                       {
                           _txb = new TextBox();
                           _txb.ID = "txb" + _gtcp.DataField;
                           _txb.Width = new System.Web.UI.WebControls.Unit(_gtcp.Width);
                           _txb.DataBinding += new EventHandler(Txb_DataBinding);
                           _txb.MaxLength = _gtcp.MaxLength;
                           switch (_gtcp.ReadOnlyOn)
                           {
                               case CommonParameters.ReadOnlyTemplateMode.All:
                                   {
                                       _txb.ReadOnly = true;
                                   } break;
                               case CommonParameters.ReadOnlyTemplateMode.Item:
                                   {
                                   } break;
                               default: throw new NotImplementedException("ReadOnlyOn non ancora gestita in tutte le tipologie");
                           }
                           pContainer.Controls.Add(_txb);
                           if (_gtcp.Required)
                           {
                               RequiredFieldValidator rfv = new RequiredFieldValidator();
                               rfv.ID = "rfv" + _gtcp.DataField;
                               rfv.CssClass = "ValidatorStyle";
                               rfv.ControlToValidate = "txb" + _gtcp.DataField;
                               rfv.Text = "!";
                               rfv.ErrorMessage = _gtcp.LabelText + " è obbligatorio!";
                               rfv.Display = ValidatorDisplay.Static;
                               pContainer.Controls.Add(rfv);
                                                                                                                     }
                           if (_gtcp.Codice)
                           {
                               RegularExpressionValidator rev = new RegularExpressionValidator();
                               rev.ID = "rev" + _gtcp.DataField;
                               rev.ControlToValidate = "txb" + _gtcp.DataField;
                               rev.Text = "!";
                               rev.CssClass = "ValidatorStyle";
                               rev.ErrorMessage = _gtcp.LabelText + " contiene caratteri non validi!";
                               rev.Display = ValidatorDisplay.Static;
                               rev.ValidationExpression = "^[^\\/*?\"<>|]*$";
                               pContainer.Controls.Add(rev);
                           }
                       } break;
               }
           }
           void Lbl_DataBinding(object sender, EventArgs e)
           {
               Telerik.Web.UI.GridDataItem item = _lbl.NamingContainer as Telerik.Web.UI.GridDataItem;
               if (DataBinder.Eval(item.DataItem, _gtcp.DataField) != null)
               {
                   _lbl.Text = DataBinder.Eval(item.DataItem, _gtcp.DataField).ToString();
                     
                    
               }
           }
           void Txb_DataBinding(object sender, EventArgs e)
           {
               Telerik.Web.UI.GridItem item = _txb.NamingContainer as Telerik.Web.UI.GridItem;
               if (item is Telerik.Web.UI.GridDataItem)
               {
                   object value = DataBinder.Eval(item.DataItem, _gtcp.DataField);
                   if ((value != DBNull.Value) && (value != null))
                   {
                       _txb.Text = value.ToString();
                   }
                   else
                   {
                       _txb.Text = "";
                   }
               }
           }
           #endregion
       }

I use entity framework with automatic insert/update/delete. 
Insert and  Update operations works fine, but Delete NOT ! , the entity tells me a concurrency message ... but it's a false messagge.
Because doing a debug after the "DeleteComand"  the grid "executes"  public System.Collections.Specialized.IOrderedDictionary ExtractValues(System.Web.UI.Control pContainer) "  the grid know the DAtaKeyName and it's the one i choose to delete, but on this function i see the return the LAST ITEM of the page i'm watching on the grid.
Then The entity Class receive a bad information...
So, the question is where is the mistake, ??? I try a telerik standar grid with automatic CRUD operations with entity datasource and everything works as expected, the entity class received information ok.
I hope someone undertand my problem.
Thanks !!!!

4 Answers, 1 is accepted

Sort by
0
Veli
Telerik team
answered on 28 Sep 2011, 10:13 AM
Hi Archimede,

The problem is that you use instance fields in your template class (MyTemplateText). The InstantiateIn method accesses these instance fields and configures them. However, note that the InstantiateIn method is called multiple times when the template is instantiated in different item cells. If your InstantiateIn method uses shared controls, you get the your control references messed up.

The same happens with the ExtractValues method - it references the _txb and _lbl controls and uses them for extracting values. However, as this template is instantiated multiple times in all grid cells for this column, your 2 control references actually refer to the controls in the last instantiated container. This is why you get incorrect values extracted.

When using ITemplate classes, you need to make sure the InstantiateIn and ExtractValues do not use shared fields. Otherwise, your template is not reusable. These 2 methods should follow a "fire and forget" approach, meaning all controls you need in the template must be local to the method, not to the class. InstantiateIn must create instances to your controls, add them to the container and then "forget" about them. Similarly, ExtractValues must find the controls you need from the passed container control. Only then you ensure reusability for your template.

Veli
the Telerik team
If you want to get updates on new releases, tips and tricks and sneak peeks at our product labs directly from the developers working on the RadControls for ASP.NET AJAX, subscribe to their blog feed now
0
archimede
Top achievements
Rank 1
answered on 29 Sep 2011, 12:18 PM
Hi Veli,
Thanks for the completeness of your answer.
When you said " all controls you need in the template must be local to the method" you mean that i can't create the controlls programmatically inside the class? i must insert the controls on the page ( aspx o create it on .cd file ) ?.
Now, on my project to create a column tempalte for a rad grid i only  write this code:
<mwc:GridTemplateColumn Type="Text" DataField="CodArtForn" LabelResources="codartfornitore_simi"
                   Width="200px"  />
And in the class i create different columns considering the TYPE ( es: Currency --> Label + Radnumerictextbox ...)
Everything is created on my class GridTemplateColumn.cs that inherits yours.

Can you give me some advice on how to better structure the class and get a structure in the aspx code clean and reusable ?

Thank you very much for your answer !!!


0
Veli
Telerik team
answered on 30 Sep 2011, 08:15 AM
Hello Archimede,

There is no magic to it. You can create any control you want, you just have to make sure you reference the correct control that goes in the current container in the InstantiateIn and ExtractValues methods.

For example, if your template is instantiated 5 times, and in the InstantiateIn method you define a TextBox control, you will surely have 5 TextBox control instantiated. When you assign each instantiated TextBox control to a private field in your class, in the end, which TextBox control is references by the private field? Answering this question helps you realize you shouldn't really be putting references of control outside of InstantiateIn.

Instead of sharing the control reference in a private field. you should be sharing a common property that can identify the control in the provided container. ID, for example, is a good candidate for keeping in a private field. Your controls can all use the same ID. There is no ID conflicts with that, because each time your template is instantiated in a different naming container. Sharing your control ID helps you find the control by its ID in the ExtractValues method later on.

Bottom line:
1. InstantiateIn should add controls to the container
2. ExtractValues should find the controls from the container. A shared ID or another control property can help.

Veli
the Telerik team
If you want to get updates on new releases, tips and tricks and sneak peeks at our product labs directly from the developers working on the RadControls for ASP.NET AJAX, subscribe to their blog feed now
0
archimede
Top achievements
Rank 1
answered on 04 Oct 2011, 12:01 PM
Thanks!!!!
As advised me i create the ID property and then did the search inside the container and it works perfectly :)

   .......
    vNomeControllo ="lbl"+_gtcp.DataField ;
    Label lbl = (Label)(pContainer.FindControl(vNomeControllo));
    String value= lbl.Text;
 
data.Add(_gtcp.DataField, value  );
 
          ....

Thank you very much for the assistance and professionalism
!!!!
Tags
Grid
Asked by
archimede
Top achievements
Rank 1
Answers by
Veli
Telerik team
archimede
Top achievements
Rank 1
Share this question
or