ASP.NET ListView - How to set EmptyDataTemplate programmatically? - asp.net

I have a class MyListView, it inherits from ASP.NET ListView. I would like to implement a default behaviour - if a programmer doesn't specify EmptyDataTemplate in aspx code, the MyListView will use a predefined default template (class MyEmptyDataTemplate).
What I have tried is this:
public class MyListView : ListView
{
protected override void CreateChildControls()
{
if (EmptyDataTemplate == null)
EmptyItemTemplate = new MyEmptyDataTemplate();
base.CreateChildControls();
}
}
The MyEmptyDataTemplate implements ITemplate interface. The problem is, that InstantiateIn() method of the MyEmptyDataTemplate is never called, and my default template never appears in case there are no records in datasource. Apparently I wrong understand the ListView component lifecycle and template should be set somewhere else.

Try to do this on the Init event:
public class MyListView : ListView
{
public MyListView()
{
this.Init += (o, e) =>
{
if (EmptyDataTemplate == null)
EmptyDataTemplate = new MyEmptyDataTemplate();
};
}
}
edit
After checking this again I realized that EmptyDataTemplate was checked if emtpy, but the template which has been assigned is EmptyItemTemplate. However both methods are good to instantiate the templates..

Related

Sitecore CustomValidator does not fire on WFFM custom field

I've try to extend SingleLineText field on WFFM on Sitecore. This field will have CustomValidator. But ServerValidate event does not fire when page postbacked. The snipped code below.
public class SingleLineText : Sitecore.Form.Web.UI.Controls.SingleLineText
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
var validator = new CustomValidator() { Display = ValidatorDisplay.None };
validator.ServerValidate += this.Validator_ServerValidate;
this.generalPanel.Controls.Add(validator);
}
protected void Validator_ServerValidate(object source, ServerValidateEventArgs args)
{
// does not fire
var validator = source as IValidator;
args.IsValid = this.IsValid(validator);
}
}
The same code works fine on ustom user control field which has ascx.
You will want to move your validation code to a new class that implements FormCustomValidator.
public class MySingleLineTextValidator : FormCustomValidator
{
protected override bool EvaluateIsValid()
{
if (!String.IsNullOrEmpty(base.ControlToValidate))
{
Control controlToValidate = this.FindControl(base.ControlToValidate);
//Code to validate
}
return false;
}}
Then you will need add a BaseValidator Item in the WFFM Validation Folder, usually this path; /sitecore/system/Modules/Web Forms for Marketers/Settings/Validation. Add the assembly and class to the item.
Now against your custom Field, add the your new BaseValidator item in the Validation field and that's it.
See this post of a wffm custom form validator for a full example

Firing OnCreatingModelDataSource event in ASP.NET Web Forms applications

All ASP.NET data bound controls have an additional event in ASP.NET 4.5, CreatingModelDataSource. It provides a great way to create our own implementation of ModelDataSource and bind to a control like GridView.
I created a sample ModelDataSource and hooked it up with a GridView in the CreatingModelDataSource event as follows:
protected void gvStudent_CreatingModelDataSource(object sender, CreatingModelDataSourceEventArgs e)
{
e.ModelDataSource = new MyModelDataSource((GridView)sender);
}
Following is the sample ModeldataSource implementation that I wrote:
public class MyModelDataSource : ModelDataSource
{
MyDataSourceView view;
public MyModelDataSource(Control control)
: base(control)
{
}
public override ModelDataSourceView View
{
get
{
if (view == null)
{
view = new MyDataSourceView(this);
}
return view;
}
}
}
And following is MyModelDataSourceView:
public class MyDataSourceView : ModelDataSourceView
{
private MyModelDataSource _owner;
private StudentRepository repository;
public MyDataSourceView(MyModelDataSource owner)
: base(owner)
{
_owner = owner;
repository = new StudentRepository();
}
protected override IEnumerable ExecuteSelect(DataSourceSelectArguments arguments)
{
return repository.GetAll();
}
}
But the ExecuteSelect method doesn't get called automatically. It gets called when I set a SelectMethod to the GridView. As the result of ExecuteSelect method is finally bound to the GridView, specifying the SelectMethod doesn't make any sense here. Also, the event is not fired when gridView.DataBind() is called. Is there any way to kick off the things and make this event called automatically?
CreatingModelDataSource() was put in for the Model data source which is used in Model Binding. When you use model binding you need to specify the Select() method for model binding to work with GridVIew

Can't FindControl when RenderControl ascx in RenderBeginTag while overriding Panel

I'm creating a container using Panel control as follows:
public class CustomContainer : Panel
{
public override void RenderBeginTag(HtmlTextWriter writer)
{
var control this.Page.LoadControl("web user control path.ascx");
control.ID = "userControlId";
control.RenderControl(writer);
base.RenderBeginTag(writer);
}
public void ShowMessage(string message)
{
var control = this.FindControl("userControlId"); // control here is null!!
var custom = control as CustomControl;
custom.Message = message;
}
}
when I try to find the control with id userControlId which I rendered, it always retuns null!
Does anyone know what's happening? How can I solve this issue?
BTW: I can't add the CustomControl in CreateChildControls method because if the CustomContainer has code block I got an exception!
The Controls collection cannot be modified because the control
contains code blocks (i.e. <% ... %>).
You're probably calling ShowMessage before the control is rendered. Try calling ShowMessage during OnPreLoad or OnLoad. Basically, anywhere after the Render.

Designer problem with CompositeDataBoundControl

I have a custom class:
SimpleTemplatedControl : CompositeDataBoundControl
private ITemplate _itemTemplate;
[PersistenceMode(PersistenceMode.InnerProperty),
TemplateContainer(typeof(SimpleItem)),
]
public ITemplate ItemTemplate
{
get { return _itemTemplate; }// get
set { _itemTemplate = value; }// set
}
protected override int CreateChildControls(
System.Collections.IEnumerable dataSource,
bool dataBinding)
{
//
}
When I drop this on a webform I get such a smart tag in which I can choose a DataSource control. Pretty convinient. However if I add this attribute to this class:
[Designer(typeof(SimpleDesigner))]
I don't get to see that anymore but instead a smart tag to fill in my Template (also handy).
I would like to have both option available from within the same smart tag just like with a GridView control. How to accomplish this?
Which is the Designer type you're using? Normally it would be ControlDesigner but for the CompositeDataBoundControl you should use the DataBoundControlDesigner class to inherit your designer from.
Grz, Kris.

Constructor in webform?

I have an ASP.NET webform where I initialize an array with a list of controls on the page like this
FileUpload[4] = new FileUpload[4];
public myclass()
{
fileUpload[0] = FileUpload1;
fileUpload[0] = FileUpload2;
...etc
}
I then use these in the page load and they are all null. This seems a strange behavior to me. Can someone elaborate and explain? I can understand that they are null in the constructor but why should they be null when used in the page load.
They are null because the controls haven't been created yet.
Take a look at the ASP.NET Page Life Cycle Overview and the Init event.
If you want to add controls "manually", you need to do this in OnInit() so they can be given state from the LoadViewState() call that will happen just after OnInit().
If you don't know how many controls you need to add, because it's dynamic somehow, you can override LoadViewState and SaveViewState. See this example(written without Visual Studio):
public class MyPage : Page
{
class State
{
numberOfControls int
otherState object
}
override void LoadViewState(savedState object)
{
var myState = (State)savedState;
SetupMyControls(myState.numberOfControls);
base.LoadViewState(myState.otherState);
}
override object SaveViewState()
{
return new State
{
numberOfControls = GetNumberOfMyControls(),
otherState = base.SaveViewState()
};
}
}

Resources