The First - LblTextBox:
A label and textbox that have a LabelText field that can be set to change the label text
The Second - LoginCtl:
A login control that has two instances of LblTextBox for user name, password and a submit button
I want to control the tag rendering of these controls for formatting so I am not overriding CreateChildControls() to get the job done.
My issue is that the controls are rendered but none of the OnInit() code in either controls takes hold (blank labels, css styles not applied, etc..).
Any direction would be great!
public class LblTextBox : CompositeControl
{
public string LabelText { get; set; }
public string Text { get; set; }
TextBox input;
Label label;
RequiredFieldValidator evalReqField;
public LblTextBox()
{
label = new Label();
input = new TextBox();
evalReqField = new RequiredFieldValidator();
}
protected override void OnInit(EventArgs e)
{
label.ID = "lblTextBox";
label.Text = string.Format("{0}:", LabelText);
input.ID = "tbInput";
evalReqField.ID = "evalInput";
evalReqField.ControlToValidate = input.ID;
evalReqField.ErrorMessage = "(Required)";
evalReqField.Display = ValidatorDisplay.Dynamic;
}
protected override void RenderChildren(HtmlTextWriter writer)
{
writer.RenderBeginTag(HtmlTextWriterTag.Div);
label.RenderControl(writer);
input.RenderControl(writer);
evalReqField.RenderControl(writer);
writer.RenderEndTag();
}
}
public class LoginCtl : CompositeControl
{
public string UserName
{
get
{
return (ltbUser != null) ? ltbUser.Text : string.Empty;
}
set
{
if (ltbUser != null)
ltbUser.Text = value;
}
}
public string Password
{
get
{
return (ltbPass != null) ? ltbPass.Text : string.Empty;
}
set
{
if (ltbPass != null)
ltbPass.Text = value;
}
}
private LblTextBox ltbUser;
private LblTextBox ltbPass;
private Button btnSubmit;
public LoginCtl()
{
ltbUser = new LblTextBox();
ltbPass = new LblTextBox();
btnSubmit = new Button();
}
protected override void OnInit(EventArgs e)
{
ltbUser.LabelText = "User Name";
ltbPass.LabelText = "Password";
btnSubmit.Text = "Submit";
btnSubmit.CssClass = "Submit";
}
protected override void RenderChildren(HtmlTextWriter writer)
{
writer.AddAttribute(HtmlTextWriterAttribute.Class, "LoginCtlDiv");
writer.RenderBeginTag(HtmlTextWriterTag.Div);
ltbUser.RenderControl(writer);
ltbPass.RenderControl(writer);
btnSubmit.RenderControl(writer);
writer.RenderEndTag();
}
}
The goal was to be able to set properties in the aspx Markup using the control. However, the properties were never initialized.
My error was in the understanding of using CreateChildControls() and RenderChildren(..)
I thought that it was to use one or the other. Instead, I instantiate all the child controls and add them in CreateChildControls().
In order to load the properties, I wait till the OnPreRender() event. The controls will all be loaded and so will the data. Then I make the final changes before the control is rendered to the page.
Another little note, I really wanted to change the default tag that is wrapped around my controls for display purposes (ASP will wrap it with a span by default). So if you want a block level elem this will cause a problem. If you override the TagKey property and set it to an enum elem it will use that instead of the default span tag.
I restructured it as the following:
public class LblTextBox : CompositeControl
{
protected override void OnPreRender(EventArgs e)
{
label.Text = string.Format("{0}:", LabelText);
base.OnPreRender(e);
}
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Div;
}
}
protected override void CreateChildControls()
{
label = new Label();
input = new TextBox();
evalReqField = new RequiredFieldValidator();
label.ID = "lblTextBox";
input.ID = "tbInput";
evalReqField.ID = "evalInput";
evalReqField.ControlToValidate = input.ID;
evalReqField.ErrorMessage = "(Required)";
evalReqField.Display = ValidatorDisplay.Dynamic;
Controls.Add(label);
Controls.Add(input);
Controls.Add(evalReqField);
base.CreateChildControls();
}
public string LabelText { get; set; } //label text
public string Text { get; set; } //text in textbox
TextBox input;
Label label;
RequiredFieldValidator evalReqField;
}
public class LoginCtl : CompositeControl
{
protected override void CreateChildControls()
{
ltbUser = new LblTextBox();
ltbPass = new LblTextBox();
btnSubmit = new Button();
ltbUser.LabelText = "User Name";
ltbPass.LabelText = "Password";
ltbPass.MargBetween = "10px";
btnSubmit.Text = "Submit";
btnSubmit.CssClass = "Submit";
Controls.Add(ltbUser);
Controls.Add(ltbPass);
Controls.Add(btnSubmit);
}
//..
//..
private LblTextBox ltbUser;
private LblTextBox ltbPass;
private Button btnSubmit;
protected override HtmlTextWriterTag TagKey
{
get
{
return HtmlTextWriterTag.Div;
}
}
}
I don't remember why (I'll try to recall), but I had very similar problem few months ago, and my solution was to initialize all of properties except of "ID" in OnLoad event handler:
protected override void OnLoad(EventArgs e)
{
label.Text = string.Format("{0}:", LabelText);
evalReqField.ControlToValidate = input.ID;
evalReqField.ErrorMessage = "(Required)";
evalReqField.Display = ValidatorDisplay.Dynamic;
}
Hope this helps
Related
My problem is, the data which is date entered by user is doesn't after submit button. So I have fields in my registration page and A button to save in my database.
This is what I've tried.
//My Datepicker Design
`
<local:BirthdayDatePickerControl
TextColor="Black"
x:Name="entryField_DateOfBirth"
/>
`
The purpose that I create a custom control in my datepicker is to put an placeholder iny my datepicker field.
//my Birthdaypickercontrol.cs
`
public class BirthdayDatePickerControl : DatePicker
{
public event EventHandler ClearRequested;
// for my placeholder "birthdate"
public static readonly BindableProperty EnterTextProperty = BindableProperty.Create(propertyName: "Placeholder", returnType: typeof(string), declaringType: typeof(BirthdayDatePickerControl), defaultValue: default(string));
public string Placeholder { get; set; }
//function to clear data of my datepicker input
public void clear()
{
if (ClearRequested != null)
{
ClearRequested(this, EventArgs.Empty);
}
}
}
`
In my project.android, I create a birthday renderer.cs
//so this is my code
`
[assembly: ExportRenderer(typeof(BirthdayDatePickerControl), typeof(BirthdayDatePickerRenderer))]
public class BirthdayDatePickerRenderer : DatePickerRenderer
{
public BirthdayDatePickerRenderer(Context context) : base(context)
{
}
EditText editText;
protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.DatePicker> e)
{
base.OnElementChanged(e);
//code for placeholder
if (Control != null)
{
Control.Text = "Birth Date";
}
//end here
//code start here for clearing the data in datepicker input field
editText = Control as EditText;
if (e.NewElement != null)
{
BirthdayDatePickerControl bdaydatePickerControl = e.NewElement as BirthdayDatePickerControl;
bdaydatePickerControl.ClearRequested += DatePickerControl_ClearRequested;
}
//end here
}
public void DatePickerControl_ClearRequested(object sender, EventArgs e)
{
editText.Text = string.Empty;
}
}
`
The codes I pasted will anyway, but..
Assuming in the onload of my registration page, The UI will be like this( pic for reference and ctto to google). After user choose birthdate, example 12/1/22 and hit submit button(all data save in to database). The problem is the placeholder "birthdate" remove/disappear Like this, then if I click the datepicker input field to check the date, the date is still pointing in 12/1/22. What I expected is after performing the ClearData(), the date should be reset in today's date.
//this is my ClearData() function
`
public void ClearData()
{
entryField_DateOfBirth.clear();// this is what I tried and got an bad ouput
}
`
You said:
What I expected is after performing the ClearData(), the date should be reset in today's date.
public void DatePickerControl_ClearRequested(object sender, EventArgs e)
{
editText.Text = string.Empty;
}
Change to this:
public void DatePickerControl_ClearRequested(object sender, EventArgs e)
{
BirthdayDatePickerControl birthdayDate = sender as BirthdayDatePickerControl;
birthdayDate.Date = DateTime.Now;
editText.Text = "Birth Date";
}
I have an observrable collection in my class that contains checkboxes. I implemented a button to check all checkboxes at once. I tried just cycling through all elements and checking the box via binding:
void selectAll_clicked(System.Object sender, System.EventArgs e)
{
var x = sender as Button;
if (!allSelected)
{
allSelected = true;
x.Text = AppResources.DeselectAll;
foreach (var elem in contactList)
elem.isChecked = true;
}
else
{
allSelected = false;
x.Text = AppResources.SelectAll;
foreach (var elem in contactList)
elem.isChecked = false;
}
}
}
I am sure this effects the list, but the UI isnt updated at all.
How can I make sure the observablecollection "updates" visibly?
I also tried adding propertychanged handler:
private void SetList()
{
listview_contacts.ItemsSource = contactList;
contactList.CollectionChanged += items_CollectionChanged;
}
static void items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.OldItems != null)
{
foreach (INotifyPropertyChanged item in e.OldItems)
item.PropertyChanged -= item_PropertyChanged;
}
if (e.NewItems != null)
{
foreach (INotifyPropertyChanged item in e.NewItems)
item.PropertyChanged += item_PropertyChanged;
}
}
static void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
}
BUt this just says that the cast isnt valid...
Thank you
I was able to achieve that by altering my type like so:
public class ContactType : INotifyPropertyChanged
{
private string _name;
private bool _isChecked;
public string name
{
get => _name; set
{
_name = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(name)));
}
}
public string phone { get; set; }
public string initials { get; set; }
public bool isChecked
{
get => _isChecked; set
{
_isChecked = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(isChecked)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
I'm trying to create a factory pattern based on the CompositeControl class.
Everything is working fine. Except as I understand it I have to add the control back onto the placeholder control on my actual page. I've searched around for examples and got one to almost work expect it only worked on the first postback.
I've created a sample here and I'll post all the code here.
Code on my webpage, the most important here is I guess on OnInit where I'm trying to add the control back onto the placeholder, I guess this is what I might be doing wrong.
using SampleControls;
public partial class Test : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
//Setup First Control
Session.Clear();
BaseCompositeControl ltb = new LabelTextBox();
PlaceHolder1.Controls.Add(ltb);
Session.Add("Control", ltb);
}
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
// Check if the post back and recreate the control
if (IsPostBack)
{
int c = this.Form.Controls.Count;
for (int i = 0; i < Session.Count; i++)
{
if (Session[i].ToString().Contains("Control"))
{
this.PlaceHolder1.Controls.Add((BaseCompositeControl)(Session[i]));
}
}
}
}
protected void Button1_Click(object sender, EventArgs e)
{
//Get Postback Date
BaseCompositeControl oltb = (BaseCompositeControl)this.PlaceHolder1.Controls[0];
lblPstBck.Text = oltb.Text;
this.PlaceHolder1.Controls.Clear();
Session.Clear();
//Load next Control
BaseCompositeControl ltb = new LabelCheckBox();
PlaceHolder1.Controls.Add(ltb);
Session.Add("Control", ltb);
}
}
This is composite control classes, I don't know if I have to do something here to handle the viewstate or how?
public abstract class BaseCompositeControl : CompositeControl
{
protected string _Title;
public abstract string Text
{
get;
set;
}
public string Title
{
get { EnsureChildControls();
return _Title; }
set { EnsureChildControls();
_Title = value; }
}
protected override void CreateChildControls()
{
// Clears child controls
Controls.Clear();
// Build the control tree
CreateControlHierarchy();
ClearChildViewState();
}
protected abstract void CreateControlHierarchy();
}
TextBox control
public class LabelCheckBox : BaseCompositeControl
{
protected CheckBox _CheckBox;
public override string Text
{
get
{
EnsureChildControls();
return _CheckBox.Checked.ToString(); ;
}
set
{
EnsureChildControls();
_CheckBox.Checked = Convert.ToBoolean(value);
}
}
protected override void CreateControlHierarchy()
{
_CheckBox = new CheckBox();
Label l = new Label();
// Configure controls
l.Text = "Second Control";
// Connect to the parent
Controls.Add(l);
Controls.Add(_CheckBox);
}
}
Checkbox control
public class LabelTextBox : BaseCompositeControl
{
protected TextBox _Text;
public override string Text
{
get
{
EnsureChildControls();
return _Text.Text;
}
set
{
EnsureChildControls();
_Text.Text = value;
}
}
protected override void CreateControlHierarchy()
{
Label l = new Label();
_Text = new TextBox();
// Configure controls
l.Text = "First Control";
// Connect to the parent
Controls.Add(l);
Controls.Add(_Text);
}
}
I asked this a long time ago,
But I think this is how you should do it. Using a factory pattern for user controls.
http://weblogs.asp.net/sfeldman/archive/2007/12/17/factory-pattern-for-user-controls.aspx
I have a class UserControlBase that inherits System.Web.UI.UserControl and my user controls inherit UserControlBase class. UserControlBase has some common functions that are used in all user controls.
I want to put error display function to UserControlBase as well so that I may not have to declare and manage it in all user controls. Error will be displayed in some label in usercontrol. Issue is how to access label which is in usercontrol in UserControlBase in function ? I don't want to pass label as argument.
In your UserControl Base, expose the text value of the label only:
public abstract class UserControlBase : System.Web.UI.UserControl
{
private Label ErrorLabel { get; set; }
protected string ErrorMessage
{
get { return ErrorLabel.Text; }
set { ErrorLabel.Text = value; }
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
ErrorLabel = new Label();
Controls.Add(ErrorLabel);
}
//... Other functions
}
In your user controls that inherit this:
public partial class WebUserControl1 : UserControlBase
{
protected void Page_Load(object sender, EventArgs e)
{
try
{
}
catch (Exception)
{
ErrorMessage = "Error"; //Or whatever
}
}
}
I've got several Gridviews in my application in which I use a custom PagerTemplate. I'd like to turn this custom template into a UserControl so that I don't need to replicate the same logic in multiple pages. I'm pretty sure that such a thing is possible, but I'm unsure of how exactly to wire the UserControl to the Gridview's events, and what interfaces my control may need to implement.
I'm using ASP 2.0 frameworks.
Has anyone done something like this? And if so, do you have any sample code for your usercontrol?
Dave Anderson, a co-worker of mine, wrote this server control that could help you get started. Note that we're targeting .NET 3.5.
[AspNetHostingPermission(
SecurityAction.Demand,
Level = AspNetHostingPermissionLevel.Minimal),
AspNetHostingPermission(SecurityAction.InheritanceDemand,
Level = AspNetHostingPermissionLevel.Minimal),
DefaultProperty("Text"),
ToolboxData("<{0}:Pager runat=\"server\"> </{0}:Pager>"),
Designer(typeof(ServerControls.Design.PagerDesigner))
]
public class Pager : WebControl, INamingContainer
{
#region Private Constants
private const string Command_First = "First";
private const string Command_Prev = "Prev";
private const string Command_Next = "Next";
private const string Command_Last = "Last";
#endregion
#region Private members
private Control PageableNamingContainer;
private PropertyInfo PageCountInfo;
private PropertyInfo PageIndexInfo;
private DropDownList ddlCurrentPage;
private Label lblPageCount;
private Button btnFirst;
private Button btnPrevious;
private Button btnNext;
private Button btnLast;
#endregion
#region Private Properties
private int PageCount
{
get
{
int Result;
if (InsideDataPager)
Result = (int)Math.Ceiling((decimal)(TotalRowCount / PageSize)) + 1;
else
Result = (int)PageCountInfo.GetValue(PageableNamingContainer, null);
return Result;
}
}
private int PageIndex
{
get
{
int Result;
if (InsideDataPager)
Result = (int)Math.Floor((decimal)(StartRowIndex / PageSize));
else
Result = (int)PageIndexInfo.GetValue(PageableNamingContainer, null);
return Result;
}
}
private int StartRowIndex
{
get
{
if (InsideDataPager)
return MyDataPager.StartRowIndex;
else
throw new Exception("DataPager functionality requires DataPager.");
}
}
private int TotalRowCount
{
get
{
if (InsideDataPager)
return MyDataPager.TotalRowCount;
else
throw new Exception("DataPager functionality requires DataPager.");
}
}
private int PageSize
{
get
{
if (InsideDataPager)
return MyDataPager.PageSize;
else
throw new Exception("DataPager functionality requires DataPager.");
}
}
private bool InsideDataPager
{
get { return ViewState["InsideDataPager"] == null ? false : (bool)ViewState["InsideDataPager"]; }
set { ViewState["InsideDataPager"] = value; }
}
#region DataPager-Specific properties
private DataPager MyDataPager
{
get
{
if (InsideDataPager)
return (DataPager)PageableNamingContainer;
else
throw new Exception("DataPager functionality requires DataPager.");
}
}
private int PrevPageStartIndex
{
get { return StartRowIndex >= PageSize ? StartRowIndex - PageSize : 0; }
}
private int NextPageStartIndex
{
get { return StartRowIndex + PageSize >= TotalRowCount ? LastPageStartIndex : StartRowIndex + PageSize; }
}
private int LastPageStartIndex
{
get { return (PageCount-1) * PageSize; }
}
#endregion
#endregion
#region Public Properties
[
Category("Behavior"),
DefaultValue(""),
Description("The stylesheet class to use for the buttons")
]
public bool HideInactiveButtons { get; set; }
[
Category("Behavior"),
DefaultValue("true"),
Description("Indicates whether the controls will invoke validation routines")
]
public bool CausesValidation { get; set; }
[
Category("Appearance"),
DefaultValue(""),
Description("The stylesheet class to use for the buttons")
]
public string ButtonCssClass { get; set; }
[
Category("Appearance"),
DefaultValue("<<"),
Description("The text to be shown on the button that navigates to the First page")
]
public string FirstText { get; set; }
[
Category("Appearance"),
DefaultValue("<"),
Description("The text to be shown on the button that navigates to the Previous page")
]
public string PreviousText { get; set; }
[
Category("Appearance"),
DefaultValue(">"),
Description("The text to be shown on the button that navigates to the Next page")
]
public string NextText { get; set; }
[
Category("Appearance"),
DefaultValue(">>"),
Description("The text to be shown on the button that navigates to the Last page")
]
public string LastText { get; set; }
#endregion
#region Overridden properties
public override ControlCollection Controls
{
get
{
EnsureChildControls();
return base.Controls;
}
}
#endregion
#region Overridden methods/events
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (!GetPageInfo(NamingContainer))
throw new Exception("Unable to locate the Pageable Container.");
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if (PageableNamingContainer != null)
{
EnsureChildControls();
ddlCurrentPage.Items.Clear();
for (int i = 0; i < PageCount; i++)
ddlCurrentPage.Items.Add(new ListItem((i + 1).ToString(), (i + 1).ToString()));
lblPageCount.Text = PageCount.ToString();
if (HideInactiveButtons)
{
btnFirst.Visible = btnPrevious.Visible = (PageIndex > 0);
btnLast.Visible = btnNext.Visible = (PageIndex < (PageCount - 1));
}
else
{
btnFirst.Enabled = btnPrevious.Enabled = (PageIndex > 0);
btnLast.Enabled = btnNext.Enabled = (PageIndex < (PageCount - 1));
}
ddlCurrentPage.SelectedIndex = PageIndex;
}
else
ddlCurrentPage.SelectedIndex = 0;
}
protected override bool OnBubbleEvent(object source, EventArgs args)
{
// We handle all our events inside this class when
// we are inside a DataPager
return InsideDataPager;
}
#endregion
#region Event delegate
protected void PagerEvent(object sender, EventArgs e)
{
if (InsideDataPager)
{
int NewStartingIndex;
if (sender.GetType() == typeof(Button))
{
string arg = ((Button)sender).CommandArgument.ToString();
switch (arg)
{
case Command_Prev:
NewStartingIndex = PrevPageStartIndex;
break;
case Command_Next:
NewStartingIndex = NextPageStartIndex;
break;
case Command_Last:
NewStartingIndex = LastPageStartIndex;
break;
case Command_First:
default:
NewStartingIndex = 0;
break;
}
}
else
{
NewStartingIndex = Math.Min(((DropDownList)sender).SelectedIndex * PageSize, LastPageStartIndex);
}
MyDataPager.SetPageProperties(NewStartingIndex, MyDataPager.MaximumRows, true);
}
else
{
CommandEventArgs ea = new CommandEventArgs("Page", ((DropDownList)sender).SelectedValue);
RaiseBubbleEvent(this, ea);
}
}
#endregion
#region GetPageableContainer
private bool GetPageInfo(Control namingContainer)
{
if (namingContainer == null || namingContainer.GetType() == typeof(Page))
throw new Exception(this.GetType().ToString() + " must be used in a pageable container like a GridView.");
/*
* NOTE: If we are inside a DataPager, this will be
* our first-level NamingContainer, so there
* will never be any reflection in that case.
*/
if (namingContainer.GetType() == typeof(DataPagerFieldItem))
{
InsideDataPager = true;
PageableNamingContainer = ((DataPagerFieldItem)namingContainer).Pager;
return true;
}
PageCountInfo = namingContainer.GetType().GetProperty("PageCount");
PageIndexInfo = namingContainer.GetType().GetProperty("PageIndex");
if (PageCountInfo == null || PageIndexInfo == null)
return GetPageInfo(namingContainer.NamingContainer);
else
{
PageableNamingContainer = namingContainer;
return true;
}
}
#endregion
#region Control generation
protected override void CreateChildControls()
{
Controls.Clear();
Controls.Add(BuildControlTable());
}
private Table BuildControlTable()
{
Table ControlTable = new Table();
ControlTable.CssClass = CssClass;
TableRow tr = new TableRow();
TableCell td = new TableCell();
td.Text = "Page";
tr.Cells.Add(td);
td = new TableCell();
ddlCurrentPage = new DropDownList();
ddlCurrentPage.ID = "ddlCurrentPage";
ddlCurrentPage.AutoPostBack = true;
ddlCurrentPage.SelectedIndexChanged += PagerEvent;
ddlCurrentPage.CausesValidation = CausesValidation;
td.Controls.Add(ddlCurrentPage);
tr.Cells.Add(td);
td = new TableCell();
td.Text = "of";
tr.Cells.Add(td);
td = new TableCell();
lblPageCount = new Label();
td.Controls.Add(lblPageCount);
tr.Cells.Add(td);
AddButton(tr, ref btnFirst, string.IsNullOrEmpty(FirstText) ? "<<" : FirstText, Command_First);
AddButton(tr, ref btnPrevious, string.IsNullOrEmpty(PreviousText) ? "<" : PreviousText, Command_Prev);
AddButton(tr, ref btnNext, string.IsNullOrEmpty(NextText) ? ">" : NextText, Command_Next);
AddButton(tr, ref btnLast, string.IsNullOrEmpty(LastText) ? ">>" : LastText, Command_Last);
ControlTable.Rows.Add(tr);
return ControlTable;
}
private void AddButton(TableRow row, ref Button button, string text, string argument)
{
button = new Button();
button.Text = text;
button.CssClass = ButtonCssClass;
button.CommandName = "Page";
button.CommandArgument = argument;
button.CausesValidation = CausesValidation;
if (InsideDataPager)
button.Click += PagerEvent;
TableCell td = new TableCell();
td.Controls.Add(button);
row.Cells.Add(td);
}
#endregion
}