I have created a very simple custom control:
[assembly: System.Web.UI.TagPrefix("CustomMultiLineTextBox", "evo")]
public class CustomMultiLineTextBox :
System.Web.UI.WebControls.TextBox
{
public override int Rows
{
get
{
return 5;
}
}
public override System.Web.UI.WebControls.TextBoxMode TextMode
{
get
{
return System.Web.UI.WebControls.TextBoxMode.MultiLine;
}
}
public override string CssClass
{
get
{
return "textboxStyle";
}
set
{
//base.CssClass = "textboxStyle";
base.CssClass = value;
}
}
}
}
However, when I drop this control onto my aspx page the CssClass does not seem to be applied. The TextMode and Rows property are set correctly.
<evo:CustomMultiLineTextBox ID="txtTrainingNeeds" runat="server">
</evo:CustomMultiLineTextBox>
Only if I add CssClass="textboxStyle" to markup will the CssClass be applied.
Any suggestions?
Thanks in advance
Since it doesn't look like you're modifying behavior, only data, I would set the properties to the values you want in the constructor instead of overriding the properties themselves.
public CustomMultiLineTextBox()
{
Rows = 5;
TextBoxMode = System.Web.UI.WebControls.TextBoxMode.MultiLine;
CssClass = "textboxStyle";
}
Related
I have a server-side control which renders as <input type="Something"> or <textarea>. The code is self-explanatory:
public string Namespace
{
get { return nspace; }
set { nspace = value; }
}
public string Model
{
get { return model; }
set { model = value; }
}
public string Text
{
get { return text; }
set { text = value; }
}
public string TextMode
{
get { return textMode; }
set { textMode = value; }
}
public string _Type
{
get { return type; }
set { type = value; }
}
public string Property { get; set; }
protected override void RenderContents(HtmlTextWriter output)
{
output.AddAttribute(HtmlTextWriterAttribute.Id, Property.ToLower());
output.AddAttribute(HtmlTextWriterAttribute.Name, Property.ToLower());
output.AddAttribute(HtmlTextWriterAttribute.Type, _Type);
if(!String.IsNullOrEmpty(Text))
output.AddAttribute(HtmlTextWriterAttribute.Value, Text);
Type modelType = Type.GetType(string.Format("{0}.{1}", Namespace, Model));
PropertyInfo propInfo = modelType.GetProperty(Property);
var attr = propInfo.GetCustomAttribute<RequiredAttribute>(false);
if (attr != null)
{
output.AddAttribute("data-val", "true");
output.AddAttribute("data-val-required", attr.ErrorMessage);
}
//forces styles to be added to the control
this.AddAttributesToRender(output);
if (!String.IsNullOrEmpty(TextMode))
{
output.RenderBeginTag("textarea");
output.RenderEndTag();
}
else
{
output.RenderBeginTag("input");
output.RenderEndTag();
}
}
This control is aimed at getting validation error messages from Data Model (instead of providing "data-val" and "data-val-required" to every textbox).
using this code is easy:
<ServerControlTag:ControlName Property="aProp" runat="Server" Model="MyModel" ID="txtSomething" />
Which renders as a input type=text tag, and the following renders as a textarea tag:
<ServerControlTag:ControlName Property="Description" runat="Server" Model="MyModel" TextMode="MultiLine" ID="txtDescription" class="message" />
My problem is when rendering textarea I cannot find any attribute to fill the text of textarrea. To set text in a textarea I have just found the following syntax:
<textarea ... > My Text Here </textarea>
yet, I don't know how to implement it in my server control. I don't know even if I am on the right track.
You need to call the normal Write() method to write text inside the tag.
Remember to HTML-encode the text.
public partial class ChatUserControl : System.Web.UI.UserControl
{
UserChatClass ucc = new UserChatClass();
public ChatUserControl()
{
lblChatFriend = new Label();
txtChatMessage = new TextBox();
imgFriend = new Image();
rpChatMessages = new Repeater();
}
public string ChatFriend { get { return this.lblChatFriend.Text; } set { this.lblChatFriend.Text = value; } }
public string imgFriendUrl { get { return this.imgFriend.ImageUrl; } set { this.imgFriend.ImageUrl = value; } }
public object rpChatDataSource { get { return this.rpChatMessages.DataSource; } set { this.rpChatMessages.DataSource = value; } }
public Repeater rpChatMessagesToBind { get { return this.rpChatMessages; } set { this.rpChatMessages = value; } }
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
ChatUserControl user1 = new ChatUserControl();
divChatUserControlCover.Controls.Add(user1);
}
}
private void BindUserControls()
{ ChatUserControl user1 = divChatUserControlCover.Controls[1] as ChatUserControl;
user1.ChatFriend = row["username"].ToString();
user1.imgFriendUrl = "../../HttpImageHandler.jpg?username=" + row["username"].ToString();
DataSet dsCM = ucc.GetChatMessages(Session["username"].ToString(), row["username"].ToString());
user1.rpChatDataSource = dsCM;
user1.DataBindForRpChatMessagesToBind();
user1.Visible = true;
}
Master.aspx
<div id="divChatUserControlCover" runat="server">
</div>
Ok I have edited the code and now I have created properties. How do I call the DataBind method for rpChatMessages? I also cant see my usercontrol on page. Why
I'm not sure if your trying to reference the first label or second label. If its the second lable you can't just do chatMessage. you would have to do
((Label)rpChatMessages.FindControl("chatMessage")) due to scope of controls.
When you reference a component inside another component (ie Repeater) the child component no longer belongs to the document (implied this) but rather belongs to the control, ie
this.rpChatMessages { chatMessage }
I think you are just trying to pass a value to one control inside a UserControl if this is correct, declare a public property like this:
ASCX code behind
public string MyProperty
{
get
{
return this.lbl.Text;
}
set
{
this.lbl.Text = value;
}
}
Setting the value to the UserControl
private void BindUserControls()
{
ChatUserControl user1 = divChatUserControlCover.Controls[1] as ChatUserControl;
user1.MyProperty = row["username"].ToString();
Setting the value in the page markup
<uc1:ChatUserControl MyProperty='<%# Eval("some field") %>' ...
Edit 1
Remove that line
public object rpChatDataSource { get { return this.rpChatMessages.DataSource; } set { this.rpChatMessages.DataSource = value; }
And instead add a method
public void BindMyRepeaterOrWhatever(IEnumerable<Yourentity> data)
{
this.myDataBoundControl.DataSource = data;
this.myDataBoundControl.DataBind();
}
You can change the IEnumerable<Yourentity> data for object data but if you can pass a strongly typed enumeration would be better
To my surprise I found why my user control's child controls dont get instantiated. Its because ChatUserControl user1 = new ChatUserControl() doesnt get its child controls initialized.
The proper way to create a new intance of user control is this way....
ChatUserControl user1 = (ChatUserControl)Page.LoadControl("~/ChatUserControl.ascx");
I have a custom asp-net control that inherits from another one and its works as expected, though the properties are only set properly if i code them in the markup directly, so for instance if i need set a property at runtime that is some dynamic value, this value is never set or somehow lost.
Here's the markup code:
<!--related form-->
<fw:advancedformdisplay id="formDisp" runat="server" captchaenabled="true" EmailEnabled="true" EnableViewState="true" captchaprivatekey="xxxxxxxxxxxxxxxxxxxx" captchapublickey="xxxxxxxxxxxxx" captchatheme="white" SourceType="MenuItem" SourceMainId="Auto">
</fw:advancedformdisplay>
This is the code of the control:
[DefaultProperty("CaptchaEnabled"),ToolboxData("<{0}:AdvancedFormDisplay runat=server></{0}:AdvancedFormDisplay>"), Description("This is an enhanced FormDisplay control that inlcudes Googles Captcha control is enabled")]
public class AdvancedFormDisplay :SiteBuilder.WebControls.FormDisplay
{
bool _CaptchaEnabled = false, sendEmail = false;
string captchaErrorMessage = "The verification code entered is not valid. Please try again!";
RecaptchaControl captchaControl = null;
string captchaPrivateKey = "", captchaPublicKey = "", captchaTheme = "clean";
string originalFormHtml = string.Empty;
string afterText = string.Empty, beforeText = string.Empty;
Literal litHtmlForm = null;
string captchaErrorClass = "errorCaptcha";
public string EmailBeforeText
{
get { return beforeText; }
set { beforeText = value; }
}
public string EmailAfterText
{
get { return afterText; }
set { afterText = value; }
}
public string CaptchaErrorClass
{
get { return captchaErrorClass; }
set { captchaErrorClass = value; }
}
public bool CaptchaEnabled
{
get { return _CaptchaEnabled; }
set { _CaptchaEnabled = value; }
}
public bool EmailEnabled
{
get { return sendEmail; }
set { sendEmail = value; }
}
public string CaptchaErrorMessage
{
get { return captchaErrorMessage; }
set { captchaErrorMessage = value; }
}
/// <summary>
/// red,white,blackglass,clean
/// </summary>
public string CaptchaTheme
{
get { return captchaTheme; }
set { captchaTheme = value; }
}
public string CaptchaPrivateKey
{
get { return captchaPrivateKey; }
set { captchaPrivateKey = value; }
}
public string CaptchaPublicKey
{
get { return captchaPublicKey; }
set { captchaPublicKey = value; }
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
}
public override void OnSaved(FormDisplayEventArgs e)
{
//If captcha control is enabled we need to adda bit of code to redirect form properly
if (CaptchaEnabled && e.Redirect && !e.SendMail)
{
//Do Stuff
}
if(sendEmail)
{
//Send email
}
base.OnSaved(e);
}
public override void OnSaving(FormDisplayEventArgs e)
{
if (CaptchaEnabled)
{
//Validate and do stuff
}
base.OnSaving(e);
}
}
And then in my asp.net page that is using control, created by markup code, in the Page_Load() i try to assign some values to some properties and and the values aren't set properly, meaning that if i have set for isntance, the property EmailBeforeText = "somthing" this value will not be assigned..
protected void Page_Load(object sender, EventArgs e)
{
//2: Get the language of menuitem - Based on current culture setting (for by dropdownbox - change logic)
try
{
currentCulture = Thread.CurrentThread.CurrentCulture.ToString();
// Redirect if domain does not match rootnode.
DomainChecker.CheckURL(this.Request, this.Response, currentCulture);
if (footerArticle != null)
footerArticle.SourceMenuId = Digimaker.Config.Custom.Get("FooterID_" + currentCulture).ToString();
}
catch
{
currentCulture = "en-GB";
if( footerArticle != null )
footerArticle.SourceMenuId = Digimaker.Config.Custom.Get("FooterID_" + currentCulture).ToString();
}
Any ideas what i'm missing here?
Thanks a lot for your reading!
Regards,
byte_slave
short answer: use viewstate to persist your custom values!
Understanding ASP.NET ViewState whitepaper (see example with NavigateUrl)
edit: as reading the white-paper is obviously a really hard thing:
Each control is responsible for storing its own state, which is
accomplished by adding its changed state to its ViewState property.
The ViewState property is defined in the System.Web.UI.Control class,
meaning that all ASP.NET server controls have this property available.
(When talking about view state in general I'll use lower case letters
with a space between view and state; when discussing the ViewState
property, I'll use the correct casing and code-formatted text.)
If you examine the simple properties of any ASP.NET server control
you'll see that the properties read and write directly to the view
state. (You can view the decompiled source code for a .NET assembly by
using a tool like Reflector.) For example, consider the HyperLink Web
control's NavigateUrl property. The code for this property looks like
so:
public string NavigateUrl
{
get
{
string text = (string) ViewState["NavigateUrl"];
if (text != null)
return text;
else
return string.Empty;
}
set
{
ViewState["NavigateUrl"] = value;
}
}
As this code sample illustrates, whenever a control's property is
read, the control's ViewState is consulted. If there is not an entry
in the ViewState, then the default value for the property is returned.
When the property is assigned, the assigned value is written directly
to the ViewState.
I have written the following override for the DataFormatString in my BoundField derived control, yet the field is still formatted as a plain number. I assume that this is because the formatting code isn't calling the DataFormatString property but using the private _dataField field. I would like set the base property in my override, but I want to do so based on a declarative FormatType enum property that will determine which default format string to use. Where could I do this?
public override string DataFormatString
{
get
{
var baseString = base.DataFormatString;
if (!string.IsNullOrWhiteSpace(baseString))
{
return FormatStrings.Currency;
}
return baseString;
}
set
{
base.DataFormatString = value;
}
}
EDIT: It turns out declarative property values are set when the control is built by it's parent, so it's pretty safe to assume they won't be properly used until after this phase of the page life cycle. This is what I actually wanted to know.
You can add the DefaultValue attribute at the top of the method:
[DefaultValue(false)]
public bool SomeCondition
{
get { return someCondition; }
set { someCondition = value; }
}
It looks like the parameterless constructor is the best place to do this. I wanted to set some properties to default values based on other properties, but I realised it wasn't necessary if I determined these defaults when needed, versus in the property getters. E.g:
public BoundReportField()
{
_formatType = FieldFormatTypes.String;
}
protected virtual string GetDefaultFormatString(FieldFormatTypes formatType)
{
var prop = typeof(FormatStrings).GetProperty(formatType.ToString()).GetValue(null, null);
return prop.ToString();
}
protected virtual IFormatProvider GetFormatProvider(FieldFormatTypes formatType)
{
var info = (CultureInfo)CultureInfo.CurrentCulture.Clone();
info.NumberFormat.CurrencyDecimalDigits = 0;
info.NumberFormat.CurrencySymbol = "R";
info.NumberFormat.CurrencyGroupSeparator = ",";
info.NumberFormat.CurrencyDecimalSeparator = ".";
return info;
}
private FieldFormatTypes _formatType;
public virtual FieldFormatTypes FormatType
{
get { return _formatType; }
set
{
_formatType = value;
}
}
protected override string FormatDataValue(object dataValue, bool encode)
{
var formatString = DataFormatString;
var formatProvider = GetFormatProvider(_formatType);
if (string.IsNullOrWhiteSpace(formatString))
{
formatString = GetDefaultFormatString(_formatType);
}
ApplyFormatStyles(_fieldCell);
var retString = string.Format(formatProvider, formatString, dataValue);
return retString;
}
I am in need of some help. I am building a custom web user control which is going to be picking colours.
As of right now, it has two [asp:textbox]es on the page (foregroundColour and backgroundColour).
I want my foreground colour to default to "FFFFFF" and my background colour to default to "000000", AND I the user to be able to specify their own initial values though the tag.
<ucFontChooser id="testchooser" runat="server" foregroundcolor="AABBCC" />
I have two properties that are tied to the textboxes:
[DefaultValue("000000")]
public string ForegroundColor { get { return foregroundColorSelectorHex.Text; } set { foregroundColorSelectorHex.Text = value; } }
[DefaultValue("FFFFFF")]
public string BackgroundColor { get { return backgroundColorSelectorHex.Text; } set { backgroundColorSelectorHex.Text = value; } }
Please note that I am aware that the DefaultValue is only for the visual studio property window and doesn't actually set any value.
However, I have tried to set the default value by in the constructor of the usercontrol to do:
ForegroundColor = "000000"
This gives me an exception, because at the point of the constructor, the foregroundColorSelectorHex is null.
So if I try and setting the default in the OnInit event, or on *Page_Load* then it simply always uses the default I set and the set property value of "AABBCC" is overwritten.
What is the correct way to do what am I trying?
Thank you.
After much debugging, I came up with a solution to do exactly what I need.
public override string ID
{
set
{
base.ID = value;
InitializeProperties();
}
}
protected void InitializeProperties()
{
ForegroundColor = "000000";
BackgroundColor = "ffffff";
EnableBackgroundColor = false;
PrimaryFont = "Arial";
SecondaryFont = "Helvetica";
TertiaryFont = "sans-serif";
}
the .NET framework will call mycontrol.ID = "bla", which is when the user controls subcontrols come into context. It is called BEFORE the containing control/page reads the tags attributes and sets the properties.
Looks hacky, but works great.
I think a complete answer would be too long to answer here, and it's documented at MSDN already.
See this page: http://msdn.microsoft.com/en-us/library/ms972975.aspx
And search for the text "Adding Properties and Methods to a User Control"
(But read the whole article anyway so you understand the details.)
However, from the code in the article, it should you how to return a default value if the property is null. Assuming you have a property named CategoryID, the property should be defined as:
public int CategoryID
{
get
{
object o = ViewState["CategoryID"];
if (o == null)
return 0; // return a default value
else
return (int) o;
}
set
{
ViewState["CategoryID"] = value;
}
}
You can use the same pattern to define the color.
Try keeping the value of the property in the viewstate and then setting the .Text in the Page_PreRender, like so:
public string ForegroundColor
{
get
{
if (ViewState["forecolor"] == null)
{
ViewState["forecolor"] = "000000";
}
return (string) ViewState["forecolor"];
}
set
{
ViewState["forecolor"] = value;
}
}
protected override void OnInit(EventArgs e)
{
this.PreRender += Page_PreRender;
base.OnInit(e);
}
private void Page_PreRender(object sender, EventArgs e)
{
foregroundColorSelectorHex.Text = ForegroundColor;
}
Not sure this will work, but could you do something like this in your page_load:
protected void Page_Load {
if (String.IsNullOrEmpty(ForegroundColor))
ForegroundColor = "FFFFFF";
}
You should initialize the value when it is not postback i.e.
if(!Page.IsPostBack){
//Initialize your values
ForegroundColor = "FFFFFF";
}
Can't you create your foregroundColorSelectorHex and backgroundColorSelectorHex in the constructor ?
public string ForegroundColor {
get { return foregroundColorSelectorHex.Text; }
set { foregroundColorSelectorHex.Text = value; }
}
public string BackgroundColor {
get { return backgroundColorSelectorHex.Text; }
set { backgroundColorSelectorHex.Text = value; }
}
public FontChooser () {
foregroundColorSelectorHex = new ColorSelector();
backgroundColorSelectorHex = new ColorSelector();
ForegroundColor = "FFFFFF";
BackgroundColor = "000000";
}