Setting parent page controls visibility from Child user control page - asp.net

I have a parent page Page1 which has button1. Page1 has a usercontrol uc1. uc1 has an update panel inside which a grid grid1 is present. I am trying to set Page1.button1's visibility to false, depending on the row command event(there are some if conditions in the row command event) of uc1.grid1. I am setting Page1.button1's visibility in the following way:
Create a IsButton1Visible property in uc1. Set the property in UC1.Grid1.RowCommand to false, on page1 PreRender event, access IsButton1Visible and set Page1.button1 visibility.
Even though in quick watch Page1.button1 visibility is set to false at the line of assignment, when I see the UI, it is still visible. I don't know what I am doing wrong. Or the way that I am getting hold of button1 and its visibility is not correct.
In general can we set a Parent page's control's property from a user control during the user control event?

If you use the event-driven model approach
Delegate/EventArgs code:
public class ButtonVisiblityEventArgs : EventArgs
{
public ButtonVisiblityEventArgs(bool visible)
{
this.Visiblity = visible;
}
public bool Visiblity { get; private set; }
}
public delegate void UpdateParentButtonVisibilityEventHandler(object sender, ButtonVisiblityEventArgs args);
User control code:
public event UpdateParentButtonVisibilityEventHandler RaiseUpdateParentButtonVisibilityEvent;
private void RequestParentButtonVisibilityChange(bool setVisible)
{
if (RaiseUpdateParentButtonVisibilityEvent != null)
{
RaiseUpdateParentButtonVisibilityEvent(this, new ButtonVisiblityEventArgs(setVisible));
}
}
And in your command handler, just call:
RequestParentButtonVisibilityChange(false);
whenever you want to hide the button. On your page:
protected void Page_Load(object sender, EventArgs e)
{
this.RaiseUpdateParentButtonVisibilityEvent += new UpdateParentButtonVisibilityEventHandler(uc_RaiseUpdatecurrentDisplayPanelRequestEvent);
}
private void uc_RaiseUpdatecurrentDisplayPanelRequestEvent(object sender, ButtonVisiblityEventArgs args)
{
button1.Visible = args.Visiblity;
}

If the problem you are having is that your button lives outside of the update panel, you can do the following. Page codebhind:
protected void Page_Load(object sender, EventArgs e)
{
string hideScript = string.Format("function updateButtonVisibility( visibility ) {{ var button = $('#{0}'); if (visibility) {{ button.show(); }} else {{ button.hide(); }} }}", this.button1.ClientID);
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "updateButtonVisibility", hideScript, true);
}
And in your user control command handler:
bool shouldButtonBeVisible = false; //update this appropriately in your logic
ScriptManager.RegisterStartupScript(this, this.GetType(), "upUpdateButtonVisibility", "updateButtonVisibility(" + shouldButtonBeVisible ? "true" : "false" + ");", true);
Please note that this creates a TIGHT dependency between your UC and the page. It requires that any page that consumes this control has registered this script. There are ways to get around this (such as setting a function script callback to call, detecting if that javascript function exists, etc), but this should at least get you moving.
If there is something specific on the page after your update panel finishes that you could key off, it might be better to register an end request handler
$(function() { Sys.WebForms.PageRequestManager.getInstance().add_endRequest(updatePanelEndRequestHandler); } );
function updatePanelEndRequestHandler() {
var shouldBeVisible = $('.MyClassThatSaysIShouldntAllowMoreButtons').length > 0; //do some checking on the grid
updateButtonVisibility(shouldBeVisible);
}

you can put your user controls inside panels on your parent pages and change the visibility.
e.g.
<asp:Panel runat="server" ID="pnlQuote">
...
</asp:Panel>
<asp:Panel runat="server" ID="pnlContact">
<uc1:ContactForm runat="server" ID="ContactForm " />
</asp:Panel>
From the child control you can make a button click event which does something like this
protected void btnBackToQuote_Click(object sender, EventArgs e)
{
Panel pnlQuote = this.Parent.FindControl("pnlQuote") as Panel;
Panel pnlContact = this.Parent.FindControl("pnlContact") as Panel;
pnlQuote .Visible = true;
pnlContact.Visible = false;
}

Related

How to keep button enabled after closing the form

I'm trying to make a system and I'm having trouble with buttons being disabled.
I have a function that makes the button on a another form enable the button on the main form but whenever I get back to the main form the button becomes disabled again.
How do I keep this permanent even after closing the program? Can I save it in a database to keep its function enabled even if its default is disabled?
Here's the picture of what it looks like:
Thanks for the help.
Take two buttons - "button1" and "button2" on "MainForm" Form.
Set property Enabled=false for "button1"
MainForm.cs
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
Form2 oFrm2 = new Form2();
oFrm2.evtFrm += new ShowFrm(oFrm2_evtFrm);
oFrm2.Show();
}
void oFrm2_evtFrm()
{
button1.Enabled = true;
}
}
Take one button - "button1" on "Form2" Form.
Form2.cs
public delegate void ShowFrm();
public partial class Form2 : Form
{
public event ShowFrm evtFrm;
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if (evtFrm != null)
{
evtFrm();
}
}
}
MainForm will display first.
Click on "button2" to display "Form2".
On "Form2", click on "button1" to make enable "button1" of "MainForm"
If you want to make "button1" enable permanent, you have to store value - "button1" is enable or disable.

RaisePostBackEvent called on wrong control

I have spent two days with another colleague investigating this. I was surprised as most solutions discussing this problem either have the wrong solution or a solution that works, I think, for the wrong reasons.
We have a custom button control that needs to raise a ServerClick event when it is pressed. Here is the summarised code:
public class MyButton : WebControl, IPostBackEventHandler
{
protected HtmlGenericControl _Button;
protected string _OnClick = "";
protected string _Name;
public event EventHandler ServerClick;
// etc...
public MyButton()
{
Width = Unit.Pixel(100);
_Button = new HtmlGenericControl("button");
Controls.Add(_Button);
}
protected override void Render(HtmlTextWriter writer)
{
_Button.Attributes.Add("id", string.IsNullOrEmpty(_Name) ? base.ID : _Name);
_Button.Attributes.Add("name", _Name);
// etc...
_OnClick = Page.ClientScript.GetPostBackEventReference(this, "");
_Button.Attributes.Add("onClick", _OnClick);
// etc...
ID = String.Empty;
Name = String.Empty;
AccessKey = String.Empty;
TabIndex = -1;
Width = Unit.Empty;
base.Render(writer);
}
protected virtual void OnServerClick()
{
if (this.ServerClick != null)
{
this.ServerClick(this, new EventArgs());
}
}
public void RaisePostBackEvent(string eventArgument)
{
this.OnServerClick();
}
}
On the browser end the code uses two of these buttons
<form>
<!-- etc ... -->
<div class="row actionBar">
<PGSC:MyButton Name="btnAccept" ID="btnAccept" LabelID="3244" TabIndex="70" runat="server" OnServerClick="AcceptClickHandler"/>
<PGSC:MyButton Name="btnClose" ID="btnClose" LabelID="349" OnClick="window.returnValue=frmMMD.hdnMmdId.value;window.close();" TabIndex="80" runat="server" />
</div>
</form>
The Problem:
The event is not raised on the accept button. Debugging reveals that RaisePostBackEvent is called but on the Close button, which does not have a ServerClick handler attached, hence nothing happens. No event handlers get called.
Notes:
The problem is not seen if there is only one MyButton on the page.
If the buttons are reordered such that the accept button is the last on the page, it starts working.
Moving the buttons outside of the form tag causes events to work as expected, and the accept buttons event handler is called correctly.
Implementing IPostBackDataHandler and calling RaisePostBackEvent() from IPostBackDataHandler::RaisePostDataChangedEvent() causes the event to be raised correctly on the accept button when inside the form tag.
Calling RegisterRequiresRaiseEvent(btnAccept) during PageLoad routes events correctly to the accept button.
The Question:
What is the correct solution from the ones that work above? Or is there another solution? We need it to work such that multiple buttons on the page can raise independent click events, without regard to their order or position on the page.
My Thoughts:
This problem seems to be discussed here: http://forums.asp.net/t/1074998.aspx?ASP+NET+RaisePostbackEvent+Issues
One is lead to believe that calling __doPostback() with the correct __EVENTTARGET should automatically route the event correctly to the button, but this is not happening in reality. It only happens if we also implement IPostBackDataHandler. Many solutions on the web seem to point to __doPostback, UniqueID etc as the culprit when actually implementing IPostBackDataHandler is what seemingly fixes the issue.
The Control implements IPostBackEventHandler but not IPostBackDataHandler. I think this is correct because the control does not need to raise any data driven events. So implementing IPostBackDataHandler to get it working seems like a hack.
Using RegisterRequiresRaiseEvent is unintuitive and besides will not work if multiple buttons on the page would like to raise events.
I wonder, how does an asp:Button do it?
I've simulated a situation.
Hope it helps.
There is the MyButton WebServerControl class:
[DefaultProperty("Text")]
[ToolboxData("<{0}:MyButton runat=server></{0}:MyButton>")]
public class MyButton : WebControl, IPostBackEventHandler
{
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string Text
{
get
{
String s = (String)ViewState["Text"];
return ((s == null) ? String.Empty : s);
}
set
{
ViewState["Text"] = value;
}
}
protected HtmlGenericControl _Button;
protected string _OnClick = "";
protected string _Name;
public event EventHandler ServerClick;
// etc...
public MyButton()
{
Width = Unit.Pixel(100);
_Button = new HtmlGenericControl("button");
Controls.Add(_Button);
}
protected override void Render(HtmlTextWriter writer)
{
_Button.Attributes.Add("id", string.IsNullOrEmpty(_Name) ? base.ID : _Name);
_Button.Attributes.Add("name", _Name);
// etc...
_OnClick = Page.ClientScript.GetPostBackEventReference(this, "");
_Button.Attributes.Add("onClick", _OnClick);
// etc...
ID = String.Empty;
//Name = String.Empty;
AccessKey = String.Empty;
TabIndex = -1;
Width = Unit.Empty;
base.Render(writer);
}
protected virtual void OnServerClick()
{
if (this.ServerClick != null)
{
this.ServerClick(this, new EventArgs());
}
}
public void RaisePostBackEvent(string eventArgument)
{
this.OnServerClick();
}
}
I then used my web server control in a project, let's say this is the default.aspx:
<div><cc1:MyButton ID="btnAccept" runat="server" TabIndex="70" OnServerClick="AcceptClickHandler" />
<cc1:MyButton ID="btnClose" Text="Close" Width="256px" LabelID="349" runat="server" TabIndex="80" /></div><div>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</div>
And in default.aspx.cs I've implemented simply the event:
protected void AcceptClickHandler(object sender, EventArgs e)
{
Label1.Text = DateTime.Now.ToLongTimeString();
}
The AcceptClickHandler fires only when clicking on the Accept button and not
on the Close button.
Sorry if I didnt get the problem right.

Why is OnPreRender being called over and over again?

In my Sharepoint 2010 WebPart, I have this code:
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if (this.dpsvisWebPart != null && this.dpsvisWebPart.CustomTitleProp != null)
{
lbl_Title.Text = String.Format("<h1>{0}</h1>", this.dpsvisWebPart.CustomTitleProp.ToString());
if (this.dpsvisWebPart.CheckboxGenSection1)
{
GenerateSection1();
}
if (this.dpsvisWebPart.CheckboxGenSection2)
{
GenerateSection2();
}
if (this.dpsvisWebPart.CheckboxGenSection3)
{
GenerateSection3();
}
if (this.dpsvisWebPart.CheckboxGenSection4)
{
GenerateSection4();
}
if (this.dpsvisWebPart.CheckboxGenSection5)
{
GenerateSection5();
}
if (this.dpsvisWebPart.CheckboxGenSection6)
{
GenerateSection6();
}
if (this.dpsvisWebPart.CheckboxGenSection7)
{
GenerateSection7();
}
if (AnyCheckboxSelected())
{
// Create Save button
this.Controls.Add(new LiteralControl("<br />"));
Button btnSave = new Button();
btnSave.Text = "Save";
btnSave.Click += new EventHandler(btnSave_Click);
this.Controls.Add(btnSave);
AddVerticalSpace();
}
}
}
On testing my WebPart (clicking the button, thus - presumably - executing the btnSave_Click handler, I found that nothing was being saved.
Stepping through the code, I see that OnPreRender is being reached - in fact, over and over again.
So, I added this to the WebPart class:
private bool PreRenderAlreadyRun = false;
...and then changed the beginning of OnPreRender() to this:
protected override void OnPreRender(EventArgs e)
{
if (PreRenderAlreadyRun) return;
PreRenderAlreadyRun = true;
base.OnPreRender(e);
. . .
...but PreRenderAlreadyRun is always false when OnPreRender is entered, which happens over and over. Other breakpoints are not reached (the button click, etc.) presumably because the page is in an endless loop.
How can I get OnPreRender() to run only once? Or should this code be in Page_Load() instead of OnPreRender(), or...???
The solution was to move the code that was in OnPreRender() to Page_Load()
Apparently, just like at the stockyard, rendering happens many times, while the page is only loaded once. That's my theory, and I'm stickin' to it (for now, anyway).

ViewState error with dynamically built menu

I have a Menu control that I dynamically populate with categories. When a user clicks a category, the postback should populate a grid with products in that category. However, I seem to have tried every way possible, i.e. whatever page life cycle time, only to always get this error:
Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request.
Here is all my code:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
BuildCategoryMenu();
}
}
protected void categoryMenu_ItemClick(object source, DevExpress.Web.ASPxMenu.MenuItemEventArgs e)
{
var catId = new Guid(e.Item.Name);
ListProductsByCatId(catId);
}
private void BuildCategoryMenu()
{
var cats = _categoryService.ListActive();
categoryMenu.Items.Clear();
foreach (var cat in cats)
{
categoryMenu.Items.Add(new MenuItem { Text = cat.Name, Value = cat.id.ToString() });
}
}
private void ListProductsByCatId(Guid catId)
{
productGrid.DataSource = _productService.ListByCatId(new Guid("a5c2f0ef-a3cc-4af1-abac-37f1be6a5c74"));
productGrid.DataBind();
}
Here is my Menu:
<asp:Menu ID="categoryMenu" runat="server" EnableViewState="false">
</asp:Menu>
EnableViewState is only false because it didn't work with true either.
One answer to this is to avoid the postbacks and code URL's into the menu items. More RESTful, but probably making AJAXing the menu a bit harder.

apply CSS dynamically in asp.net 2.0

I have a scrolling div with Three linkbuttons and three differents divs. I need to apply CSS to active linkbutton as soon as button is clicked.The codes used by me are:
protected void btnNetwork_Click(object sender, EventArgs e)
{
this.btnForecast.CssClass = "li_1";
this.btnBlog.CssClass = "li_2";
this.btnNetwork.CssClass = "li_3_active";
this.btnNetwork.ForeColor = System.Drawing.Color.White;
lblMsg.Visible = false;
BindGW("-----------------------------------");
Forecast.Visible = false;
Blog.Visible = false;
Network.Visible = true;
}
Thanks & Regards,
Khushi
Instead of using server side event use client side javascript event. Try:
$get('btnId').setAttribute("class", "some_class_name");
You will not be able to dynamically change the CSS properties of elements by using post-back, which refreshes the page. Javascript must be used if you want to the change to happen immediately.
Simple example:
take one button and one label
create one stylesheet and add class style1 as:
body
{
}
.style1
{
color: #000080;
}
write this simple code in button click event
protected void Button1_Click(object sender, EventArgs e)
{
this.Label1.CssClass = "style1";
}

Resources