Archive for the ‘MasterPage’ tag
Solution for FindControl with MasterPages
Imagine you have the following declaration
<asp:Content ContentPlaceHolderID="plcMainContent" ID="cntMain" runat="server"> ... <asp:Panel id="pnlThumb1" runat="server" Visible="true"/> ... </asp:Content>
and you are calling in your CodeBeside
this.pnlThumb1.Visible = false;
it will simply work without any problem.
Now think about changing your call to
this.FindControl("pnlThumb1").Visible = false;
what happens? You will get a NullReferenceException!
What you can do is first get a reference to your Content and second make a FindControl call:
ContentPlaceHolder mainContent = (ContentPlaceHolder)this.Master.FindControl("plcMainContent"); mainContent.FindControl("pnlThumb1").Visible = false;
This works, but this workaround is not very elegant.
We can get more elegance to our code by using reflection and a simple extension class.
The basic idea behind the following code is, that ASP.NET generates protected Control declarations for every control in the page. So we can get references to the controls by reflecting into the class instead of using FindControl.
public static class PageExtensions { public static T GetControl<T>(this Page page, string name) where T : Control { FieldInfo field = page.GetType().GetField(name, System.Reflection.BindingFlags.IgnoreCase | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic); if (field != null) return (T)field.GetValue(page); return null; } }
The usage now is quite simple:
this.GetControl<Panel>("pnlThumb1").Visible = false;
Eleganter Zugriff auf MasterPage-Controls
Will man von einer Content Page auf Controls der MasterPage zugreifen, so ist die erste Idee oft die Nutzung von MasterPage.FindControl. Klar, das funktioniert. Nur stellt sich die Frage, ob das nicht schöner geht? Bevor dieser Frage auf den Grund gegangen wird, soll das Problem kurz an einem Beispiel veranschaulicht werden:
MasterPage.master:
<%@ Master Language="C#" AutoEventWireup="true" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %> <html> <body> <form id="form1" runat="server"> <asp:TextBox runat="server" ID="TextBoxMaster" /> <asp:ContentPlaceHolder ID="ContentPlaceHolderMain" runat="server"> </asp:ContentPlaceHolder> </form> </body> </html>
Das Ziel soll nun sein aus einer Content Pager heraus, möglichst elegant auf die TextBox “TextBoxMaster” zuzugreifen. Perfekt wäre also ungefähr so etwas:
protected void Page_Load(object sender, EventArgs e) { Master.TextBoxMaster.Text = "Hello world"; }
Leider funktioniert das so auf Anhieb nicht. Das erste Problem ist, dass hierfür der Compiler wissen müsste, welches der Typ der MasterPage ist, der von der Content Page referenziert wird. Da man aber die MasterPage zur Laufzeit zuweisen kann, kommt man hiermit nicht so recht weiter…
Oder? Da wurde doch in ASP.NET 2.0 eine neue Seiteneigenschaft MasterType eingeführt, die sollte doch genau das Problem lösen und zur Compilezeit den Typen der MasterPage bekannt machen!
<%@ Master Language="C#" MasterPageFile="~/MyMasterPage.master" AutoEventWireup="true" CodeFile="MyMasterPage.master.cs" Inherits="contentPage" %> <%@ MasterType VirtualPath="~/MyMasterPage.master" %> <asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolderMain" runat="Server"> Inhalt der Content Page </asp:Content>
Der Ansatz ist gar nicht so falsch. Jetzt weiß der Compiler uns auch IntelliSense schonmal, welche Eigenschaften und Methoden zur referenzierten MasterPage gehören.
Doch leider führt der Aufruf von Master.TextBoxMaster wieder ins Nirvana.
Der Grund hierfür ist, dass alle Controls einer Seite (der MasterPage eingeschlossen) standardmäßig die Sichtbarkeit protected tragen. Die gute Nachricht ist: das können wir ändern!
Ganz ohne Arbeit geht es leider nicht, doch die hält sich in Grenzen.
Schritt 1:
Entfernen der partial-class-Deklaration. Dies soll ASP.NET beibringen, dass nur noch eine Code-Datei für die MasterPage existiert und keine temporäre mehr für die Control-Deklarationen zur Compilezeit erzeugt werden muss.
Schritt 2:
Deklarieren der Controls mit der public-Sichtbarkeit.
public class MyMasterPage : System.Web.UI.MasterPage { public TextBox TextBoxMaster; }
Schritt 3:
Ändern der @Page Direktive: Tausche Inherits durch CodeBaseFileClass und verschiebe die CodeBehind-Datei in das Verzeichnis App_Code.
<%@ Master Language="C#" MasterPageFile="~/MyMasterPage.master" AutoEventWireup="true" CodeFileBaseClass="MyMasterPage" %>
Schritt 4:
Ausführen des lang ersehnten Codes in der Content Page
protected void Page_Load(object sender, EventArgs e) { Master.TextBoxMaster.Text = "Hello world"; }









