I have a Repeater control with a Rating control (from the latest AJAX Control Toolkit) inside:
<asp:Repeater ID="repStudents" runat="server" onitemcommand="repStudents_ItemCommand">
<ItemTemplate>
<%# Eval("FirstName") %>
<asp:Rating ID="warnings" runat="server" Direction="NotSet" MaxRating="3" StarCssClass="star" EmptyStarCssClass="em" FilledStarCssClass="gr" WaitingStarCssClass="gr" AutoPostBack="True" CommandArgument='<%# Eval("Id") %>' CommandName="warn"></asp:Rating>
<br />
</ItemTemplate>
</asp:Repeater>
In the code behind, I have:
protected void repStudents_ItemCommand(object source, System.Web.UI.WebControls.RepeaterCommandEventArgs e)
{
//Custom log function
Log.Append(e.CommandName + " " + e.CommandArgument);
}
All renders fine. However, when I click on a rating the page posts back but repStudents_ItemCommand is not fired. How can I fix this?
Note that if I put a Button in the same Repeater, repStudents_ItemCommand fires correctly when I click the button.
The Rating control does not support CommandName/CommandArgument properties. But you can extend it as follows:
public class ExRating : Rating {
[Category("Behavior")]
public string CommandName {
get { return (string)ViewState["CommandName"] ?? string.Empty; }
set { ViewState["CommandName"] = value; }
}
[Category("Behavior")]
public string CommandArgument {
get { return (string)ViewState["CommandArgument"] ?? string.Empty; }
set { ViewState["CommandArgument"] = value; }
}
protected override void OnChanged(RatingEventArgs e) {
base.OnChanged(e);
RaiseBubbleEvent(this, new CommandEventArgs(CommandName, CommandArgument));
}
}
Then replace the old control with new one:
<pages>
<tagMapping>
<add tagType="AjaxControlToolkit.Rating, AjaxControlToolkit" mappedTagType="Sample.ExRating, Sample"/>
</tagMapping>
</pages>
Related
How Can I Add One Event to Each item On A CheckBoxList, pr example I Wanto to add One Click Event to check What Item Has been checked.
thanks in advance.
Each item in CheckBoxList is of type System.Web.UI.WebControls.ListItem and has no events defined.
That's a bit tricky with the CheckBoxList. Don't think there's a straight way to add an click-event to each item, since the ListItem-class doesn't have any events.
You could set AutoPostBack="true" on the CheckBoxList and check on page load which items are selected, but you wouldn't know easy which was the last one clicked.
Other solution is to get rid of the CheckBoxList and create just CheckBoxes and set the click-event on those to the same event-method. And there you could check the sender.
ASPX:
<asp:CheckBox ID="CheckBox1" Text="A" OnCheckedChanged="CheckBox_Clicked" AutoPostBack="true" runat="server" />
<asp:CheckBox ID="CheckBox2" Text="B" OnCheckedChanged="CheckBox_Clicked" AutoPostBack="true" runat="server" />
<asp:CheckBox ID="CheckBox3" Text="C" OnCheckedChanged="CheckBox_Clicked" AutoPostBack="true" runat="server" />
Code behind:
void CheckBox_CheckedChanged(object sender, EventArgs e)
{
Console.WriteLine(((CheckBox)sender).Text);
}
Or you could make your own custom CheckBoxList that handles click-events on items.
OK. So I found this question/answer and it didn't help me out. While the provided answer is correct, there is an easy way to build a CheckBoxList-like control witha Repeater control.
Turns out that you can use a Repeater with an ItemTemplate with a CheckBox.
I have a complete explanation here: http://www.rhyous.com/2014/10/17/aspx-checkboxlist-alternative-that-allows-for-the-oncheckedchanged-event/
I also copied the needed data here in this answer:
Default.aspx
<%# Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CheckBoxListExample._Default" %>
<%# Import Namespace="CheckBoxListExample" %>
<%# Import Namespace="CheckBoxListExample.Models" %>
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
<div>
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<asp:CheckBox ID="cb1" runat="server" AutoPostBack="true" OnCheckedChanged="RepeaterCheckBoxChanged"
Text="<%# ((CheckBoxViewModel)Container.DataItem).Name %>"
Checked="<%# ((CheckBoxViewModel)Container.DataItem).IsChecked %>" />
</ItemTemplate>
</asp:Repeater>
</div>
</asp:Content>
Default.aspx.cs
using System;
using System.Collections.Generic;
using System.Web.UI;
using System.Web.UI.WebControls;
using CheckBoxListExample.Models;
namespace CheckBoxListExample
{
public partial class _Default : Page
{
private List<CheckBoxViewModel> _ViewModels;
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
var _ViewModels = new List<CheckBoxViewModel>
{
new CheckBoxViewModel {Name = "Test1", IsChecked = true},
new CheckBoxViewModel {Name = "Test2"},
new CheckBoxViewModel {Name = "Test3"}
};
Repeater1.DataSource = _ViewModels;
Repeater1.DataBind();
}
}
protected void RepeaterCheckBoxChanged(object sender, EventArgs e)
{
var cb = sender as CheckBox;
if (cb == null) return;
if (cb.Checked)
{
// Insert
}
else
{
// Delete
}
}
}
}
CheckBoxViewModel
namespace CheckBoxListExample.Models
{
public class CheckBoxViewModel
{
public string Name { get; set; }
public bool IsChecked { get; set; }
}
}
What I am trying to achieve that if a user control already added to placeholder then it will be removed otherwise will be added to it and it will be done in a LinkButton's onclick.
The code:
public partial class SiteSettings : System.Web.UI.Page {
private UserSettings UserSettingsControl;
protected void Page_Load(object sender, EventArgs e) {
System.Diagnostics.Debug.WriteLine("Pageload");
UserSettingsControl = LoadControl("~/UserControls/UserSettings.ascx") as UserSettings;
}
protected void UserLink_Click(object sender, EventArgs e) {
if (SettingsPlaceholder.Controls.Contains(UserSettingsControl)) {
System.Diagnostics.Debug.WriteLine("Contains");
SettingsPlaceholder.Controls.Remove(UserSettingsControl);
} else {
System.Diagnostics.Debug.WriteLine("Does not Contains");
SettingsPlaceholder.Controls.Add(UserSettingsControl);
}
}
}
Now it is not working. And I am getting:
Pageload // on first time load
Pageload // on first time click
Does not Contains // on first time click
Pageload // on second time click
Does not Contains // on second time click
in the Output window.
How can I achieve this? I also tried to store it into ViewState, but since UserControl is not serializable so that didn't worked.
The aspx page is:
<telerik:RadAjaxManager ID="AjaxManager" runat="server">
<AjaxSettings>
<telerik:AjaxSetting AjaxControlID="UserLink">
<UpdatedControls>
<telerik:AjaxUpdatedControl ControlID="SettingsPanel" LoadingPanelID="LoadingPanel" UpdatePanelRenderMode="Block" />
<telerik:AjaxUpdatedControl ControlID="PlaceHolderPanel" />
</UpdatedControls>
</telerik:AjaxSetting>
</AjaxSettings>
<ClientEvents OnResponseEnd="respondEnd" />
</telerik:RadAjaxManager>
<asp:Panel ID="SettingsPanel" runat="server">
<telerik:RadSplitter ID="MainSplitter" runat="server" MinHeight="200" Width="100%"
OnClientLoaded="splitterLoaded" OnClientResized="splitterLoaded">
<telerik:RadPane ID="LeftPane" runat="server" MaxWidth="250" Width="150" MinWidth="150" CssClass="left-rounded-corner settings-splitter-left">
<asp:Panel runat="server">
<asp:LinkButton ID="UserLink" runat="server" onclick="UserLink_Click" Text="User Settings" />
</asp:Panel>
</telerik:RadPane>
<telerik:RadSplitBar ID="Splitbar" runat="server" CollapseMode="Forward" />
<telerik:RadPane ID="RightPane" runat="server" CssClass="right-rounded-corner settings-splitter-right">
<asp:Panel ID="PlaceHolderPanel" runat="server" Height="100%">
<asp:PlaceHolder runat="server" ID="SettingsPlaceholder" />
</asp:Panel>
</telerik:RadPane>
</telerik:RadSplitter>
</asp:Panel>
<telerik:RadAjaxLoadingPanel ID="LoadingPanel" runat="server" />
Edit:
Modified code:
public partial class SiteSettings : System.Web.UI.Page {
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
AddUserSettings();
}
}
public UserControl UserSettingsControl {
get {
if (ViewState["UserSettings"] == null) {
ViewState["UserSettings"] = LoadControl("~/UserControls/UserSettings.ascx") as UserSettings;
}
return (UserControl)ViewState["UserSettings"];
}
}
public UserControl SpaceSettingsControl {
get {
if (ViewState["SpaceSettings"] == null) {
ViewState["SpaceSettings"] = LoadControl("~/UserControls/SpaceSettings.ascx") as SpaceSettings;
}
return (UserControl)ViewState["SpaceSettings"];
}
}
protected void SettingsLink_OnCommand(object sender, CommandEventArgs commandEventArgs) {
switch (commandEventArgs.CommandName) {
case "User":
AddUserSettings();
break;
case "Space":
AddSpaceSettings();
break;
}
}
private void AddUserSettings() {
AddSettings(UserSettingsControl);
}
private void AddSpaceSettings() {
AddSettings(SpaceSettingsControl);
}
private void AddSettings(UserControl control) {
SettingsPlaceholder.Controls.Add(control);
}
}
Create a Property in your WebForm like below.
public UserSettings UserSettingsControl
{
get
{
if (Session["MyControl"] == null)
Session["MyControl"] =
LoadControl("~/UserControls/UserSettings.ascx") as UserSettings;
return (UserSettings)Session["MyControl"];
}
}
Now you can access the memory of UserSettingsControl. As it will persist across the Postback. In the original code, the UserSettingsControl was being reset to null across PostBack.
By end of the Page Life Cycle all the controls created at runtime
will be disposed. Finally, you cannot find the control created at
runtime after Postback. Only Recreation of the same control will be
required on each PostBack.
You could just not use a PlaceHolder and have the control there the whole time. Then the linkButton could toggle the visibility of the control.
The main problem is that the you are adding the control to the page linkButton click. Dynamically added controls work best when added in the Page_Init and Page_PreInit this allows them to maintain their ViewState. Also they have to be added to the placeholder on every postback. If in your example another control causes a postback after the SettingsControl is added to the placeholder, then the SettingsControl will disappear because it is not being added on every postback.
Is it possible filtering a list in a content page by a value set in its master page? I mean when a user clicks on a link button in master page a variable is set and then based on the value that variable, when loading a content page, a list in it is filtered?
Yes, definitely. The only trick is to cast Page.Master to the type of master page that you're using.
Here's a quick example I whipped up:
MasterPage.master
<asp:Button runat="server" ID="btnToggleEvensOnly" Text="Toggle Even Number Filtering" OnClick="btnToggleEvensOnly_Click" />
<asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
MasterPage.master.cs
public bool IsFiltered
{
get
{
return ViewState["isFiltered"] == null ? false : (bool) ViewState["isFiltered"];
}
set
{
ViewState["isFiltered"] = value;
}
}
protected void btnToggleEvensOnly_Click(object sender, EventArgs e)
{
IsFiltered = !IsFiltered;
}
Default.aspx
<asp:Content ContentPlaceHolderID="ContentPlaceHolder1" runat="server" >
<asp:Repeater runat="server" ID="rptList">
<HeaderTemplate>
<table>
</HeaderTemplate>
<ItemTemplate>
<tr><td><%# Eval("i") %></td></tr>
</ItemTemplate>
<FooterTemplate>
</table>
</FooterTemplate>
</asp:Repeater>
</asp:Content>
Default.aspx.cs
protected override void OnPreRender(EventArgs e)
{
List<MyItem> items = new List<MyItem>();
for (int i = 0; i < 10; i++)
{
items.Add(new MyItem { i = i });
}
var query = items.AsEnumerable();
if (((MasterPage)Master).IsFiltered)
{
query = query.Where(mi => mi.i % 2 == 0);
}
rptList.DataSource = query;
rptList.DataBind();
base.OnPreRender(e);
}
public class MyItem
{
public int i { get; set; }
}
EDIT
Fixed the problem - I needed to add the validators to a ValidationGroup and then call each of the validation controls Validate() method on the submit behaviour of the button.
protected void btnDone_Click(object sender, EventArgs e)
{
this.cvValidation.Validate();
this.revYear.Validate();
if (Page.IsValid)
{
DateTime sub = Convert.ToDateTime(String.Format("01/{0}/{1}", ddlMonth.SelectedValue, txtYear.Text));
string str = sub.ToString("MMMM") + " " + sub.ToString("yyyy");
pcePopUp.Commit(str);
}
}
I am trying to add a CustomValidator to my UserControl but I cannot get the validator to run as it should. What I am trying to achieve is to test to see if the month/year is in the future.
After breaking into the code I have noticed that the validateDate method is being fired twice. Any help on this situation would be greatly appreciated.
Could it be a problem with the way I am retrieving data from the controls as using the following two methods.
private void loadPostBackData()
{
loadPostBackDataItem(((TextBox)puymcStartDate.FindControl("txtDate")));
loadPostBackDataItem(((TextBox)puymcEndDate.FindControl("txtDate")));
}
private void loadPostBackDataItem(TextBox control)
{
string controlId = control.ClientID.Replace("_", "$");
string postedValue = Request.Params[controlId];
if (!String.IsNullOrEmpty(postedValue))
{
control.Text = postedValue;
}
else
{
control.Text = String.Empty;
}
}
UserControl code
ASP.NET Code
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="CtrlPopUpYearMonthCalendar.ascx.cs" Inherits="CLIck10.Controls.CtrlPopUpYearMonthCalendar" %>
<%# Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajaxToolkit" %>
<asp:TextBox ID="txtDate" ReadOnly="true" runat="server" />
<div id="divPopUp" runat="server" class="box" style="width:320px;visibility:hidden;margin-left:5px;">
<div class="boxTitle">
<h1>Choose date</h1>
</div>
<div style="padding:5px;">
<asp:UpdatePanel id="upPopUp" UpdateMode="Always" runat="server">
<ContentTemplate>
<asp:DropDownList ID="ddlMonth" runat="server" /> <asp:TextBox ID="txtYear" runat="server" />
<asp:Button ID="btnDone" Text="Done" runat="server" UseSubmitBehavior="false" onclick="btnDone_Click" />
<asp:RegularExpressionValidator ID="revYear" ValidationExpression="^[0-9]{4}$" ControlToValidate="txtYear" Display="Dynamic" Text="(*)" ErrorMessage="Year must be valid" runat="server" />
<asp:CustomValidator ID="cvValidation" Text="(*)" Display="Dynamic" ErrorMessage="Date must be in the future" OnServerValidate="validateDate" ValidateEmptyText="true" runat="server" />
<asp:ValidationSummary ID="vsDate" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
</div>
</div>
<ajaxToolkit:PopupControlExtender ID="pcePopUp" PopupControlID="divPopUp" TargetControlID="txtDate" Position="Right" runat="server" />
Code Behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using AjaxControlToolkit;
using System.Diagnostics;
namespace CLIck10.Controls
{
public partial class CtrlPopUpYearMonthCalendar : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
DateTime month = Convert.ToDateTime("01/01/2000");
for (int i = 0; i < 12; i++)
{
DateTime nextMonth = month.AddMonths(i);
ListItem item = new ListItem();
item.Text = nextMonth.ToString("MMMM");
item.Value = nextMonth.Month.ToString();
ddlMonth.Items.Add(item);
}
if (txtDate.Text.Equals(String.Empty))
{
ddlMonth.Items.FindByValue(DateTime.Now.AddMonths(1).Month.ToString()).Selected = true;
if (DateTime.Now.Month.ToString("MM").Equals("12"))
{
txtYear.Text = DateTime.Now.AddYears(1).ToString("yyyy");
}
else
{
txtYear.Text = DateTime.Now.ToString("yyyy");
}
}
else
{
DateTime date = Convert.ToDateTime("01, " + txtDate.Text);
ddlMonth.Items.FindByValue(date.Month.ToString()).Selected = true;
txtYear.Text = date.ToString("yyyy");
}
}
}
protected void btnDone_Click(object sender, EventArgs e)
{
DateTime sub = Convert.ToDateTime(String.Format("01/{0}/{1}", ddlMonth.SelectedValue, txtYear.Text));
string str = sub.ToString("MMMM") + " " + sub.ToString("yyyy");
pcePopUp.Commit(str);
}
public void validateDate(object sender, ServerValidateEventArgs e)
{
DateTime sub = Convert.ToDateTime(String.Format("01/{0}/{1}", ddlMonth.SelectedValue, txtYear.Text));
if (sub >= DateTime.Now)
{
e.IsValid = true;
}
else
{
e.IsValid = false;
}
}
}
}
After experimenting with just embedding the control in a blank page It works so it must be something to do with the page I am working on.
I tried out your code as a page (not a usercontrol) and it worked fine.
Are you dynamically adding your usercontrols to the page?
I am using a UserControl Which is present in the Master Page. I need to access a Master page control in the UserControl. I need your suggestions.
The Scenario is A label is present in the Master Page. Based upon selections in the usercontrol i need to modify the masterpage label. The UserControl is present in the Master page itself not in the content place holder.
Create a public method (or public property) in the master page to modify your label and in the UserControl you are able to call it, through the Page.master object:
YourMasterPageClass master = Page.master as YourMasterPageClass;
if(master != null)
{
master.YourEditMethod("hello");
}
Quick and Easy way is to create event in control and handle in master like this:
//Control aspx
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="TestControl.ascx.cs"
Inherits="TestControl" %>
<div style="width:300px;border:2px groove blue;">
<asp:Button ID="btn1" runat="server" Text="One" onclick="btn_Click" />
<asp:Button ID="btn2" runat="server" Text="Two" onclick="btn_Click" />
<asp:Button ID="btn3" runat="server" Text="Three" onclick="btn_Click" />
<asp:Button ID="btn4" runat="server" Text="Four" onclick="btn_Click" />
</div>
//Control C#
namespace Controls
{
public partial class TestControl : System.Web.UI.UserControl
{
public delegate void UserChoice(TestEventArgs e);
public event UserChoice OnUserChoice;
protected void btn_Click(object sender, EventArgs e)
{
if (OnUserChoice != null)
OnUserChoice(new TestEventArgs(((Button)sender).Text));
}
}
public class TestEventArgs : EventArgs
{
private string _value;
public TestEventArgs(string str)
{
_value = str;
}
public string Message
{
get { return _value; }
}
}
}
//MasterPage Code
protected void Page_Load(object sender, EventArgs e)
{
test1.OnUserChoice += new
Controls.TestControl.UserChoice(test1_OnUserChoice);
}
void test1_OnUserChoice(ROMS.Intranet.Controls.TestEventArgs e)
{
MasterLabel.Text = e.Message;
}
MasterLabel is name of the label in master page.
test1 is the control in master page.