I'm trying to make a generic Search UserControl that can be given some values, based on those values the search results will display. However I'm currently trying to display the results of my values, and they always show up as my default values.
my UserControl code:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="ProductSearch.ascx.cs" Inherits="..." %>
<asp:Label ID="lblSearchWord" runat="server" />
<asp:Label ID="lblSearch" runat="server" />
Code Behind:
private string _searchWord = string.Empty;
private int _search = -1;
public string SearchWord
{
get { return _searchWord; }
set { _searchWord = value; }
}
public int Search
{
get { return _search; }
set { _search = value; }
}
protected void Page_Load(object sender, EventArgs e)
{
lblGroupId.Text = LevelId.ToString();
lblSearchWord.Text = SearchWord;
}
When I press the search button on the main aspx.cs page I do the following:
protected void btnSearch_Click(object sender, EventArgs e)
{
ucPS.SearchWord = txtProductSearch.Text;
ucPS.Search = 1
}
My aspx page contains the following
<%# Register src="UserControls/ProductSearch.ascx" tagname="ProductSearch" tagprefix="ps" %>
<ps:ProductSearch id="ucPS" runat="server" />
My problem is that I can't use Query strings as the user might have selected some other things on this page that I need to keep the state of, however I did test that one and foudn it working.
Where am I going wrong? or is there an better alternative (except for query strings).
All variables in a page are disposed at the end of the page-lifecycle. Hence SearchWord will always be initialized with the default value on every postback.
You need to persist it somewehere else, for example in a ViewState variable.
public string SearchWord
{
get
{
if (ViewState["SearchWord"] == null)
return "";
else
return (String)ViewState["SearchWord"];
}
set { ViewState["SearchWord"] = value; }
}
Nine Options for Managing Persistent User State in Your ASP.NET Application
public string SearchWord
{
get
{
if (ViewState["SearchWord"] == null)
ViewState["SearchWord"] = string.Empty;
return ViewState["SearchWord"];
}
set
{
ViewState["SearchWord"] = value;
}
}
and I use databind not pageload, this way your usercontrol doesn't load unless you call it.
protected override DataBind()
{
//you can add a condition here if you like
if(SearchWord != string.Empty)
lblSearchWord.Text = SearchWord;
}
to call this from aspx:
usercontrol.SearchWord = "my word";
usercontrol.DataBind();
and thats it..
Related
I have a master page which contains a label for status messages. I need to set the status text from different .aspx pages. How can this be done from the content page?
public partial class Site : System.Web.UI.MasterPage
{
public string StatusNachricht
{
get
{
return lblStatus.Text;
}
set
{
lblStatus.Text = value;
}
}
protected void Page_Load(object sender, EventArgs e)
{
}
}
I have tried this, but was unsuccessful in making it work:
public partial class DatenAendern : System.Web.UI.Page
{
var master = Master as Site;
protected void Page_Load(object sender, EventArgs e)
{
if (master != null)
{
master.setStatusLabel("");
}
}
protected void grdBenutzer_RowCommand(object sender, GridViewCommandEventArgs e)
{
try
{
//some code
if (master != null)
{
master.setStatusLabel("Passwort erfolgreich geändert.");
}
}
catch (Exception ex)
{
if (master != null)
{
master.setStatusLabel("Passwort konnte nicht geändert werden!");
}
}
}
}
}
In the MasterPage.cs file add the property of Label like this:
public string ErrorMessage
{
get
{
return lblMessage.Text;
}
set
{
lblMessage.Text = value;
}
}
On your aspx page, just below the Page Directive add this:
<%# Page Title="" Language="C#" MasterPageFile="Master Path Name"..... %>
<%# MasterType VirtualPath="Master Path Name" %> // Add this
And in your codebehind(aspx.cs) page you can then easily access the Label Property and set its text as required. Like this:
this.Master.ErrorMessage = "Your Error Message here";
In Content page you can access the label and set the text such as
Here 'lblStatus' is the your master page label ID
Label lblMasterStatus = (Label)Master.FindControl("lblStatus");
lblMasterStatus.Text = "Meaasage from content page";
It Works
To find master page controls on Child page
Label lbl_UserName = this.Master.FindControl("lbl_UserName") as Label;
lbl_UserName.Text = txtUsr.Text;
I have a helper method for this in my System.Web.UI.Page class
protected T FindControlFromMaster<T>(string name) where T : Control
{
MasterPage master = this.Master;
while (master != null)
{
T control = master.FindControl(name) as T;
if (control != null)
return control;
master = master.Master;
}
return null;
}
then you can access using below code.
Label lblStatus = FindControlFromMaster<Label>("lblStatus");
if(lblStatus!=null)
lblStatus.Text = "something";
You cannot use var in a field, only on local variables.
But even this won't work:
Site master = Master as Site;
Because you cannot use this in a field and Master as Site is the same as this.Master as Site. So just initialize the field from Page_Init when the page is fully initialized and you can use this:
Site master = null;
protected void Page_Init(object sender, EventArgs e)
{
master = this.Master as Site;
}
This is more complicated if you have a nested MasterPage. You need to first find the content control that contains the nested MasterPage, and then find the control on your nested MasterPage from that.
Crucial bit: Master.Master.
See here: http://forums.asp.net/t/1059255.aspx?Nested+master+pages+and+Master+FindControl
Example:
'Find the content control
Dim ct As ContentPlaceHolder = Me.Master.Master.FindControl("cphMain")
'now find controls inside that content
Dim lbtnSave As LinkButton = ct.FindControl("lbtnSave")
If you are trying to access an html element: this is an HTML Anchor...
My nav bar has items that are not list items (<li>) but rather html anchors (<a>)
See below: (This is the site master)
<nav class="mdl-navigation">
<a class="mdl-navigation__link" href="" runat="server" id="liHome">Home</a>
<a class="mdl-navigation__link" href="" runat="server" id="liDashboard">Dashboard</a>
</nav>
Now in your code behind for another page, for mine, it's the login page...
On PageLoad() define this:
HtmlAnchor lblMasterStatus = (HtmlAnchor)Master.FindControl("liHome");
lblMasterStatus.Visible =false;
HtmlAnchor lblMasterStatus1 = (HtmlAnchor)Master.FindControl("liDashboard");
lblMasterStatus1.Visible = false;
Now we have accessed the site masters controls, and have made them invisible on the login page.
The code worked before I did nothing other than added another variable and a getter to it.
Now everything doesn't work.
The .NET version of all the projects in the solution is the same (4.7).
Screenshot of the error
I cannot run the project anymore as it doesn't start properly (there's an error).
What is going on? This has been happening for months now. The answer I got from my seniors is that it's a matter of the solution being that huge that Visual Studio mishandles it occassionally and thus this error is the resulting mishap. The difference is that this time, restarting Visual Studio/my computer didn't "solve" it. I tried with those restarts after cleaning and rebuilding didn't achieve anything.
Does anyone know what to do?
The code worked before I added <%# GetCssClass %> to the .ascx file. After I added that, everything became broken, and even when I undo adding that, nothing still works.
.ascx
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="EventICTGenerator.ascx.cs" Inherits="CMSApp.CMSWebParts.MyCompany.DetailPages.Event.EventICTGenerator" %>
<%# Register Src="~/CMSWebParts/MyCompany/Controls/ICSCalendarControl.ascx" TagPrefix="uc1" TagName="ICSCalendarControl" %>
<uc1:ICSCalendarControl runat="server" ID="ICSCalendarControl" LinkCssClass='event-header__info-actions-save <%# GetCssClass %>'
ResourceString="MyCompany.event.SaveTheDate"
EventName='<%# EventName %>'
EventLocation='<%# EventLocation %>'
EventAddress='<%# EventAddress %>'
EventStartDate='<%# EventStartDate %>'
EventEndDate='<%# EventEndDate %>'
EventSummary='<%# EventSummary %>' />
<%# Position %>
.ascx.cs
using CMS.DocumentEngine;
using CMS.Helpers;
using CMS.PortalEngine.Web.UI;
using System;
using System.Linq;
namespace CMSApp.CMSWebParts.MyCompany.DetailPages.Event
{
public partial class EventICTGenerator : CMSAbstractWebPart
{
protected string EventName = "";
protected string EventLocation = "";
protected string EventAddress = "";
protected DateTime EventStartDate = DateTime.Now;
protected DateTime EventEndDate = DateTime.Now;
protected string EventSummary = "";
protected int widgetPosition = -1;
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (!StopProcessing)
{
SetupControl();
BindEventData(EventDocumentID);
}
}
private void SetupControl()
{
BindEventData(EventDocumentID);
this.DataBind();
widgetPosition = Position;
}
protected string EventDocumentID
{
get
{
return ValidationHelper.GetString(GetValue("EventID"), string.Empty);
}
}
protected string EventLink
{
get
{
return ValidationHelper.GetString(GetValue("Link"), string.Empty);
}
}
protected int Position
{
get
{
return ValidationHelper.GetInteger(GetValue("Position"), -1);
}
}
protected string GetCssClass
{
get
{
return Position switch
{
1 => "generic-content_align generic-content_align–left",
2 => "generic-content_align generic-content_align–center",
3 => "generic-content_align generic-content_align–right",
_ => "",
};
}
}
protected string EventLinkText
{
get
{
return ValidationHelper.GetString(GetValue("LinkText"), string.Empty);
}
}
private string LinkTextAndUrl()
{
return $"{EventLinkText} <{EventLink}>";
}
private void BindEventData(string documentID)
{
TreeNode item = DocumentHelper.GetDocuments("MyCompany.Event")
.Columns("EventName, LocationName, LocationAddress, ShortDescription, Date, EndDate")
.OnCurrentSite()
.WhereEquals("DocumentID", documentID)
.FirstOrDefault();
if (item != null)
{
string summary = ValidationHelper.GetString(item.GetValue("ShortDescription"), string.Empty);
this.EventName = ValidationHelper.GetString(item.GetValue("EventName"), string.Empty);
this.EventLocation = ValidationHelper.GetString(item.GetValue("LocationName"), string.Empty);
this.EventAddress = ValidationHelper.GetString(item.GetValue("LocationAddress"), string.Empty);
this.EventSummary = $"{summary}\n{LinkTextAndUrl()}";
this.EventStartDate = ValidationHelper.GetDateTime(item.GetValue("Date"), DateTime.Now);
this.EventEndDate = ValidationHelper.GetDateTime(item.GetValue("EndDate"), DateTime.Now);
}
}
}
}
What "solved" was this changing my switch-case.
I inputted it like
switch
{
1 => "generic-content_align generic-content_align–left",
2 => "generic-content_align generic-content_align–center",
3 => "generic-content_align generic-content_align–right",
_ => "",
};
VS was telling me that my switch case was not good, and that's why I changed it to that form to begin with. It then didn't tell me anything's wrong with it or in any way point me to it. -.-
Now that I've changed the way that that switch case is writtern voila, it works.
There a two different navigation menues on a page in their own seperate usercontrols. The menu items in the two menus can navigate to the same pages.
The topmenu has some jQuery animation and the leftmenu has not.
The question is how can I get which anchor tag in a navigation menu made a postback when the anchor tag is in a repeater and the repeater is in a usercontrol(The anchor tags are dynamically created). The problem is that the topmenu usercontrol codebehind runs and sets some values for hiddenfields so the jQuery animation will run properly for the topmenu, but when the leftmenu is clicked it should not run and set the hiddenfields in the topmenu codebehind. So I need to figure out how to differentiate between the two menus.
Here is the repeater markup:
<asp:Repeater runat="server" ID="RightSide">
<HeaderTemplate><ul></HeaderTemplate>
<ItemTemplate>
<li data-type="<%# ((Item)Container.DataItem).HasChildren ? "dropdown" : "link" %>" class="<%# ((Item)Container.DataItem).HasChildren ? "dropdown" : "link" %>">
<a href='<%# GetLink(((Item)Container.DataItem),"MenuLink") %>'><%#((Item)Container.DataItem)["MenuTitle"] %></a>
</li>
</ItemTemplate>
<FooterTemplate></ul></FooterTemplate>
</asp:Repeater>
TopMenu .cs code:
public partial class TopMenu
{
private ID _homeId = new ID("{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}");
protected void Page_Load(object sender, EventArgs e)
{
RightSide.DataSource = GetMultiList("Right side", RootItem);
RightSide.DataBind();
***HERE I NEED TO MAKE THE CHECK.
So the code below should only run if the postback came from the topmenu***
var sectionItem = GetAncestorOrDefault(CurrentItem);
Sitecore.Data.Database context = Sitecore.Context.Database;
Sitecore.Data.Items.Item homeItem = context.GetItem("/sitecore/content/home");
List<Item> items = new List<Item>();
Sitecore.Data.Fields.MultilistField multilistField = homeItem.Fields["Right Side"];
foreach (string id in multilistField)
{
Sitecore.Data.Items.Item multiItem = Sitecore.Context.Database.Items.GetItem(id);
if (multiItem.HasChildren)
{
items.Add(multiItem);
}
}
foreach (Item item in items)
{
if (item.Name.Equals(sectionItem.Name))
{
hiddenAttr.Value = sectionItem.Name;
break;
}
else
{
hiddenAttr.Value = String.Empty;
}
}
}
}
I have tried with eventtarget but it is always null and also with hidden field which value is always "" in the codebehind. I am out of ideas...
I will post more code if needed.
Thanks in advance!
Örvar
You are overwriting all values in postback. Wrap the code in if(!IsPostBack){} for repeater data binding:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
RightSide.DataSource = GetMultiList("Right side", RootItem);
RightSide.DataBind();
}
else
{
// ***HERE I NEED TO MAKE THE CHECK.
// So the code below should only run if the postback came from the topmenu***
var sectionItem = GetAncestorOrDefault(CurrentItem);
Sitecore.Data.Database context = Sitecore.Context.Database;
Sitecore.Data.Items.Item homeItem = context.GetItem("/sitecore/content/home");
List<Item> items = new List<Item>();
Sitecore.Data.Fields.MultilistField multilistField = homeItem.Fields["Right Side"];
foreach (string id in multilistField)
{
Sitecore.Data.Items.Item multiItem = Sitecore.Context.Database.Items.GetItem(id);
if (multiItem.HasChildren)
{
items.Add(multiItem);
}
}
foreach (Item item in items)
{
if (item.Name.Equals(sectionItem.Name))
{
hiddenAttr.Value = sectionItem.Name;
break;
}
else
{
hiddenAttr.Value = String.Empty;
}
}
}
}
Also I would suggest using a query parameter in tag. If the href is
"/MyContent/MyPgae1"
you can change it to
"/MyContent/MyPgae1?s=r"
and in the postback :
if (!IsPostBack)
{
RightSide.DataSource = GetMultiList("Right side", RootItem);
RightSide.DataBind();
}
else
{
if(Request.QueryString["s"] == "r")
{
//request is from rightmenu
}
I have a search textbox situated on a masterpage like so:
<asp:TextBox ID="frmSearch" runat="server" CssClass="searchbox"></asp:TextBox>
<asp:LinkButton ID="searchGo" PostBackUrl="search.aspx" runat="server">GO</asp:LinkButton>
The code behind for the search page has the following to pick up the textbox value (snippet):
if (PreviousPage != null && PreviousPage.IsCrossPagePostBack)
{
Page previousPage = PreviousPage;
TextBox tbSearch = (TextBox)PreviousPage.Master.FindControl("frmSearch");
searchValue.Text = tbSearch.Text;
//more code here...
}
All works great. BUT not if you enter a value whilst actually on search.aspx, which obviously isn't a previous page. How can I get round this dead end I've put myself in?
If you use the #MasterType in the page directive, then you will have a strongly-typed master page, meaning you can access exposed properties, controls, et cetera, without the need the do lookups:
<%# MasterType VirtualPath="MasterSourceType.master" %>
searchValue.Text = PreviousPage.Master.frmSearch.Text;
EDIT: In order to help stretch your imagination a little, consider an extremely simple property exposed by the master page:
public string SearchQuery
{
get { return frmSearch.Text; }
set { frmSearch.Text = value; }
}
Then, through no stroke of ingenuity whatsoever, it can be seen that we can access it like so:
searchValue.Text = PreviousPage.Master.SearchQuery;
Or,
PreviousPage.Master.SearchQuery = "a query";
Here is a solution (but I guess its old now):
{
if (PreviousPage == null)
{
TextBox tbSearch = (TextBox)Master.FindControl("txtSearch");
searchValue.Value = tbSearch.Text;
}
else
{
TextBox tbSearch = (TextBox)PreviousPage.Master.FindControl("txtSearch");
searchValue.Value = tbSearch.Text;
}
}
I have in many places in my ASP.NET project used the Session variable for storing data. I usually write something like this:
public uint MyPropery
{
get
{
object o = Session["MyProperty"];
if (o != null)
return (uint)o;
else
return 0;
}
set
{
Session["MyProperty"] = value;
}
}
However, this time I get a NullReferenceException in the setter. As far as I know, it is valid to assign the Session variable in the manner above. Also, Session is not null and neither is value.
Any ideas on this?
Edit:
Adding the code for the UserControl in which the property exists. I am using ext.net but that shouldn't have anything to do with this. One thought that crossed my mind:
The UserControl (seen below) is added dynamically in code-behind of a page. Can that have anything to do with it?
I am adding UserControls like this (on a Page):
foreach(CoreCommons.System.Comment c in cg.Reply_Comments)
{
WebApplicationExtNetTest.Secure.UserControls.CoreComment cc = new UserControls.CoreComment();
cc._Comment = c; // here is where i get the NullRef
this.Panel1.ContentControls.Add(cc);
}
Markup:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="CoreComment.ascx.cs" Inherits="WebApplicationExtNetTest.Secure.UserControls.CoreComment" %>
<%# Register Assembly="Ext.Net" Namespace="Ext.Net" TagPrefix="ext" %>
<ext:Panel runat="server" ID="CoreCommentOuterPanel" BodyStyle="background: #FFFDDE">
<Items>
<ext:ColumnLayout runat="server">
<Columns>
<ext:LayoutColumn ColumnWidth="0.8">
<ext:Image runat="server" ImageUrl="/Resources/bullet_triangle_green_16x16.png" Align="AbsMiddle"></ext:Image>
<ext:Label runat="server" ID="lblCommentInfo"></ext:Label>
</ext:LayoutColumn>
<ext:LayoutColumn ColumnWidth="0.2"><ext:Button runat="server" ID="btnDelete" Icon="Delete"></ext:Button></ext:LayoutColumn>
</Columns>
</ext:ColumnLayout>
<ext:Label runat="server" ID="lblComment"></ext:Label>
</Items>
</ext:Panel>
Code-behind:
namespace WebApplicationExtNetTest.Secure.UserControls
{
public partial class CoreComment : System.Web.UI.UserControl
{
public CoreCommons.System.Comment _Comment
{
get
{
object o = Session["CoreComment_ObjectId"];
if (o != null)
return (tWorks.Core.CoreCommons.System.Comment)o;
else
return null;
}
set
{
Session["CoreComment_ObjectId"] = value;
SetComment();
}
}
protected void Page_Load(object sender, EventArgs e)
{
}
private void SetComment()
{
if (_Comment == null)
{
lblCommentInfo.Text = "";
lblComment.Text = "";
}
else
{
lblCommentInfo.Text = _Comment.Author + ", " + _Comment.TimeStamp.ToString("g");
lblComment.Text = _Comment.Text;
}
}
}
}
I'm almost completely sure the NullReferenceException is thrown in SetComment() because none of the CoreComment's child controls (lblComment, lblCommentInfo) are properly instantiated at the point you set the _Comment property.
The reason these child controls are not instantiated is indeed the way you currently add the CoreComment controls. For dynamically adding UserControls, you must use Page.LoadControl() (see: here) to create a new instance of the control, as it does some behind-the-scenes magic to ensure it is properly initialized, which includes the instantiation of the child controls.
On a sidenote, personally I'd change SetComment() to SetComment(CoreCommons.System.Comment comment) and use the parameter instead of repeatedly calling the getter, or, if staying with the original, at least call the getter only once and store the result in a local variable. With what I assume is probably InProc session storage it won't make much of a difference, but in any other storage mode you'd repeatedly deserialize the Comment object for no reason.
You need to use the Page.LoadControl() method instead , please look here
BTW:the problem is in adding the control programatically with that way.
Use:
return Session["MyProperty"] as uint? ?? 0;
and post somewhere full exception stack trace with inner exception(s)