Asp.net: Can we use MasterPage's viewstate in ContentPage? - asp.net

Asp.net: Can we use MasterPage's viewstate in ContentPage ?

From a Content Page you can refer to a MasterPage through the Master Property. Create a Property on the Master Page that uses its getter and setter to store its value in ViewState, like so:
string MyProperty
{
get { return ViewState["MyProperty"] as string; }
set { ViewState["MyProperty"] = value; }
}
Obviously you could make that code safer by testing for nulls and what-not...
Here's the important bit: Viewstate elements are only accessible from the controls that added them so you need to refer back up the tree.
You can also strongly type the Master property on Page by using the <%# MasterType %> directive in your ASPX file, thusly:
<%# MasterType VirtualPath="~/masters/SourcePage.master"" %>
HTH.

Related

Make control public in designer generated file

It there any way to tell the ASP.NET .designer.cs code generator to create public controls instead of protected?
.master.designer.cs file:
/// <summary>
/// btnLanguageEN control.
/// </summary>
/// <remarks>
/// Auto-generated field.
/// To modify move field declaration from designer file to code-behind file.
/// </remarks>
protected global::System.Web.UI.WebControls.LinkButton btnLanguageEN;
.master file:
<asp:LinkButton runat="server" ID="btnLanguageEN" OnClick="btnLanguageEN_Click" Text="ENG" />
Why I need it? I am trying to access to master page controls from child page:
.aspx file:
<%# MasterType TypeName="www.MainMaster" %>
.aspx.cs file:
Master.btnLanguageEN.Text = "123";
Here I receive an error stating that btnLanguageEN is protected.
Rather than modify the designer generated code, reference the control through the Page's Master property using the FindControl method.
You'll need to add the following directive to the top of your child page (if it's not already there) to reference the master page:
<%# MasterType virtualpath="~/Masters/Master1.master" %>
Then, in your child page's code behind, you can do things like the following.
void Page_Load()
{
// Gets a reference to a LinkButton on the master mage.
// a ContentPlaceHolder
LinkButton mpLinkButton = (LinkButton) Master.FindControl("btnLanguageEN");
if(mpLinkButton != null)
{
mpLinkButton.Text = "123 - Labelled by Child Page";
}
}
Reference: http://msdn.microsoft.com/en-us/library/xxwa0ff0.aspx
Create a strongly typed reference to your master page by including this on your ASPX page.
<%# MasterType virtualpath="~/Masters/Master1.master" %>
On your Master Page, create a property. This will make the control available from other classes..
public Button btnLanguageENMaster
{
get {return btnLanguageEN;}
private set;
}
Then from your regular page code behind you can do this...
Master.btnLanguageENMaster.Text = "Hello, world!"

How to LoadControl a control that uses VaryByControl OutputCache, specifying values for properties

I've got a user control that should use caching, with VaryByControl. The .ascx file looks like this :
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="TestControl.ascx.cs" Inherits="mynamespace.TestControl" %>
<%# OutputCache Duration="10" Shared="true" VaryByControl="Test" %>
<p id="SomeText" runat="server">Nothing</p>
The TestControl class in the code-behind file has a int Test {...} property and an Page_Load() event handler that fills the SomeText paragraph with:
SomeText.InnerText = string.Format(#"Test={0} at {1}", Test, DateTime.Now)
I've got a .aspx file that looks like this:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="TestPage.aspx.cs" Inherits="mynamespace.TestPage" %>
<%# Register TagPrefix="xxx" TagName="TestControl" Src="Controls\TestControl.ascx" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<xxx:TestControl Test="6" runat="server" />
<xxx:TestControl Test="7" runat="server" />
<hr />
<asp:PlaceHolder ID="Suport" runat="server" />
</body>
</html>
The two <xxx:TestControl> tags properly load instances of TestControl with Test set to the expected value, I can refresh the browser a few times and I can see the cache properly doing it's job.
Now I'd like to fill the <asp:PlaceHolder ID="Suport" /> with some instances of TestControl, using varying Test values, that should all benefit from proper caching. I'm trying to use the LoadControl method, but I can't find a way to specify a value for the Test property. I expect such a method to exist, after all asp.net code loading the .aspx page manages to find the proper cached control. All I get is an instance of PartialCachingControl without CachedControl initialized and at runtime the rendered TestControl shows Test has the default value of 0.
This is how my .aspx Page_Load() event handler looks like:
protected void Page_Load(object sender, EventArgs e)
{
PartialCachingControl tc = (PartialCachingControl) LoadControl(#"Controls\TestControl.ascx");
if (tc.CachedControl != null)
((TestControl)tc.CachedControl).Test = 67;
Suport.Controls.Add(tc);
}
Edit
I could work around the problem by caching the whole page, but it just seems odd that I can't find a way to do it this way. Especially since invoking the control through the ASPX file works as expected (proving there's a way).
Edit 2
Hmm, no answers so far. I started a bounty, hopefully it gets a bit more attention.
To get a control participate in the full page life cycle it shall be added in the Init event or the CreateChildControls method rather than to add it on Load. Since VaryByControl needs fully qualified control identifiers to work it must be initialized before the page cycle begins.
Something similar to this:
protected override void OnInit(EventArgs e) {
var testControl = LoadControl(#"TestControl.ascx");
testControl.ID = "TestControl";
Suport.Controls.Add(testControl);
base.OnInit(e);
}
protected override void OnLoad(EventArgs e) {
TestControl testControl = GetTestControl("TestControl");
if(testControl != null){ //If it is null it is cached and can not be changed
testControl.Test = 242;
}
base.OnLoad(e);
}
private TestControl GetTestControl(string name) {
var control = this.Suport.FindControl(name);
var partialCachedControl = control as PartialCachingControl;
if(partialCachedControl != null) {
control = partialCachedControl.CachedControl;
}
return control as TestControl;
}
Since the output is cached per control you can not change the control until the cache is cleared. If you want to change the value and regenerate the content you either have to get the cache cleared or create a new control (with a new ID). One way to clear the cache is to use VaryByCustom instead and generates a cache key that changes if your Test-value is changing.
Also remember to implement INamingContainer interface on your test-control to avoid naming conflicts between the different objects. To do this, just add the interface to the control, like this:
public class TestControl: WebControl, INamingContainer {}
You have to swap 2 lines in order to make your code work :
PartialCachingControl tc = (PartialCachingControl) LoadControl(#"Controls\TestControl.ascx");
Suport.Controls.Add(tc);
if (tc.CachedControl != null)
((TestControl)tc.CachedControl).Test = 67;
As soon as you add the control, the cached control is initialized.
E.G.
I think you have misunderstood the VarByControl-property, it does not tell the cache to change upon a property on the control, but on the ID of controls on the page. Here is the text from MSDN:
The VaryByControl property is set to fully qualified control identifiers, where the identifier is a concatenation of control IDs starting from the top-level parent control and delimited with a dollar sign ($) character.
In your case you can maybe set VaryByCustom instead of VaryByControl and generate a cache key from the Test-property-value and vary it if it changes.

All controls are still null after calling EnsureChildControls()?

The way this page is laid out, all of the data is loaded at Page_Init. Well, I have a custom control that is having problems with this though.
I have it on the page like so:
<cc:SomeControl... />
And then I set the value at Page_Init using
MyControl.Value="blah";
Simple stuff..
The Value is an accessor and has something similar to this:
public string Value{
get...
set{
EnsureChildControls();
MyHiddenField.Value=value;
}
}
and it is here that I have a problem. It says that MyHiddenField is null. Is Page_Init just too early for this? Or is there some other function I need to call?
The fix for this was changing from using a namespace to reference the CustomControl to using a src with a filename
changing this:
<%# Register Assembly="MyProduct" Namespace="MyProduct.CustomControls" TagPrefix="cc" %>
to this:
<%# Register src="/CustomControls/MyControl.ascx" tagname="MyControl" tagprefix="uc2" %>

Can I create custom directives in ASP.NET?

I have created a menu control in asp.net and have put it into master page. This menu control have property ActiveItem which when modified makes one or another item from menu appear as active.
To control active item from child page I have created a control which modifies master page property enforced by IMenuContainer interface to update menu control's active item in master page.
public class MenuActiveItem : Control
{
public ActiveItemEnum ActiveItem
{
get
{
var masterPage = Page.Master as IMenuContainer;
if (masterPage == null)
return ActiveItemEnum.None;
return masterPage.ActiveItem;
}
set
{
var masterPage = Page.Master as IMenuContainer;
if (masterPage == null)
return;
masterPage.ActiveItem = value;
}
}
}
Everything works perfectly and I really enjoy this solution, but I was thinking that, if I knew how, I would have created a custom directive with same feature instead of custom control because it just makes more sense that way.
Does anybody know how to do it?
You should be able to turn this into a custom property of your Page, which you can set in the Page directive.
Create a base class for your page, and then change your Page directives like this:
<%# Page Language="C#" MasterPageFile="~/App.master"
CodeFileBaseClass="BasePage" ActiveItem="myActiveItem" AutoEventWireup="true"
CodeFile="Page1.aspx.cs" Inherits="Page1" %>
You may have to change the property to be a string, and do a conversion to the enum. But otherwise your code can remain the same, and it doesn't have to be in a control.

Access child user control's property in parent user control

I have included a user control in another statically following code :
place the folowing directive in the asp code of the parent page or
usercontrol:
<%# Register src="Name_of_your_child_control.ascx"
tagname="Name_of_your_child_control" tagprefix="uc1" %>
use the following tag in the asp-code of the parent page/control:
<uc1:Name_of_your_child_control ID="Name_of_your_child_control1"
runat="server" />
.....
But the issue is...i am not able to access the public properties of user control which got included(child user control) in given user control(parent user control)...
Please help :(
Say your usercontrol was this:
<%# Control Inherits="Project.MyControl" Codebehind="MyControl.ascx.cs" %>
<asp:TextBox ID="TB" runat="server" />
Your control code-behind:
namespace Project
{
public partial class MyControl : UserControl
{
public string MyTextProperty
{
get { return TB.Text; }
set { TB.Text = value; }
}
}
}
In your parent page that included the control, like this:
<%# Register src="~/MyControl.ascx" tagname="MyControl" tagprefix="uc1" %>
<uc1:MyControl ID="MyControlID" runat="server" />
You can use that property in code:
MyControlID.MyTextProperty = "bob";
Using
Name_of_your_child_control1.PublicPropertyName
must work for your parent user control.
Check the path and file names you are using, Anish. You have something wrong. Is Visual Studio telling you it can't find the control? Is it failing at compile time? Runtime?
It's funny but whenever you add a property to a user control.
You need to register it again in the parent. So in your case,
Add a space at the end of this line and remove it again:
$<% Register src="~/MyControl.ascx" tagname="MyControl" tagprefix="uc1" %>
This will re - register the user control and you will be able to access new properties.

Resources