Multiple EditCommandColumns in a datagrid

I understand how to use an EditCommandColumn along with EditItemTemplates to make an entire row of a Datagrid editable, however, I was wondering if there is a way to add multiple EditCommandColumns and associate them with specific columns in a row.  Basically, I want to be able to make only individual columns of data editable at a time.  I don't want columns 1, 2, and 3 to all change into textboxes when I click a single edit button, I want an edit button next to each column so a user can only edit one at a time.  Is this possible?  Or rather, is there a relatively easy way to do this?
smoogaAsked:
Who is Participating?
 
RamuncikasCommented:
raterus,

your aproach to the problem is nice (i like designing usercontrols), but in this case I'd change my above source to this:

If e.CommandName = "Edit" Then
            Select Case e.CommandArgument
                Case "Col1"
                    CType(dg.Columns(2), TemplateColumn).EditItemTemplate = Nothing
                    CType(dg.Columns(4), TemplateColumn).EditItemTemplate = Nothing
                Case "Col2"
                    CType(dg.Columns(0), TemplateColumn).EditItemTemplate = Nothing
                    CType(dg.Columns(4), TemplateColumn).EditItemTemplate = Nothing
                Case "Col3"
                     CType(dg.Columns(0), TemplateColumn).EditItemTemplate = Nothing
                     CType(dg.Columns(2), TemplateColumn).EditItemTemplate = Nothing
            End Select
            dg.EditItemIndex = e.Item.ItemIndex
            dg.DataSource = BindGrid()
            dg.DataBind()
        End If

Again, this code assumes that Datagrid "dg" has 6 columns: columns 0, 2 and 4 are templatecolumns with controls for data representation, columns 1, 3 and 5 are templatecolumns with "Edit" buttons. BindGrid function returns dataset (I tried with datatable).

Let's hope that will do
Ramuncikas
0
 
RamuncikasCommented:
Hey, smooga.

Here is the logic worth trying:

1. Set up 3 Template columns
2. Put a button (or linkbutton) into each of them
3. Set each of button's CommandName property to "Edit" (or something like that)
4. Set each of button's CommandArgument propety to something different(like "Col1", "Col2" and "Col3")
5. !!!IMPORTANT!!! give each of buttons different names
6. Code Datagrid's ItemCommand event's handler like this:

        If e.CommandName = "Edit" Then
            Select Case e.CommandArgument
                Case "Col1"
                    CType(dg.Columns(0), BoundColumn).ReadOnly = False
                    CType(dg.Columns(2), BoundColumn).ReadOnly = True
                    CType(dg.Columns(4), BoundColumn).ReadOnly = True
                Case "Col2"
                    CType(dg.Columns(0), BoundColumn).ReadOnly = True
                    CType(dg.Columns(2), BoundColumn).ReadOnly = False
                    CType(dg.Columns(4), BoundColumn).ReadOnly = True
                Case "Col3"
                    CType(dg.Columns(0), BoundColumn).ReadOnly = True
                    CType(dg.Columns(2), BoundColumn).ReadOnly = True
                    CType(dg.Columns(4), BoundColumn).ReadOnly = False
            End Select
            dg.EditItemIndex = e.Item.ItemIndex
            dg.DataSource = BindGrid()
            dg.DataBind()
        End If

This code assumes that Datagrid "dg" has 6 columns: columns 0, 2 and 4 are databound columns, columns 1, 3 and 5 are template columns. BindGrid function returns dataset (I tried with datatable).

Let's hope this will do
Good luck
Ramuncikas
0
 
RejojohnyCommented:
>> I don't want columns 1, 2, and 3 to all change into textboxes when I click a single edit button, I want an edit button next to each column so a user can only edit one at a time
u will  not need an edit button for each column .. but one edit button for the one row, clicking on which will make only the required columns editable .. it can be acheived by making the other columns (which has to non-editable) as readonly .. right click on the datagrid to go the "property builder" ... In the columns section, select the column and check the checkbox "Readonly" .. or u could just edit the HTML tag for the boundcolumn to add a attribute "Readonly=true"
0
Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

 
RamuncikasCommented:
Rejojohny,

>> I want an edit button next to each column so a user can only edit one at a time.  Is this possible?

I think THAT was the question, and your solution provides the opportuninty to make certain columns read-only, that is uneditable.

 
0
 
smoogaAuthor Commented:
Exactly.  I want to be able to choose which column is editable.  Ramuncikas, your solution seems like it should work perfectly.  A little dissapointed that I hadn't figured that out on my own :)  I will try it out as soon as I'm done paying my mom a visit for Mother's Day.  Thanks!
0
 
smoogaAuthor Commented:
Well, I forgot to mention that I want to use TemplateColumns instead of BoundColumns.  Instead of showing just textboxes in edit mode, I'd like to display a nested datagrid.  TemplateColumns do not have a readonly property though.  Perhaps there's a way to programatically disable the EditItemTemplate of a TemplateColumn?  I'll look into this...
0
 
raterusCommented:
If that is the case, I'd design a usercontrol for each templatecolumn, this control would have a "ReadOnly" property, and depending on what it is set to, you would display the control like you want it.  You'd still use Ramuncikas' solution as a base though, for toggling them on/off.
0
 
RejojohnyCommented:
>> TemplateColumns do not have a readonly property though
but the control that u might place within it .. like the textbox ... might have it ...

Just a thought .. the design you are suggesting here would be too complex .. one datagrid having multiple templatecoluimns .. each having another datagrid within it .. and individual edits for each template column .. managing all this would be too complex .. i would advice that you have a look at designing a more simpler form .. maybe  a page having a datagrid which has the basic data shown and clicking on each of these column takes u to another page (could be a new window opened) which has the details for the selected item in a datagrid with option to edit them ...
0
 
raterusCommented:
That is actually much better, I hadn't even thought of that.  if the templatecolumn doesn't have an EditItemTemplate then it will default back to the ItemTemplate.

On the other hand, if you had usercontrols in here, it would be easier to pull values from them, since the value is encapsulated within a property in the control, whether it is readonly or not.  If you merely just "trick" the datagrid into not displaying the edititemtemplate, you will have to redetermine what edit state the datagrid was in when they hit update.  I see so many questions on here of "Object reference not set to an instance of an object" errors because they are trying to pull from a textbox in the edititemtemplate, but the itemtemplate was rendered.  It's not that hard to deal with it, but something you'll have to think about.
0
 
RamuncikasCommented:
Raterus,

Your argument is VERY strong. BUT...

It's up to Smooga witch path to choose. And in case Smooga chooses my way of problem solution, paying attention to your notices, I'd use different "update" buttons for each column with differen CommandArgument property values. This way Smooga would know what column needs to be updated by adding one more "if" statement to the DataGrid's ItemCommand event.

Ramuncikas

0
 
smoogaAuthor Commented:
raterus, I believe that is the problem I'm running into now.  I've implemented Ramuncikas' code (thanks Ramuncikas!), and am calling another method to bind the nested datagrid.  I'm trying to access it using: DataGrid nestedGrid = (DataGrid) row.FindControl( "nestedGrid" ); but I'm getting the "Object reference not set to an instance of an object" error.  I don't entirely understand what's happening here.  I'm setting dg.EditItemIndex = e.Item.ItemIndex before calling this method, so it seems to me like the edititemtemplate should be active and accessible.
0
 
raterusCommented:
Show the aspx source/code, you may just not be looking in the correct place.  Also fill us in on the state of the current datagrid, which edit mode is set.
0
 
smoogaAuthor Commented:
I believe I am looking in the right place because if I put a datagrid in the columns ItemTemplate and give it the same ID, I do not get the object reference error.  So it seems that it is using the ItemTemplate and not the EditItemTemplate.  

Will post the source in a minute... just want to remove some extraneous stuff in it that does not pertain to this thread...
0
 
raterusCommented:
Ramuncikas, perhaps you can chip in since it is your idea, but this may be what is going on.

If you are setting the TemplateColumn.EditItemTemplate = Nothing in code, what happens when you postback the code and asp.net recreates the datagrid from the viewstate.  It is going to instantiate the edititemtemplate, not from the itemtemplate, and it is going to try to match the itemtemplate viewstate to the edititemtemplate template structure.  Since none of those controls are going to match up, as far as the viewstate is concerned, your edititemtemplate will be instantiated as nothing.

Purely a guess on my part, so I may be mistaken.  Also, if this is the case, the only way to fix this would be to do something like this in page_init

TemplateColumn.EditItemTemplate = TemplateColumn.ItemTemplate, in the exact manner you disabled them before.

--Michael

{...shameless plug to my solution...}
This won't happen if you use usercontrols :^)
0
 
smoogaAuthor Commented:
<asp:DataGrid Runat="server" ID="testGrid" AutoGenerateColumns="False" CellPadding="0" CellSpacing="0" OnItemCommand="HandleItemCommand" Height="88px">
                        <Columns>
                              <asp:TemplateColumn HeaderText="% Total">
                                    <HeaderStyle Width="150px"></HeaderStyle>
                                    <ItemTemplate>
                                          <asp:Label Runat="server" ID="percTTL_lbl" />
                                    </ItemTemplate>
                                    <EditItemTemplate>
                                          <asp:TextBox Runat="server" ID="percTTL_tb" Width="150"></asp:TextBox>
                                    </EditItemTemplate>
                              </asp:TemplateColumn>
                              
                                        <asp:TemplateColumn HeaderText="Dollars">
                                    <HeaderStyle Width="150px"></HeaderStyle>
                                    <ItemTemplate>
                                          <asp:Label Runat="server" ID="dollars_lbl" />
                                    </ItemTemplate>
                                    <EditItemTemplate>
                                          <asp:TextBox Runat="server" ID="dollars_tb" Width="150"></asp:TextBox>
                                    </EditItemTemplate>
                              </asp:TemplateColumn>
                              
                              <asp:ButtonColumn Text="Edit" ButtonType="PushButton" CommandName="EditAmounts"></asp:ButtonColumn>
                              <asp:ButtonColumn Text="Set Size Range" ButtonType="PushButton" CommandName="SetSizeRange"></asp:ButtonColumn>
                              
                              <asp:TemplateColumn>
                                    <EditItemTemplate>
                                                <tr>
                                                      <td colspan="10" style="padding-left:30px;">
                                                            <asp:DataGrid Runat="server" ID="nestedGrid"></asp:DataGrid>
                                                      </td>
                                                </tr>
                                    </EditItemTemplate>
                              </asp:TemplateColumn>
                        </Columns>
                  </asp:DataGrid>



protected void HandleItemCommand( object sender, DataGridCommandEventArgs e )
            {
                  DataGridItem row = e.Item;
                  testGrid.EditItemIndex = row.ItemIndex;

                  switch ( e.CommandName ) {
                        case "EditAmounts" :
                              TemplateColumn tc = (TemplateColumn) testGrid.Columns[ 4 ];
                              tc.EditItemTemplate = null;

                              break;
                        case "SetSizeRange":
                              TemplateColumn tc1 = (TemplateColumn) testGrid.Columns[ 0 ];
                              TemplateColumn tc2 = (TemplateColumn) testGrid.Columns[ 1 ];
                              tc1.EditItemTemplate = null;
                              tc2.EditItemTemplate = null;

                              SetSizeRange( ref row );

                              break;
                  }
                  
                  DoDataBind();
            }

            private void SetSizeRange( ref DataGridItem row )
            {
                  DataGrid nestedGrid = (DataGrid) row.FindControl( "nestedGrid" );

                  ArrayList al = new ArrayList( 4 );
                  al.Add( "test 1" );
                  al.Add( "test 2" );
                  al.Add( "test 3" );
                  al.Add( "test 4" );

                  nestedGrid.DataSource = al;
                  nestedGrid.DataBind();
            }
0
 
raterusCommented:
smooga, just for kicks, can you try doing what I last suggested, even if it is a hack to write it.

Basically, in the init event of the datagrid, redo exactly what you did in the HandleItemCommand event on the previous page, as far as any template shifting, eg.
tc1.EditItemTemplate = null;

I have a gut feeling that it will work after doing this.
0
 
smoogaAuthor Commented:
I tried it but I got the same results :(
0
 
RamuncikasCommented:
Smooga,

                                        <tr>
                                             <td colspan="10" style="padding-left:30px;">
                                                  <asp:DataGrid Runat="server" ID="nestedGrid"></asp:DataGrid>
                                             </td>
                                        </tr>

What are tr's and td's doing here? I think it's  very little chance it's the cause of the problem, but still...

0
 
raterusCommented:
do you have vs.net, where you can set a breakpoint at the SetSizeRange sub, and see exactly what is contained in the controls collection of "row", on the postback?
0
 
smoogaAuthor Commented:
Ok, I should point this out.  If I click the first button, the page refreshes and the textboxes are displayed.  If I then click the second button *in the same row* the nested datagrid is displayed.  However, if I call DoDataBind() (which binds the parent datagrid) after SetSizeRange(), the nested grid is empty.  This is a whole other problem though.  What I really wanted to point out was that clicking the second button to display the nested grid does not throw an object reference error if the first button was just clicked in that same row.
0
 
smoogaAuthor Commented:
Ramuncikas,  
     I'm using the trs and tds to create a dropdown row.  The effect is that when the user clicks the second button, an indented row of bound data drops down.

Raterus,
    yes, I have VS.NET.   One sec...
0
 
RamuncikasCommented:
Also, I'd try using

       DataGrid nestedGrid = (DataGrid) row.Cells[3].FindControl( "nestedGrid" );

I maybe mistaken in syntax 'case I'm not a big C# lover

Ramuncikas
0
 
smoogaAuthor Commented:
Hmmm... curiously, the row cell count is correct, but it says "cannot view indexed property" next to the Item collection.  So I cannot see what, if anything, is actually in there.
0
 
raterusCommented:
you might have to start typing in the watch window, say if you have watched "row", you will type in one of the blank spots.

row.Controls(4) -- Then look through it's properties, check the type, etc..  Keep doing that until you can get a picture of the overall structure
0
 
smoogaAuthor Commented:
Ramuncikas,
   I know it's not a syntax error because I've verified that it works in certain conditions.  Again, if I put a datagrid in the ItemTemplate and give it the same ID, it never throws that error.  I believe it is just looking for the ItemTemplate instead of the EditItemTemplate.
0
 
RamuncikasCommented:
Smooga,

I made some thanges to your source:

       protected void HandleItemCommand( object sender, DataGridCommandEventArgs e )
        {
            DataGridItem row = e.Item;
            testGrid.EditItemIndex = row.ItemIndex;

            switch ( e.CommandName )
            {
                case "EditAmounts" :
                    TemplateColumn tc = (TemplateColumn) testGrid.Columns[ 4 ];
                    //tc.EditItemTemplate = null;
                    DoDataBind();

                    break;
                case "SetSizeRange":
                    TemplateColumn tc1 = (TemplateColumn) testGrid.Columns[ 0 ];
                    TemplateColumn tc2 = (TemplateColumn) testGrid.Columns[ 1 ];
                    tc1.EditItemTemplate = null;
                    tc2.EditItemTemplate = null;

                    SetSizeRange( ref row );

                    break;
            }
               
              //   DoDataBind();
        }


I don't know if this is a behavior you're expecting.

(god, how I hate C#:))
Ramuncikas
0
 
smoogaAuthor Commented:
Ramuncikas,
   First, thanks for all the help.  I've actually come up with a simpler solution for my specific situation.  It might not be the most flexible, but it works for what I need... and I've sent enough time on this already :)

I've just stuck my nested datagrid in a Placeholder inside a template column and I'm setting its visible property to true or false:

<asp:TemplateColumn>
                                    <ItemTemplate>
                                          <asp:PlaceHolder Runat="server" ID="nestedGrid_ph" Visible="False" EnableViewState="false">
                                                <tr>
                                                      <td colspan="10" style="padding-left:30px;">
                                                            nestedGrid<br>
                                                            <asp:DataGrid Runat="server" ID="nestedGrid"></asp:DataGrid>
                                                      </td>
                                                </tr>
                                          </asp:PlaceHolder>
                                    </ItemTemplate>
                              </asp:TemplateColumn>

protected void HandleItemCommand( object sender, DataGridCommandEventArgs e )
            {
                  DataGridItem row = e.Item;

                  switch ( e.CommandName ) {
                        case "SetSizeRange":
                              SetSizeRange( row );
                              break;
                  }
            }


private void SetSizeRange( DataGridItem row )
            {
                  PlaceHolder nestedGrid_ph = (PlaceHolder) row.FindControl( "nestedGrid_ph" );
                  DataGrid nestedGrid = (DataGrid) nestedGrid_ph.FindControl( "nestedGrid" );

                  ArrayList nest_al = new ArrayList( 4 );
                  nest_al.Add( "test 1" );
                  nest_al.Add( "test 2" );
                  nest_al.Add( "test 3" );
                  nest_al.Add( "test 4" );

                  nestedGrid.DataSource = nest_al;
                  nestedGrid.DataBind();

                  nestedGrid_ph.Visible = true;
            }

I had tried this before but couldn't get it to work.  The trick was to set the placeholder's EnableViewState to false.

Anyway, thanks for all the help guys.  Do you mind if I spilt the points between Ramuncikas and Raterus?  You both put in the effort.
0
 
RamuncikasCommented:
Of course not, if it is a 90% / 10% split :))

Just joking.
Points is not the main reason why i spend my time here. Share my expearence and get more knowledge - that's why I'm here. So, weather you decide to split or not, this will not effect my ego :)

Ramuncikas
0
 
raterusCommented:
split them fairly, just remember that Ramuncikas gave you the original suggestion...so logically I should get all the points, afterall it is about sharing :^)
0
 
smoogaAuthor Commented:
hope that works for everybody.  Thanks for all the help guys!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.