Possible To Add A User Control To A Grid Column

6 posts, 0 answers
  1. ewart
    ewart avatar
    221 posts
    Member since:
    Jan 2007

    Posted 13 Nov 2008 Link to this post

    Is it possible to Add A User Control To A Grid Column?

    I need a grid which for each row the user needs to choose an from one of two radio button options.

    Item              Buy/Sell
    Cars             [ ]  [ ]
    Dogs             [ ]  [ ]
    Houses          [ ]  [ ]

    I figured a user control would be the easiest way to do this but I could really use an example? Experimentation makes me think it's not possible as I can only add a RadElement item to the CellElement.Children() collection?

    My fallback position was to try adding to RadioButtons to the same cell and I adapted the Telerik progressbar example in this regard.. see below for method called from CellFormatting event.   Seems to work so far as long as I define a new location when adding the second element as by default it appears on top of the first element; still, I'm not sure how well this general approach will workout when I start applying more logic and controls.. is a user control a no-go?

    Cheers
      Ewart.

      private void AddRadio(CellFormattingEventArgs gCell) 
          { 
             if (gCell.CellElement.Children.Count > 0) 
                return
     
             RadRadioButtonElement element = new RadRadioButtonElement(); 
             gCell.CellElement.Children.Add(element); 
     
             // apply theme to the progress bar   
             ApplyThemeToElement(element, "Aqua"); 
          } 



  2. Nick
    Admin
    Nick avatar
    767 posts

    Posted 14 Nov 2008 Link to this post

    Hello ewart,

    Thank you for your question.

    This is possible, but is not very straightforward. Please see the following code snippet:

    private void Form1_Load(object sender, EventArgs e) 
                GridViewDataColumn c = new GridViewDataColumn(); //add a generic column 
                c.HeaderText = "A"
                this.radGridView1.Columns.Add(c); 
     
       
    private void radGridView1_CellFormatting(object sender, CellFormattingEventArgs e) 
                if (e.CellElement.ColumnIndex == 1)// the second column 
                { 
                    UserControl1 radioButtons = new UserControl1(); 
                    radioButtons.Row = e.CellElement.RowIndex;// you have to save some info in you user control instance  
                    //in this case it is the row index  
                    radioButtons.Controls["radRadioButton1"].Click += new EventHandler(Radio_Click); 
                    RadHostItem i = new RadHostItem(radioButtons); 
                    e.CellElement.Children.Add(i); 
                    e.CellElement.RowInfo.Height = 60; 
                    e.CellElement.ColumnInfo.Width = 150; 
     
     
                } 
     
    void Radio_Click(object sender, EventArgs e) 
                MessageBox.Show(((UserControl1)((RadRadioButton)sender).Parent).Row.ToString()); 
            } 

    Note 1: If you need scrolling you will have to add logic about storing/restoring state (which radio is selected if any) because the CellFormatting event handler is invoked only for the currently visible cells. The easiest way is to add a data structure (like an array) for all your rows.

    Note 2: The user controls are are created every time CellFormatting is invoked so you may wish to add some logic about caching and probably reusing a certain number of user controls (the max number of visible ones).

    Do not hesitate to write me back if you have further questions.

     
    All the best,
    Nick
    the Telerik team

    Check out Telerik Trainer, the state of the art learning tool for Telerik products.
  3. ewart
    ewart avatar
    221 posts
    Member since:
    Jan 2007

    Posted 16 Nov 2008 Link to this post

    Thanks Nick,I've given it a try over the weekend + all of today, but both it and my fallback scheme have proven too difficult to impliment.   I had a data strcuture (object collection) to maintain state but the user control schemes created strange display and performance issues as soon as I started scrolling which I tried to resolve but couldn't. 

    My original idea of just adding controls directly worked perfomance wise but changes to my added controls are not reflected in the grid until i move off the current row, if I update the grid itself.  Hope that makes scense to you - if it doesn't:

    I hook each added control with an event
      optYes.Click += delegate(object sender, EventArgs e)
                { optYes_Click(sender, e, optNo); };

      optNo.Click += delegate(object sender, EventArgs e)
                { optNo_Click(sender, e, optYes); };

    In the handler, if i try to update the grid, then the grid updates just fine but changes to my controls are not.

    optYes_Click( ... )
    {
        //some code to handle stuff.. works great.
       gCell.CellElement.RowInfo.Cells["OtherColumn"].Value = "newvalue";  // adding this fucks things up.
    }

    So when I click on my control (don't laugh but for testing I'm using two checkboxes in a single cell), the checkbox is not ticked or cleared until after I move off the row.  If I don't try to update the grid then my checkboxes work fine.  Natually, I've tried a lof of Refresh(), Repaint(), PerformLayout().. on the offchance but no joy.  I've tried chaning the CurrentRow and restoring it which exibitied slighly different behaviour but ultimately no joy either.

    It seems like I'm so close to a solution here I just need the controls inside the grid to update.

    So I'm not sure where to go from here, I'm looking at implimenting checkboxes in two different columns and making them behave sorta like radio buttons - that would be sorta ok functionality wise although if i did that I really like to make a header span two columns.. aarrgh!   Maybe if someone in the community has sucessfully added a user control or controls directy a working example would be helpful. 

    Any ideas
      Ewart.
  4. ewart
    ewart avatar
    221 posts
    Member since:
    Jan 2007

    Posted 17 Nov 2008 Link to this post

    ..to add.   I've just tried to get this working with two checkboxes in two seperate columns (not ideal but I'm pretty desperate).  Am using the code below but I pretty much have the same problem updating checkboxes.  Funny, as I can update a text box using essentially the same code.

    In the below excerpt I have two checkbox columns - when I untick one I want to tick the other..  but the state just doesn't seem to change... again, if I use a textbox the state changes fine..  I must be tired or something, gotta get some sleep now..
     

     

      private void grdMyGrid_ValueChanging(object sender, ValueChangingEventArgs e)  
          {  
             GridViewRowInfo row = null;  
     
             if (sender is GridCheckBoxCellElement)  
             {  
                GridCheckBoxCellElement g = (GridCheckBoxCellElement)sender;  
     
                row = g.RowInfo;  
     
                if( g.ColumnIndex == 2)  
                {  
     
                   if (row.Cells["optYes"].Value.ToString() == "True" ) {  
                      row.Cells["optNo"].Value = true;  
                   }  
                   else 
                   {  
                      row.Cells["optNo"].Value = false;  
                   }  
                }  
             }  
          } 

     

  5. ewart
    ewart avatar
    221 posts
    Member since:
    Jan 2007

    Posted 19 Nov 2008 Link to this post

    ..I still don't have a solution but I've determined part of the problem (at least in the simple two column checkbox scenario, not for user controls).

    The _CellFormatting event fires before the _ValueChanging event and does not fire after the values have changed. 

    Surely the _CellFormatting should fire after the ValueChanging, or before and after? (or better, only if it needs to)

    When a user ticks a RadCheckBox, I want to format columns appropriately in the _CellFormatting event, but because _CellFormatting  fires before the value is changed, and doesn't fire after, I only have the old, and therefore, incorrect values in the grid to check and so the elements are formatted incorrectly.

    arrrgh.

    I've tired with hooking the _CellBeginEdit and _CellEndEdit events too and get some pretty strange results.  Sometimes the CellEndEdit event doesn't even fire - particulally when you toggle the same CheckBox from ticked to unticked or visa versa - but it does fire if you click on another row then back.

    I was able to reproduce the same effect by editing the WinControls.GridView.Events telerik example code, using the (hidden) BMP checkbox column for testing.

     radGridView1.ValueChanging += new Telerik.WinControls.UI.ValueChangingEventHandler(radGridView1_ValueChanging);  
     
      void radGridView1_ValueChanging(object sender, ValueChangingEventArgs e)  
            {  
               AddTextToListBox(string.Format("Value Changing"));  
            }  
     
     void radGridView1_CellFormatting( object sender, CellFormattingEventArgs e )  
            {  
                if (e.CellElement is GridCommandCellElement)  
                {  
                    e.CellElement.Text = "Btn " + e.CellElement.RowInfo.Cells[ "Id" ].Value;  
                }  
                AddTextToListBox(string.Format("Cell formatting"));  
            }  
     

  6. Nick
    Admin
    Nick avatar
    767 posts

    Posted 19 Nov 2008 Link to this post

    Hello ewart,

    Thank you for contacting me back and sorry for replying a little bit late, but I was thinking of a solution that will actually solve your issue. I think that I came across one.

    Here is the code that should work, although it abandons some of the previous ideas. A new CellElement class is employed and therefore all the custom logic about preserving state during scrolling is not required:

    public partial class Form1 : Form 
        { 
            public Form1() 
            { 
                InitializeComponent(); 
            } 
     
            private void Form1_Load(object sender, EventArgs e) 
            { 
                this.radGridView1.CreateCell += new GridViewCreateCellEventHandler(radGridView1_CreateCell); 
     
                DataTable table = new DataTable(); 
                table.Columns.Add("Item"typeof(string)); 
                table.Columns.Add("Buy/Sell"typeof(bool)); 
                Random r = new Random(); 
                for (int i = 0; i < 5; i++) 
                { 
                    table.Rows.Add("Row " + i, r.Next(10) > 5 ? true : false); 
                } 
     
                this.radGridView1.DataSource = table; 
            } 
     
            void radGridView1_CreateCell(object sender, GridViewCreateCellEventArgs e) 
            { 
                if (e.Row is GridDataRowElement &&  
                    e.Column.HeaderText == "Buy/Sell")  
                { 
                    e.CellType = typeof(RadioButtonCell); 
                } 
            } 
        } 
     
     
        class RadioButtonCell : GridDataCellElement  
        { 
            RadRadioButtonElement radio1; 
            RadRadioButtonElement radio2; 
     
            public RadioButtonCell(GridViewColumn column, GridRowElement rowElement):  
                base (column, rowElement)  
            {  
            } 
     
            protected override void Dispose(bool disposing) 
            { 
                if (disposing) 
                { 
                    radio1.ToggleStateChanged -= new StateChangedEventHandler(radio1_ToggleStateChanged); 
                } 
                base.Dispose(disposing); 
            } 
     
            protected override void SetContentCore(object value) 
            { 
                radio1.IsChecked = (bool)value; 
                radio2.IsChecked = !(bool)value; 
            } 
     
            protected override void CreateChildElements() 
            { 
                radio1 = new RadRadioButtonElement(); 
                radio1.ToggleStateChanged += new StateChangedEventHandler(radio1_ToggleStateChanged); 
                radio2 = new RadRadioButtonElement(); 
                this.Children.Add(radio1); 
                this.Children.Add(radio2); 
            } 
     
            protected override SizeF ArrangeOverride(SizeF finalSize) 
            { 
                if (this.Children.Count == 2)  
                { 
                    this.Children[0].Arrange(new RectangleF(0, 0, 20, 20)); 
                    this.Children[1].Arrange(new RectangleF(25, 0, 20, 20)); 
                } 
                return finalSize; 
            } 
     
            private void radio1_ToggleStateChanged(object sender, StateChangedEventArgs args) 
            { 
                this.Value = this.radio1.IsChecked; 
            } 
        }  

    The code is mostly self-explanatory. I would like to note that you have to use a boolean value in your database and have to replace the string in CreateCell event with the header text of your radio column.

    Do not hesitate to write me back if you have further questions.
     

    Best wishes,
    Nick
    the Telerik team

    Check out Telerik Trainer, the state of the art learning tool for Telerik products.
Back to Top