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.
Related
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..
I have a custom control for building forms to automatically generate a label-input field pair. But I need to be able to modify attributes of the generated label-input field pair in my vb code behind file. The problem is that the code behind file seems to be applied before the custom control. How do I work around this issue?
You could expose the inner controls as public properties of your custom control.
For example:
public class MyCustomControl : CustomControl
{
Label _label;
// initialize _label in OnInit() ...
public string LabelText { get { return _label.Text; } set { _label.Text = value; } }
}
I have a WebControl and it has a property. However, value of this property should not be changed once the control has been constructed... in other words, the property can be set only in some code like:
<ct:Acontrol ID="xxx" Aproperty="xxx" runat="server"></ct:Acontrol>
but not:
xxx.Aproperty=...
so what is the normal way to do that? Thanks!
The properties that you are using in markup must be public properties with a public getter and setter. There is no special syntax for "only set this once".
What you can do is check in the setter whether it was already set and if so, not set to the new value.
private string _aProperty;
public string Aproperty
{
get { return _aProperty;}
set
{
if(_aProperty == null)
{
_aProperty = value;
}
}
}
You should be able to use
xxx.Attributes("Aproperty")
All ASP.NET markup attributes are set as properties after the constructor is executed. You can select specific read-only properties to be set only in the constructor by using sub-classes of the control.
<!-- Aproperty=xxx -->
<ct:Acontrolxxx ID="xxx" runat="server"></ct:Acontrolyyy>
<!-- Aproperty=yyy -->
<ct:Acontrolyyy ID="yyy" runat="server"></ct:Acontrolxxx>
public class Acontrolxxx : Acontrolbase
{
public Acontrolxxx () { base.Aproperty = xxx; }
}
The property is probably using a combination of the EditorBrowsable and DesignerSerializationVisibility attributes:
[EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
public string SomeProperty { get; set; }
The DesignerSerializationVisibility attribute shows the property in markup, and the EditorBrowsable attribute hides the property in code-behind.
The following test:
[TestClass]
public class MyTestClass
{
private TestContext _testContext;
protected TestContext TestContext
{
get { return _testContext; }
set { _testContext = value; }
}
[TestMethod]
[HostType("ASP.NET")]
[UrlToTest("http://localhost/MyPage.aspx")]
public void TestMyPage()
{
TextBox tb = TestContext.RequestedPage.FindControl("ControlId") as TextBox;
Assert.IsNotNull(tb);
}
}
fails, and using the string "ctl00$ContentPlaceHolder1$ControlId" as control Id provide a proper control... I know, ASP.NET contains "ClientID" property for web-controls, but is there any possibility to know in advance the control's client Id in the TEST (Under VS 2008)?
Thanks.
I don't think the ClientID is what you're after here. I think your problem is that FindControl is not doing what you think it is.
FindControl is not recursive. If your textbox is inside of a ContentPlaceHolder, then you need to call FindControl on the placeholder, not the Page.
Otherwise, I suggest writing a recursive FindControl function that will search the entire control heirarchy. You can see an example here.
I hope someone can help me. I have the following custom server control:
[ParseChildren(true)]
public class MyControl : WebControl, INamingContainer
{
[PersistenceMode(PersistenceMode.InnerProperty)]
public string MyProperty
{
get;set;
}
}
It works perfectly with the following mark-up:
<acme:MyControl runat="sever">
<MyProperty>Test String</MyProperty>
</acme:MyControl>
But if I try to localise the property string, I get a parse error:
<acme:MyControl runat="sever">
<MyProperty><%=(string)GetLocalResourceObject("MyResourceKey") %></MyProperty>
</acme:MyControl>
Even if I cast the type, ASP.NET indicates that the property cannot accept controls as children. How should the expression look like if I want to localise it? I can make the property accessible as an attribute of the control's tag, but I prefer the mark-up above, it looks more elegant and clean.
Thanks
Add a second property called MyPropertyResourceKey, so your final code would be:
[ParseChildren(true)]
public class MyControl : WebControl, INamingContainer
{
[PersistenceMode(PersistenceMode.InnerProperty)]
public string MyProperty
{
get;set;
}
string _propertyResourceKey;
[PersistenceMode(PersistenceMode.InnerProperty)]
public string MyPropertyResourceKey
{
get {
return _propertyResourceKey;
}
set {
_propertyResourceKey = value;
MyProperty = (string)GetLocalResourceObject(_propertyResourceKey);
}
}
}
EDIT:
Based on comments, it seems that there may also be a demand for a more flexible method. Generally, if you are looking assign a dynamic value to a control, you will want to either create a Data Bound control (if applicable) http://msdn.microsoft.com/en-us/library/ms366540.aspx.
If, on the other hand, the control does't know how its will usually be assigned, the accepted method is to assign the property value in the code-behind of the page.