[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

Multiple EditCommandColumns in a datagrid

Posted on 2005-05-06
30
Medium Priority
?
466 Views
Last Modified: 2012-08-13
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?
0
Comment
Question by:smooga
  • 12
  • 8
  • 8
  • +1
30 Comments
 
LVL 14

Expert Comment

by:Ramuncikas
ID: 13953331
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
 
LVL 26

Expert Comment

by:Rejojohny
ID: 13953378
>> 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
 
LVL 14

Expert Comment

by:Ramuncikas
ID: 13953415
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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:smooga
ID: 13954448
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
 

Author Comment

by:smooga
ID: 13959386
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
 
LVL 33

Assisted Solution

by:raterus
raterus earned 500 total points
ID: 13959444
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
 
LVL 26

Expert Comment

by:Rejojohny
ID: 13959743
>> 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
 
LVL 14

Accepted Solution

by:
Ramuncikas earned 500 total points
ID: 13959778
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
 
LVL 33

Expert Comment

by:raterus
ID: 13959864
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
 
LVL 14

Expert Comment

by:Ramuncikas
ID: 13960127
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
 

Author Comment

by:smooga
ID: 13960189
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
 
LVL 33

Expert Comment

by:raterus
ID: 13960223
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
 

Author Comment

by:smooga
ID: 13960268
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
 
LVL 33

Expert Comment

by:raterus
ID: 13960373
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
 

Author Comment

by:smooga
ID: 13960396
<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
 
LVL 33

Expert Comment

by:raterus
ID: 13960483
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
 

Author Comment

by:smooga
ID: 13960549
I tried it but I got the same results :(
0
 
LVL 14

Expert Comment

by:Ramuncikas
ID: 13960600
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
 
LVL 33

Expert Comment

by:raterus
ID: 13960620
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
 

Author Comment

by:smooga
ID: 13960666
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
 

Author Comment

by:smooga
ID: 13960692
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
 
LVL 14

Expert Comment

by:Ramuncikas
ID: 13960724
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
 

Author Comment

by:smooga
ID: 13960736
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
 
LVL 33

Expert Comment

by:raterus
ID: 13960782
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
 

Author Comment

by:smooga
ID: 13960786
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
 
LVL 14

Expert Comment

by:Ramuncikas
ID: 13961140
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
 

Author Comment

by:smooga
ID: 13961332
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
 
LVL 14

Expert Comment

by:Ramuncikas
ID: 13961481
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
 
LVL 33

Expert Comment

by:raterus
ID: 13961581
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
 

Author Comment

by:smooga
ID: 13961595
hope that works for everybody.  Thanks for all the help guys!
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction This article shows how to use the open source plupload control to upload multiple images. The images are resized on the client side before uploading and the upload is done in chunks. Background I had to provide a way for user…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
Loops Section Overview
Whether it be Exchange Server Crash Issues, Dirty Shutdown Errors or Failed to mount error, Stellar Phoenix Mailbox Exchange Recovery has always got your back. With the help of its easy to understand user interface and 3 simple steps recovery proced…
Suggested Courses

834 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question