Dabbas
Dabbas

Reputation: 3238

Why DataItem in my custom template databound control is null in ItemCommand event?

Here is my custom control code:

namespace MyControlNameSpace  
{  
  public class MyControlItemCommandEventArgs : CommandEventArgs
  {
    private MyControlItem _item;
    private object _commandSource;

    public MyControlItemCommandEventArgs(MyControlItem item, object commandSource, CommandEventArgs cea) : base(cea)
     {
      _item = item;
      _commandSource = commandSource;   
     }

    public MyControlItem Item { get{ return _item; } }
    public object CommandSource { get{ return _commandSource; } }

  }

  public class MyControlItem : Control, IDataItemContainer
  {
    public MyControlItem(object dataItem, int index)
    {
        _dataItem = dataItem;
        _dataItemIndex = _displayIndex = index;
    }  

    private readonly object _dataItem;
    private readonly int _dataItemIndex;
    private readonly int _displayIndex;

    public object DataItem { get { return _dataItem; } }
    public int DataItemIndex { get { return _dataItemIndex; } }
    public int DisplayIndex { get { return _displayIndex; } }

    protected override bool OnBubbleEvent(object source, EventArgs args)
    {
      if (args is CommandEventArgs)
      {
       var e = new MyControlItemCommandEventArgs(this, source, (CommandEventArgs)args);
       base.RaiseBubbleEvent(this, e);
       return true;
      }

      return false;
    }
  }  

  public delegate void ItemEventHandler(object sender, MyControlItemCommandEventArgs e);

  [DefaultProperty("Text")]
  [ToolboxData("<{0}:MyControl runat=server></{0}:MyControl>")]
  public class MyControl : CompositeDataBoundControl, IPrivilage
  {
    public event ItemEventHandler ItemCommand;

    protected virtual void OnItemCommand(MyControlItemCommandEventArgs e)
    {
     if (ItemCommand != null)
        ItemCommand(this, e);
    }

    protected override bool OnBubbleEvent(object source, EventArgs args)
    {
        // only bother bubbling appropriate events
        if (args is MyControlItemCommandEventArgs)
        {
            OnItemCommand((MyControlItemCommandEventArgs)args);
            return true;
        }

        return false;
    }

    protected override int CreateChildControls(IEnumerable dataSource, bool dataBinding)
    {
       // here I'm adding some controls like buttons and other

       // Iterate for ItemTemplate
       foreach (object dataItem in dataSource)
       {
         if (ItemTemplate != null)
         {
           // create instance of MyControlItem control
           var item = new MyControlItem(dataItem, count++);
           // instantiate in new item object
           ItemTemplate.InstantiateIn(item);
           // add item to Controls collection
           Controls.Add(item);
           // need to support <%# %> expressions
           item.DataBind();
         }
       }

      // some code here
    }
  }

In .aspx page:

protected void Page_Load(object sender, EventArgs e)
 {
   // if it's not post back then get the data and assign to MyControl DataSource property
   if(!IsPostBack)
     GetData();
 }    

protected void MyControl1_OnItemCommand(object sender, MyControlItemCommandEventArgs e)
 {
   var x = e.DataItem;  
   // x here is always null;
 }

As you can see I can't get e.DataItem when OnItemCommand event because it's always null.
I tried to remove if(!IsPostBack) in Page_Load so that every time page load datasource assigned, but this is not right, I should be able to not assigning datasource if it's PostBack like in Asp.Net Repeater control.

Any Idea how to do it?

Upvotes: 0

Views: 829

Answers (1)

Richard Deeming
Richard Deeming

Reputation: 31248

The OnItemCommand event is raised on post-back. At that point, if the CompositeDataBoundControl has ViewState enabled, it will recreate the child controls without querying the database. Your CreateChildControls method will be called with dataBinding set to false, and the dataSource will be an enumerable sequence of null objects which serve as placeholders for the actual data.

You'll get the same behaviour in any data-bound control. If you try the same thing with a Repeater, you'll see that the e.Item.DataItem is null in the ItemCommand event.

Upvotes: 0

Related Questions