Take the 2-minute tour ×
SharePoint Stack Exchange is a question and answer site for SharePoint enthusiasts. It's 100% free, no registration required.

I have a small problem with a GridView in my web part. I bind a DataTable to the SourceData of my GridView and check if the current user is an administrator. If he is, I will add additional CommandField columns. Here a part of my code:

protected void SumbitSearch_Click(object sender, EventArgs e)
{
...
GridViewResult.DataSource = null;
GridViewResult.BinData();
...
GridViewResult.DataSource = result;
GridViewResult.DataBind();
GridViewResult.HeaderRow.Cells[0].Visible = false;
foreach (GridViewRow gvr in GridViewResult.Rows)
{
    gvr.Cells[0].Visible = false;
}
GridViewResult.HeaderRow.Cells[1].Width = Unit.Pixel(175);
GridViewResult.HeaderRow.Cells[2].Width = Unit.Pixel(175);
GridViewResult.HeaderRow.Cells[1].Text = "Von: " + languageFrom;
GridViewResult.HeaderRow.Cells[2].Text = "Nach: " + languageTo;
//if() Check admin
//{
    CommandField deleteButton = new CommandField();
    deleteButton.ShowDeleteButton = true;
    GridViewResult.Columns.Add(deleteButton);
//}
...
}

If I deploy my web part, and click on my button, nothing happens. If I click a second time, suddenly the Ident column appears. If I click a third time, the delete Button appear. A fourth time a second delete Button appear and so on. I think the problem occur, because the new delete button column will add at the first column in the table. How could I fix this?

Btw is it possible to set a css style for the button? If I use deleteButton. ControlStyle.CssClass =""; the css class is valid for the complete table.

Last Change:

Okay, now I did it witch CreateChildControls(). But it doesn’t work right. The Button will only displayed at the last row of the Table and the event handler would not be fired.

My CreateChildControls() looks like:

...
protected Button deleteButton;
...

if((Page.IsPostBack) && ( // Check if admin == true )
{
    //Controls.Clear();
    deleteButton = new Button();
    deleteButton.Text = "Löschen";
    deleteButton.Click += new EventHandler(clickd);
    base.CreateChildControls();
}

Later i add a new cell to every row of the gridview:

TableCell test = new TableCell();
int i = 0;
while (i < GridViewResult.Rows.Count)
{                           
    deleteButton.ID = "delete_" + GridViewResult.Rows[i].Cells[1].Text;
    test.Controls.Add(deleteButton);
    GridViewResult.Rows[i].Cells.Add(test);
    i++;
}

I would like to have, a delete button for every row in my table. At the runtime, I dont know how many rows the result have. Is it generally possible to add a control in a function outside of CreateChildControls() if the control is created in the CreateChildControls? What works wrong?

Greetz, Taz

share|improve this question
    
Well I'd say the first problem is that you are adding the button in a postback function. Do you have a CreateChildControls function? –  Kit Menke Oct 18 '11 at 15:00
    
No i haven't. Do you mean to overwrite the CreateChildControls and add here the controls? –  hofmeister Oct 18 '11 at 17:10
    
This turned out to be very interesting! I added an example to my answer. Hopefully that helps! –  Kit Menke Oct 19 '11 at 16:52
add comment

1 Answer

up vote 2 down vote accepted

The problem is that you are creating the CommandField button in a postback event: SumbitSearch_Click. Take a look at Wictor's wonderful graphic.

Instead, you should be overriding the CreateChildControls function and creating most of your controls there. You'll notice, however, that on a postback the CreateChildControls will be called before your SumbitSearch_Click function (which makes sense if you think about it.. the button must exist before the button click event can fire).

You could use the Page.IsPostback within CreateChildControls to have some separate logic or use OnPreRender to make the decision since it will run after your events.


Here is an example which uses the session as a DataSource.

SPGridView with query and delete

The code:

class SimpleGridView : CompositeControl
{
    private const string SESSION_ID = "SalesData";
    private ObjectDataSource _gridDS;
    private TextBox _txtQuery;
    private SPGridView _grid;

    public DataView SelectData(string query)
    {
        DataTable dataSource = null;

        // using session to simulate a "delete", otherwise it would do nothing each time :)
        if (null == this.Page.Session[SESSION_ID])
        {
            dataSource = new DataTable();

            // setup columns
            dataSource.Columns.Add("ID", Type.GetType("System.Int32"));
            dataSource.Columns.Add("Name");
            dataSource.Columns.Add("Region");
            dataSource.Columns.Add("Total Sales", Type.GetType("System.Double"));
            dataSource.Columns.Add("Created", Type.GetType("System.DateTime"));

            // add some bogus data
            dataSource.Rows.Add(1, "J. Smith", "Europe", 10000, new DateTime(2010, 10, 7, 8, 0, 0));
            dataSource.Rows.Add(2, "J. Smith", "North America", 15000, new DateTime(2010, 10, 8, 9, 00, 0));
            dataSource.Rows.Add(3, "J. Smith", "Asia", 5000, new DateTime(2010, 10, 7, 10, 0, 0));
            dataSource.Rows.Add(4, "S. Jones", "Europe", 7000, new DateTime(2010, 10, 9, 11, 0, 0));
            dataSource.Rows.Add(5, "S. Jones", "North America", 30000, new DateTime(2010, 10, 7, 9, 00, 0));
            dataSource.Rows.Add(6, "S. Jones", "Asia", 8700, new DateTime(2010, 10, 9, 8, 0, 0));
            dataSource.Rows.Add(7, "W. Nguyen", "Europe", 3000, new DateTime(2010, 10, 8, 8, 0, 0));
            dataSource.Rows.Add(8, "W. Nguyen", "North America", 50000, new DateTime(2010, 10, 7, 12, 30, 0));
            dataSource.Rows.Add(9, "W. Nguyen", "Asia", 25000, new DateTime(2010, 10, 7, 8, 0, 0));
            dataSource.Rows.Add(10, "C. O'Reilly", "Europe", 200, new DateTime(2008, 1, 16, 15, 0, 0));
            dataSource.Rows.Add(11, "C. O'Reilly", "North America", 5000, new DateTime(2009, 11, 1, 16, 0, 0));
            dataSource.Rows.Add(12, "C. O'Reilly", "Asia", 8000, new DateTime(2010, 10, 9, 19, 0, 0));
            this.Page.Session[SESSION_ID] = dataSource;
        }
        else
        {
            dataSource = (DataTable)this.Page.Session[SESSION_ID];
        }

        DataView view = new DataView(dataSource);
        if (!string.IsNullOrEmpty(query))
        {
            query = query.Replace("'", "''");
            view.RowFilter = string.Format("Name LIKE '%{0}%'", query);
        }

        return view;
    }

    public void DeleteItem(int row_id)
    {
        // do some sort of delete action against our datasource
        // in this simple case, we're just deleting rows from the session
        DataTable dataSource = (DataTable)this.Page.Session[SESSION_ID];
        DataRow[] rows = dataSource.Select(string.Format("ID = {0}", row_id));
        if (null != rows && rows.Length == 1)
        {
            rows[0].Delete();
        }
    }

    private void AddBoundField(string name)
    {
        BoundField column = new BoundField();
        column.DataField = name; // must match the column name in the datasource
        column.SortExpression = name;
        column.HeaderText = name;
        _grid.Columns.Add(column);
    }

    protected override void CreateChildControls()
    {
        base.CreateChildControls();

        _txtQuery = new TextBox();
        _txtQuery.ID = "txtQuery";
        this.Controls.Add(_txtQuery);

        // really all this is good for is causing the page to post back
        Button btnSubmit = new Button();
        btnSubmit.ID = "btnSubmit";
        btnSubmit.Text = "Submit";
        btnSubmit.Click += new EventHandler(btnSubmit_Click);
        this.Controls.Add(btnSubmit);

        if (Page.IsPostBack)
        {
            // don't display the grid until they click submit at least once
            CreateGridView();
        }
    }

    void btnSubmit_Click(object sender, EventArgs e)
    {
        // clear so that they can query multiple times
        _gridDS.SelectParameters.Clear();

        // they clicked the button so set our query
        _gridDS.SelectParameters.Add("query", _txtQuery.Text);
    }

    private void CreateGridView()
    {
        const string GRIDID = "grid";
        const string DATASOURCEID = "gridDS";

        // initialize the ODS
        _gridDS = new ObjectDataSource();
        _gridDS.ID = DATASOURCEID;
        // calling our SelectData function in this CompositeControl
        _gridDS.SelectMethod = "SelectData";
        // calls our Delete Item method when they click our CommandField delete button
        _gridDS.DeleteMethod = "DeleteItem";
        // so our grid datasource knows which object to ask for data
        _gridDS.TypeName = this.GetType().AssemblyQualifiedName;
        _gridDS.ObjectCreating += new ObjectDataSourceObjectEventHandler(gridDS_ObjectCreating);
        // we need this event in order to add parameters that will be used for our delete method
        // otherwise it can't find it
        _gridDS.Deleting += new ObjectDataSourceMethodEventHandler(_gridDS_Deleting);

        this.Controls.Add(_gridDS);

        // Initialize the grid and link it to the ObjectDataSource
        _grid = new SPGridView();
        _grid.ID = GRIDID;
        _grid.DataSourceID = _gridDS.ID;
        _grid.AutoGenerateColumns = false;

        // Paging
        _grid.AllowPaging = true;
        _grid.PageSize = 10;

        // Sorting
        _grid.AllowSorting = true;

        this.Controls.Add(_grid);

        // add our columns to the grid
        AddBoundField("ID");
        AddBoundField("Name");
        AddBoundField("Region");
        AddBoundField("Total Sales");
        AddBoundField("Created");

        // our column that shows the delete button a user can click
        CommandField cfDelete = new CommandField();
        cfDelete.ShowDeleteButton = true;
        cfDelete.ButtonType = ButtonType.Button;
        cfDelete.DeleteText = "Delete";
        _grid.Columns.Add(cfDelete);

        // needed to allow deleting rows using ID
        // if you don't have this, nothing is sent to your ObjectDataSource "Deleting" event
        string[] dataKeyNames = { "ID" };
        _grid.DataKeyNames = dataKeyNames;

        // setting PagerTemplate to null here will display page numbers for paging
        _grid.PagerTemplate = null;
    }

    void _gridDS_Deleting(object sender, ObjectDataSourceMethodEventArgs e)
    {
        // This function isn't needed if your ObjectDataSource.DeleteMethod parameters
        // exactly match the column names in your datasource. I found this confusing
        // so I do a little conversion

        // it will be null if the column is not present in the grid's DataKeyNames
        if (null != e.InputParameters["ID"])
        {
            int id = (int)e.InputParameters["ID"];

            // clear the collection of parameters or it will try to find
            // a delete function that has every single parameter
            e.InputParameters.Clear();
            // notice that this parameter name matches the parameter in our delete method
            // which was set on the grid's objectdatasource
            e.InputParameters.Add("row_id", id);
        }
    }

    private void gridDS_ObjectCreating(object sender, ObjectDataSourceEventArgs e)
    {
        // our ObjectDataSource uses this CompositeControl to select data
        e.ObjectInstance = this;
    }
}
share|improve this answer
    
See my Last Change:. Thanks. –  hofmeister Oct 19 '11 at 8:17
    
@Taz I think you still want to use your CommandField deleteButton. That will add a delete button to each row for you. I think I can create an example for you since I have some code already. –  Kit Menke Oct 19 '11 at 14:51
    
That's great! Thank you. You earned a new achievement: New blog reader. :) Greetz. –  hofmeister Oct 20 '11 at 5:15
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.