Server control Guildance

  • Thread starter Thread starter SAL
  • Start date Start date
S

SAL

Hi,
I hope this is the place to post this.
I would like to develop a server control that is composed of a
RadioButtonList control, limits its ListItemCollection to three items and
allow the user to specify the text for the three items. I want to be able to
data bind it to a bit field and use the control as a tri-state bit control
to display the three possible states of a bit field in SQL Server, On, Off,
NULL.

Are there any examples available of how to go about this? Am I making too
much work of a simple task?
During DataBinding, can I examine the value of the field that the control is
bound to so that I can set the SelectedIndex property?

Any help would be greatly appreciated. I have googled this but haven't found
anything that shows me how to do this, what events/properties/methods I
have/need to override, And, whether I should implement it as a class or a
user control...

Thanks
S
 
Hello,

1. You can create a Custom Control deriving from RadioButtonList class.Then
you can set Text or Value for each list item like RadioButtonList does.
2. You can get the list items which is bound and check if the list items
count is equal to 3 in OnLoad phase. If not, you can throw some error.

protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
}

3. You can also set the default SelectedIndex, even redefine the value of
each item in onLoad phase.

Check the following link to get more information to create a Custom Control
in ASP.Net:
http://msdn.microsoft.com/en-us/library/zt27tfhy.aspx

Sincerely,

Vince Xu

Microsoft Online Support


==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

MSDN Managed Newsgroup support offering is for non-urgent issues where an
initial response from the community or a Microsoft Support Engineer within
2 business day is acceptable. Please note that each follow up response may
take approximately 2 business days as the support professional working with
you may need further investigation to reach the most efficient resolution.
The offering is not appropriate for situations that require urgent,
real-time or phone-based interactions. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
==================================================
 
Thanks Vince,
I'm having a bit of trouble with this still. I've been trying to follow the
advice in the link you included.

Basically I want the number of items in the list to be static, three items
in the list.
I want to user to be able to set the text for each item.
I want the SelectedIndex to be the bound field and I want to choose the
SelectedIndex based on the value of the bound field. The bound field should
be a bit field in SQL Server. If the bit is on, select index (0), if the bit
is off, select index (1), if the field is null, select index(2).

I am also having trouble debugging the code in design mode. Is there a way
to do that?

Thanks again,
S
 
Hello,

The datasource of this server control is static in this scenario I think.
Static values and static item count.
So just let user define the Text of RadioButtonList that we can add these
three items programically. The following code is setting the property
TextForOn,TextForOff,TextForNull that will be as three Text for the value
on,off and null. In onLoad, the control will create three items according
to these three items the user typed.

When you bind the data on this control, you can define the SelectedValue to
let it check the related item. For example, the control is in GridView.
Just bind the SelectedValue on bit field. SelectedValue will check the
value bound.

<asp:TemplateField>
<ItemTemplate>
<custom:myRadioButton ID="radio1" runat="server"
SelectedValue='<%# Eval("bitf")%>'
TextForOn="ontext" TextForOff="offtext"
TextForNull="nulltext"></custom:myRadioButton>
</ItemTemplate>
</asp:TemplateField>



public class myRadioButton : RadioButtonList
{
public myRadioButton()
{

}
private List<string> _valueList=new List<string> {
"on","off","null"};

[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForOn
{
get { return (string)(ViewState["TextForOn"] ?? string.Empty); }
set { ViewState["TextForOn"] = value; }
}
[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForOff
{
get { return (string)(ViewState["TextForOff"] ?? string.Empty);
}
set { ViewState["TextForOff"] = value; }
}

[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForNull
{
get { return (string)(ViewState["TextForNull"] ??
string.Empty); }
set { ViewState["TextForNull"] = value; }
}


[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public override string SelectedValue
{
get
{
return base.SelectedValue;
}
set
{
if (string.IsNullOrEmpty(value))
base.SelectedValue = _valueList[2];
else
if (value.ToString().Substring(0, 1).ToLower() == "t")
base.SelectedValue = _valueList[0];
else if (value.ToString().Substring(0, 1).ToLower() ==
"f")
base.SelectedValue = _valueList[1];
else
throw new Exception("SelectedValue bound is
invide.");
}
}


protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.Items.Clear();
this.Items.Add(new ListItem(TextForOn, _valueList[0]));
this.Items.Add(new ListItem(TextForOff, _valueList[1]));
this.Items.Add(new ListItem(TextForNull, _valueList[2]));

}
}

Sincerely,

Vince Xu

Microsoft Online Support
 
Vince, that works. Thank you.

However, when I set the NullText or any of the other two text properties, it
doesn't immediately display on the control. It does display after I set the
field that the SelectedValue property is bound to however.
Is there a way to make it display this immediately?

S

Vince Xu said:
Hello,

The datasource of this server control is static in this scenario I think.
Static values and static item count.
So just let user define the Text of RadioButtonList that we can add these
three items programically. The following code is setting the property
TextForOn,TextForOff,TextForNull that will be as three Text for the value
on,off and null. In onLoad, the control will create three items according
to these three items the user typed.

When you bind the data on this control, you can define the SelectedValue
to
let it check the related item. For example, the control is in GridView.
Just bind the SelectedValue on bit field. SelectedValue will check the
value bound.

<asp:TemplateField>
<ItemTemplate>
<custom:myRadioButton ID="radio1" runat="server"
SelectedValue='<%# Eval("bitf")%>'
TextForOn="ontext" TextForOff="offtext"
TextForNull="nulltext"></custom:myRadioButton>
</ItemTemplate>
</asp:TemplateField>



public class myRadioButton : RadioButtonList
{
public myRadioButton()
{

}
private List<string> _valueList=new List<string> {
"on","off","null"};

[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForOn
{
get { return (string)(ViewState["TextForOn"] ??
string.Empty); }
set { ViewState["TextForOn"] = value; }
}
[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForOff
{
get { return (string)(ViewState["TextForOff"] ?? string.Empty);
}
set { ViewState["TextForOff"] = value; }
}

[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForNull
{
get { return (string)(ViewState["TextForNull"] ??
string.Empty); }
set { ViewState["TextForNull"] = value; }
}


[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public override string SelectedValue
{
get
{
return base.SelectedValue;
}
set
{
if (string.IsNullOrEmpty(value))
base.SelectedValue = _valueList[2];
else
if (value.ToString().Substring(0, 1).ToLower() == "t")
base.SelectedValue = _valueList[0];
else if (value.ToString().Substring(0, 1).ToLower() ==
"f")
base.SelectedValue = _valueList[1];
else
throw new Exception("SelectedValue bound is
invide.");
}
}


protected override void OnInit(EventArgs e)
{
base.OnInit(e);
this.Items.Clear();
this.Items.Add(new ListItem(TextForOn, _valueList[0]));
this.Items.Add(new ListItem(TextForOff, _valueList[1]));
this.Items.Add(new ListItem(TextForNull, _valueList[2]));

}
}

Sincerely,

Vince Xu

Microsoft Online Support
 
Hello,

Do you mean you can't set the TextForXXX properties on code behind? When
you set TextForXXX properties in page load, it will keep the default text
for it. Is that what you encountered?

I think I should modify some codes in my previous codes.
1. Build CreateChildControls method instead of OnInit method.
2. Use EnsureChildControls in SelectedValue property setting.

[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public override string SelectedValue
{
get
{
EnsureChildControls();
return base.SelectedValue;
}
set
{
EnsureChildControls();
if (string.IsNullOrEmpty(value))
base.SelectedValue = _valueList[2];
else
if (value.ToString().Substring(0, 1).ToLower() == "t")
base.SelectedValue = _valueList[0];
else if (value.ToString().Substring(0, 1).ToLower() ==
"f")
base.SelectedValue = _valueList[1];
else
throw new Exception("SelectedValue bound is
invide.");
}
}


protected override void CreateChildControls()
{

this.Items.Clear();
this.Items.Add(new ListItem(TextForOn, _valueList[0]));
this.Items.Add(new ListItem(TextForOff, _valueList[1]));
this.Items.Add(new ListItem(TextForNull, _valueList[2]));
base.CreateChildControls();
}

Please use the above codes instead of the related codes in previous code I
posted.


Sincerely,

Vince Xu

Microsoft Online Support
 
Vince, thank you for your response.
Yes, that's what I mean, the text for the three text properties doesn't
change when I set them in design mode. I can set the text in design mode but
the text I set doesn't show up until the page is run or displayed.

I made the changes you suggested and here's what happens.

I drop the control into a gridview templated field. The controls displays
with one radiobutton. When I set one of the TextForXXX properties, then all
three radiobuttons display with the default text showing but not the text
that I set via the property browser.

Questions:
Why do not all three radiobuttons display when I drop the control into the
gridview's templated field?
Why does the page have to run before the text that is set via the properties
browser show up?

Thanks again for your help.

S
 
Hello,
Why do not all three radiobuttons display when I drop the control into the
gridview's templated field?

Based on my understanding, if you don't set any TextForXXX property, it
just show only one RadioButton in GridView. Right?
I tried in my site, if I don't set any Text, it will get empty as Text for
each radiobutton. That will present only three alone radiobutton without
any text beside it. I think you used some css style and block the other two
radiobutton.
To resolve it, we can set the default value for three TextForXXX property.
So it will never get empty Text on the control.

[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForOn
{
get { return (string)(ViewState["TextForOn"] ?? "On"); }
set { ViewState["TextForOn"] = value; }
}
[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForOff
{
get { return (string)(ViewState["TextForOff"] ?? "Off"); }
set { ViewState["TextForOff"] = value; }
}

[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForNull
{
get { return (string)(ViewState["TextForNull"] ?? "Null"); }
set { ViewState["TextForNull"] = value; }
}
Why does the page have to run before the text that is set via the
properties
browser show up?

Property TextForXXX is allowing you set the default value for it.(I think
you had better say it as DefaultTextForXXX) In databound event, items have
been created, so you can't modify it directly by TextForXXX unless you loop
the items and set the text for each item.

If you want to modify TextForXXX at anytime, you can build onPreRender
phase to rebind the Text to update it.

protected override void OnPreRender(EventArgs e)
{
this.Items[0].Text = TextForOn;
this.Items[1].Text = TextForOff;
this.Items[2].Text = TextForNull;
base.OnPreRender(e);

}

So the entire codes about it is as below:
public class myRadioButton : RadioButtonList
{
public myRadioButton()
{

}
private List<string> _valueList=new List<string> {
"on","off","null"};

[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForOn
{
get { return (string)(ViewState["TextForOn"] ?? "On"); }
set { ViewState["TextForOn"] = value; }
}
[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForOff
{
get { return (string)(ViewState["TextForOff"] ?? "Off"); }
set { ViewState["TextForOff"] = value; }
}

[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForNull
{
get { return (string)(ViewState["TextForNull"] ?? "Null"); }
set { ViewState["TextForNull"] = value; }
}


[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public override string SelectedValue
{
get
{
EnsureChildControls();
return base.SelectedValue;
}
set
{
EnsureChildControls();
if (string.IsNullOrEmpty(value))
base.SelectedValue = _valueList[2];
else
if (value.ToString().Substring(0, 1).ToLower() == "t")
base.SelectedValue = _valueList[0];
else if (value.ToString().Substring(0, 1).ToLower() ==
"f")
base.SelectedValue = _valueList[1];
else
throw new Exception("SelectedValue bound is
invide.");
}
}


protected override void CreateChildControls() //
OnDataBinding(EventArgs e) you can use DataBinding instead.
{

this.Items.Clear();
this.Items.Add(new ListItem(TextForOn, _valueList[0]));
this.Items.Add(new ListItem(TextForOff, _valueList[1]));
this.Items.Add(new ListItem(TextForNull, _valueList[2]));
base.CreateChildControls();//base.OnDataBinding(e);
}

protected override void OnPreRender(EventArgs e)//that will refresh
the text before render
{
this.Items[0].Text = TextForOn;
this.Items[1].Text = TextForOff;
this.Items[2].Text = TextForNull;
base.OnPreRender(e);

}
}

Hope it can help you.

Sincerely,

Vince Xu

Microsoft Online Support
 
Hello Vince,
thank you for your response. I think I've included all of your suggestions.
However, when I drop the control on a form, there is still only one radio
button that displays. Here is my code:
Let me know if I've missed something.

#Region "Private variables"
Private mTextList As String() = {"True", "False", "Null"}
#End Region

#Region "Constants"
Protected Const TRUE_TXT As String = "True"
Protected Const FALSE_TXT As String = "False"
Protected Const NULL_TXT As String = "NULL"
#End Region



Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
MyBase.OnLoad(e)
Me.RepeatDirection = WebControls.RepeatDirection.Horizontal
End Sub

Protected Overrides Sub OnPreRender(ByVal e As System.EventArgs)
MyBase.Items(0).Text = TrueText
MyBase.Items(1).Text = FalseText
MyBase.Items(2).Text = NULLText
MyBase.OnPreRender(e)
End Sub

Protected Sub Initialize()
MyBase.Items.Clear()
MyBase.Items.Add(New ListItem(TrueText, mTextList(0)))
MyBase.Items.Add(New ListItem(FalseText, mTextList(1)))
MyBase.Items.Add(New ListItem(NULLText, mTextList(2)))
End Sub

Protected Overrides Sub CreateChildControls()
Initialize()
MyBase.CreateChildControls()
End Sub

#Region "Properties"
Public Overrides Property RepeatDirection() As
System.Web.UI.WebControls.RepeatDirection
Get
Return WebControls.RepeatDirection.Horizontal
End Get
Set(ByVal value As System.Web.UI.WebControls.RepeatDirection)
MyBase.RepeatDirection = WebControls.RepeatDirection.Horizontal
End Set
End Property

<Browsable(True), DefaultValue(""), Category("Appearance"),
Description("")> _
Public Property TrueText() As String
Get
Return IIf((Not ViewState("TrueText") Is Nothing),
ViewState("TrueText"), mTextList(0))
End Get
Set(ByVal value As String)
ViewState("TrueText") = value
End Set
End Property

<Browsable(True), DefaultValue(""), Category("Appearance"),
Description("")> _
Public Property FalseText() As String
Get
Return IIf((Not ViewState("FalseText") Is Nothing),
ViewState("FalseText"), mTextList(1))
End Get
Set(ByVal value As String)
ViewState("FalseText") = value
End Set
End Property

<Browsable(True), DefaultValue(""), Category("Appearance"),
Description("")> _
Public Property NULLText() As String
Get
Return IIf((Not ViewState("NULLText") Is Nothing),
ViewState("NULLText"), mTextList(2))
End Get
Set(ByVal value As String)
ViewState("NULLText") = value
End Set
End Property

<Browsable(True), DefaultValue(""), Category("Appearance"),
Description("")> _
Public Overrides Property SelectedValue() As String
Get
EnsureChildControls()
Return MyBase.SelectedValue
End Get
Set(ByVal value As String)
EnsureChildControls()
If String.IsNullOrEmpty(value) Then
MyBase.SelectedValue = mTextList(2)
Else
If value.Substring(0, 1).ToLower() = "t" Then
MyBase.SelectedValue = Boolean.Parse(mTextList(0))
ElseIf value.Substring(0, 1).ToLower() = "f" Then
MyBase.SelectedValue = Boolean.Parse(mTextList(1))
Else
Throw New ArgumentException("Value: " & value & " is invalid
for SelectedValue")
End If
End If
End Set
End Property
#End Region




Vince Xu said:
Hello,
Why do not all three radiobuttons display when I drop the control into the
gridview's templated field?

Based on my understanding, if you don't set any TextForXXX property, it
just show only one RadioButton in GridView. Right?
I tried in my site, if I don't set any Text, it will get empty as Text for
each radiobutton. That will present only three alone radiobutton without
any text beside it. I think you used some css style and block the other
two
radiobutton.
To resolve it, we can set the default value for three TextForXXX property.
So it will never get empty Text on the control.

[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForOn
{
get { return (string)(ViewState["TextForOn"] ?? "On"); }
set { ViewState["TextForOn"] = value; }
}
[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForOff
{
get { return (string)(ViewState["TextForOff"] ?? "Off"); }
set { ViewState["TextForOff"] = value; }
}

[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForNull
{
get { return (string)(ViewState["TextForNull"] ?? "Null"); }
set { ViewState["TextForNull"] = value; }
}
Why does the page have to run before the text that is set via the
properties
browser show up?

Property TextForXXX is allowing you set the default value for it.(I think
you had better say it as DefaultTextForXXX) In databound event, items have
been created, so you can't modify it directly by TextForXXX unless you
loop
the items and set the text for each item.

If you want to modify TextForXXX at anytime, you can build onPreRender
phase to rebind the Text to update it.

protected override void OnPreRender(EventArgs e)
{
this.Items[0].Text = TextForOn;
this.Items[1].Text = TextForOff;
this.Items[2].Text = TextForNull;
base.OnPreRender(e);

}

So the entire codes about it is as below:
public class myRadioButton : RadioButtonList
{
public myRadioButton()
{

}
private List<string> _valueList=new List<string> {
"on","off","null"};

[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForOn
{
get { return (string)(ViewState["TextForOn"] ?? "On"); }
set { ViewState["TextForOn"] = value; }
}
[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForOff
{
get { return (string)(ViewState["TextForOff"] ?? "Off"); }
set { ViewState["TextForOff"] = value; }
}

[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public string TextForNull
{
get { return (string)(ViewState["TextForNull"] ?? "Null"); }
set { ViewState["TextForNull"] = value; }
}


[Browsable(true)]
[DefaultValue("")]
[Category("Appearance")]
[Description("")]
public override string SelectedValue
{
get
{
EnsureChildControls();
return base.SelectedValue;
}
set
{
EnsureChildControls();
if (string.IsNullOrEmpty(value))
base.SelectedValue = _valueList[2];
else
if (value.ToString().Substring(0, 1).ToLower() == "t")
base.SelectedValue = _valueList[0];
else if (value.ToString().Substring(0, 1).ToLower() ==
"f")
base.SelectedValue = _valueList[1];
else
throw new Exception("SelectedValue bound is
invide.");
}
}


protected override void CreateChildControls() //
OnDataBinding(EventArgs e) you can use DataBinding instead.
{

this.Items.Clear();
this.Items.Add(new ListItem(TextForOn, _valueList[0]));
this.Items.Add(new ListItem(TextForOff, _valueList[1]));
this.Items.Add(new ListItem(TextForNull, _valueList[2]));
base.CreateChildControls();//base.OnDataBinding(e);
}

protected override void OnPreRender(EventArgs e)//that will refresh
the text before render
{
this.Items[0].Text = TextForOn;
this.Items[1].Text = TextForOff;
this.Items[2].Text = TextForNull;
base.OnPreRender(e);

}
}

Hope it can help you.

Sincerely,

Vince Xu

Microsoft Online Support
 
Hello,

I tried your code and it's worked for me.
I suggest you check the source code in browser, if you can see all three
elements about radiobutton(although you can't see them all in page), it
means they all has been generated and presented in the page, but maybe some
css style you used in aspx page causes it blocks the other two radiobutton.
Maybe you put it into a div which hasn't enough width to show them all.
I suggest you send me a demo about it(contains aspx page and css style you
applied, that's important) so that I can reproduct in my site.
 
Back
Top