In a c# code behind of a user control, how can i make the control invisible based on the value of a public property?
Let's say my user control is like so and contains content:
<Ctrl:ComponentChecker ID="ComponentChecker" runat="server" MakeInvisible="Yes">
<p>This is my content...</p>
</Ctrl:ComponentChecker>
My code behind is something like this:
public class ComponentChecker : AbstractController
{
public string MakeInvisible { get; set; }
protected override void OnPreRender(EventArgs e)
{
if (MakeInvisible != null && !string.IsNullOrEmpty(MakeInvisible) && MakeInvisible == "Yes")
{
//Hide the user control
}
}
}
Any ideas where I'm going wrong? I need to inherit from AbstractController for some other logic. After some reading online, inheriting from Placeholder and then this.Visible = false does the trick but I can't do that in my case.
Related
We've got custom PopupContainerEdit that inherits from DevExpress'es PopupContainerEdit. One of our custom features is another dropdown button (EditorButton with kind = ButtonPredefines.Glyph) that acts like the default one except, it opens different PopupContainerControl. Everything works as intended except button's style coloring. The button acts like default button - that means it doesn't support state coloring (checked/unchecked) when dropdown is visible/hidden. I couldn't find any custom draw event/method for EditorButton.
Is it possible to achieve such behaviour? If so, how?
#edit
Simple example of the above situation.
Default PopupContainerEdit looks like image A. When you click on the
button (triangle like), dropdown shows and button goes into checked
state.
Our PopupContainerEdit (that inherits from default) looks like
B.
C, D is coloring example when you hover the button.
E is checked state coloring for default button (it works like that by
DevExpress'es design).
F is our button behaviour - acts like normal button.
G is what we want - checked state coloring for our button
Our approach to create custom button:
string TheToolTipText = "The text";
string OurButtonTag = "TheButton";
Image TheIcon = new Image(); // just example ...
EditorButton customButton = new EditorButton();
customButton.Width = 16;
customButton.Image = TheIcon;
customButton.ToolTip = TheToolTipText;
customButton.Tag = OurButtonTag;
customButton.Kind = ButtonPredefines.Glyph;
this.Properties.Buttons.Add(customButton);
To be honest there's nothing more to show. We're not aware of any custom Draw event or similar things.
There are two properties in RepositoryItemPopupContainerEdit that are responsible for this behavior. Fisrt one is RepositoryItemPopupBase.ActionButtonIndex property. It's value specifying which editor button will open the editor's dropdown window. The second one is RepositoryItemPopupContainerEdit.PopupControl which sets the control to display in the popup window. So, by manipulating with this two properties, you can achieve the desired behavior.
Here is example:
0. RepositoryItemPopupContainerEdit descendant
Because you need to show two different PopupContainerControl
you can create additional properties for each of your controls in your custom RepositoryItem.
public class RepositoryItemCustomEdit1 : RepositoryItemPopupContainerEdit
{
#region Some default stuff for custom repository item (constructors, registration, etc).
static RepositoryItemCustomEdit1() { RegisterCustomEdit1(); }
public const string CustomEditName = "CustomEdit1";
public RepositoryItemCustomEdit1() { }
public override string EditorTypeName { get { return CustomEditName; } }
public static void RegisterCustomEdit1()
{
Image img = null;
EditorRegistrationInfo.Default.Editors.Add(new EditorClassInfo(
CustomEditName,
typeof(CustomEdit1),
typeof(RepositoryItemCustomEdit1),
//For v13.2 you need to use custom ViewInfo class. So, here is CustomEdit1ViewInfo.
//For v15.1 you can use the base PopupContainerEditViewInfo.
typeof(CustomEdit1ViewInfo),
new ButtonEditPainter(),
true,
img));
}
#endregion
#region Hide base PopupContainerControl properties in designer.
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override PopupContainerControl PopupControl
{
get { return base.PopupControl; }
set { base.PopupControl = value; }
}
[Browsable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override int ActionButtonIndex
{
get { return base.ActionButtonIndex; }
set { base.ActionButtonIndex = value; }
}
#region
#region First PopupContainerControl properties
public int DefaultActionButtonIndex { get; set; }
public PopupContainerControl DefaultPopupControl { get; set; }
#endregion
#region Another PopupContainerControl properties
public int DifferentActionButtonIndex { get; set; }
public PopupContainerControl DifferentPopupControl { get; set; }
#endregion
public override void Assign(RepositoryItem item)
{
BeginUpdate();
try
{
base.Assign(item);
RepositoryItemCustomEdit1 source = item as RepositoryItemCustomEdit1;
if (source == null) return;
DefaultActionButtonIndex = source.DefaultActionButtonIndex;
DefaultPopupControl = source.DefaultPopupControl;
DifferentPopupControl = source.DifferentPopupControl;
DifferentActionButtonIndex = source.DifferentActionButtonIndex;
}
finally
{
EndUpdate();
}
}
}
You can see new properties in your designer:
1. PopupContainerEdit descendant
Now you can use this properties in your custom Edit class.
public class CustomEdit1 : PopupContainerEdit
{
#region Some default stuff for custom edit (constructors, registration, etc).
static CustomEdit1() { RepositoryItemCustomEdit1.RegisterCustomEdit1(); }
public CustomEdit1() { }
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public new RepositoryItemCustomEdit1 Properties { get { return base.Properties as RepositoryItemCustomEdit1; } }
public override string EditorTypeName { get { return RepositoryItemCustomEdit1.CustomEditName; } }
#endregion
protected override bool IsActionButton(EditorButtonObjectInfoArgs buttonInfo)
{
int buttonIndex = Properties.Buttons.IndexOf(buttonInfo.Button);
if (buttonIndex == Properties.DefaultActionButtonIndex ||
buttonIndex == Properties.DifferentActionButtonIndex)
{
//Set the Properties.ActionButtonIndex value according to which button is pressed:
Properties.ActionButtonIndex = buttonIndex;
//Set the Properties.PopupControl according to which button is pressed:
if (buttonIndex == Properties.DefaultActionButtonIndex)
Properties.PopupControl = Properties.DefaultPopupControl;
else
Properties.PopupControl = Properties.DifferentPopupControl;
return true;
}
return false;
}
}
2. PopupContainerEditViewInfo descendant
For v13.2 you need to use custom ViewInfo class for your editor:
public class CustomEdit1ViewInfo : PopupContainerEditViewInfo
{
public CustomEdit1ViewInfo(RepositoryItem item) : base(item) { }
public new RepositoryItemPopupBase Item { get { return base.Item as RepositoryItemCustomEdit1; } }
//Show the pressed state when button is pressed or when popup is open.
protected override bool IsButtonPressed(EditorButtonObjectInfoArgs info)
{
var hitObject = PressedInfo.HitObject as EditorButtonObjectInfoArgs;
return
(hitObject != null && hitObject.Button == info.Button) ||
(IsPopupOpen && Item.ActionButtonIndex == info.Button.Index);
}
}
Result
In the result you will get something like this:
and
I am trying to render a Wizard control to a HTML string on the click of a Button (using Control.Render). I am already disabling event validation with the following, which works fine and enables me to render the entire Page to the string. I do this within the user control that contains the Wizard:
protected void Page_Init(object sender, EventArgs e)
{
if (Request.Form["__EVENTTARGET"] != null
&& Request.Form["__EVENTTARGET"] == btnPrint.ClientID.Replace("_", "$"))
{
Page.EnableEventValidation = false;
}
}
While this works, I'd like to render the Wizard control on its own. I understand that I can override Page.VerifyRenderingInServerForm in order to prevent the page from throwing an exception when I attempt to render this control on its own (without runat="server" form tags), like so:
public override void VerifyRenderingInServerForm(Control control)
{
// base.VerifyRenderingInServerForm(control);
}
However, I don't want to override this completely. Is there a way I can bypass this dynamically, either:
For the specific PostBack in which the button in question is clicked, or...
Specifically for the Wizard control?
How about something like:
public override void VerifyRenderingInServerForm(Control control)
{
if (!SkipVerifyRenderingInServerForm)
{
base.VerifyRenderingInServerForm(control);
}
}
public bool SkipVerifyRenderingInServerForm
{
get
{
object o = HttpContext.Current.Items["SkipVerifyRenderingInServerForm"];
return (o == null) ? false : (bool) o;
}
set
{
HttpContext.Current.Items["SkipVerifyRenderingInServerForm"] = value;
}
}
You could then set SkipVerifyRenderingInServerForm to true in your button click event handler.
I'm struggling to bubble an event correctly.
I have a master page with a user control, and a page that is a child of the master page.
The user control and the page share common data, so when the user control updates, it updates the apage and vice versa.
The user control exposed an event to the master page. This is the format I use.
outside of class:
public delegate void OfferBookmarkRemoved(int OfferID);
inside class:
public event OfferBookmarkRemoved OfferBookmarkRemoved;
protected void LV_Bookmarks_ItemCommand(object source, ListViewCommandEventArgs e)
{
if (e.CommandName == "RemoveOffer")
{
var offerId = (int)e.CommandArgument;
OnOfferBookmarkRemoved(offerId);
}
}
void OnOfferBookmarkRemoved(int offerId)
{
offerId.ThrowDefault("offerId");
if (OfferBookmarkRemoved != null)
{
OfferBookmarkRemoved(offerId);
}
}
Now this can be used in the master page ok. I don't do anything in the master page and want to expose the event so that the aspx page can use it, like this:
Master.OfferBookmarkRemoved += OnBookmarkRemoved;
void OnBookmarkRemoved(int offerId)
{
offerId.ThrowDefault("offerId");
OfferList1.UpdateBookmark(offerId);
}
So the missing bit is to listen for the event in the master and make it available to the page.
Can anyone help?
You need to define this event in the master page also like that:
public event EventHandler<OfferEventArgs> OfferBookmarkRemoved
{
add
{
userControl.OfferBookmarkRemoved += value;
}
remove
{
userControl.OfferBookmarkRemoved -= value;
}
}
This way any page that registers to the master event will be registered to the usercontrol event.
By the way, you are not following the event pattern. Your event should look like:
public class OfferEventArgs : EventArgs
{
public int OfferID { get; set; }
}
public event EventHandler<OfferEventArgs> OfferBookmarkRemoved;
and when invoked:
OfferBookmarkRemoved(new OfferEventArgs() { OfferID = offerId });
If I pass the derived class testA a PlaceHolder that contains a Hyperlink, with a url that starts with
a tilde, it resolves it correctly.
However, when I pass testB
(identical apart from it inherits from
System.Web.UI.UserControl) the same PlaceHolder It
renders it literally (doesn't
transform / resolve the '~')
Any ideas?
public class testA : System.Web.UI.Control
{
public System.Web.UI.WebControls.PlaceHolder plc { get; set; }
protected override void OnLoad(EventArgs e)
{
if (plc != null)
this.Controls.Add(plc);
base.OnLoad(e);
}
}
public class testB : System.Web.UI.UserControl
{
public System.Web.UI.WebControls.PlaceHolder plc { get; set; }
protected override void OnLoad(EventArgs e)
{
if (plc != null)
this.Controls.Add(plc);
base.OnLoad(e);
}
}
This is ASP.NET
When you inherit from System.Web.UI.UserControl and do not associate your control with an ascx file then your control TemplateSourceVirtualDirectory will not be set, this is required by the ResolveClientUrl method - if its null or empty the url will be returned AS IS.
To solve your problem, just set AppRelativeTemplateSourceDirectory :
public class testB : System.Web.UI.UserControl
{
public System.Web.UI.WebControls.PlaceHolder plc { get; set; }
protected override void OnLoad(EventArgs e)
{
if (plc != null)
{
this.AppRelativeTemplateSourceDirectory =
plc.AppRelativeTemplateSourceDirectory;
this.Controls.Add(plc);
}
base.OnLoad(e);
}
}
A UserControl is normally associated with an ascx file that defines its markup. Such controls should be instantiated using TemplateControl.LoadControl() before they're added to the page, in order to perform event catch-up.
I suspect that event catch-up does not take place since you don't call LoadControl(), so the Hyperlink's NavigateUrl never gets a chance to be properly resolved.
A Server based control is not good solution for me, since my panel should by default always contain a asp checkbox which will allow the user to hide and show the panels content.
I created my Panel as a templated user control but now I have the problem that I cannot declare variables in it.
[ParseChildren(true)]
public partial class MyPanel: System.Web.UI.UserControl
{
private ITemplate messageTemplate = null;
[TemplateContainer(typeof(MessageContainer))]
[PersistenceMode(PersistenceMode.InnerProperty)]
public ITemplate Content
{
get
{
return messageTemplate;
}
set
{
messageTemplate = value;
}
}
void Page_Init()
{
MessageContainer container = new MessageContainer();
messageTemplate.InstantiateIn(container);
PlaceHolder1.Controls.Add(container);
}
[ParseChildren(true)]
public class MessageContainer : Control, INamingContainer
{
internal MessageContainer()
{
}
}
}
If I do the following in MyPage.aspx then the control definitions are not inserted into MyPage.aspx.designer.cs a they do normally:
<my:MyPanel>
<Content>
<asp:TextBox id = "foo" runat="server" />
</Content>
</my:MyPanel>
Therefore foo is not created as control variable by the designer, so I have no access to it.
How can I create my own Panel which allows declaration of controls in it?
EDIT:
I now tried with [ParseChildren(false)]. Variables for contained variables are now generated in the designer code of the form. The problem is now that messageTemplate.InstantiateIn(container) throws an exception.
You haven't given code for the control. In general, it needs to implement INamingContainer and should have properties of type ITemplate to accept templates.
Check on MSDN on how to develop one. And here's the sample code from MSDN. Also check this article for data bound templated control.
First of all, you need to use the runat="server" attribute.
<asp:TextBox id = "foo" runat="server"/>
Afterwards you can try
var textbox = this.MyCustomPanel.FindControl("foo") as TextBox;
Instead of using FindControl I guess it is possible to achieve this behaviour by setting an attribute on the designer settings of the INamingTemplate Container of your Usercontrol
You don't need to create a templated control, just create a Composite Web Control. Create a Panel & Checkbox, add them to the control collection of the composite control, adjust the rendering to display it as you want, and run with it.
look here
* EDIT **
Here is a working implementation of what you need. Make to create a reference for the Web.dll.
CustomPanel.cs
using System;
using System.ComponentModel;
using System.Drawing;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Web
{
[ AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal),
AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal),
ToolboxData("<{0}:CustomPanel runat=\"server\"> </{0}:CustomPanel>"),
]
public class CustomPanel : CompositeControl
{
private Panel panelContainer;
private CheckBox chkHideContent;
private Panel panelInnerContainer;
[Bindable(true),
Category("Appearance"),
DefaultValue(""),
Description("The text to display with the checkbox.")]
public string CheckBoxText
{
get
{
EnsureChildControls();
return chkHideContent.Text;
}
set
{
EnsureChildControls();
chkHideContent.Text = value;
}
}
[Bindable(true)]
[Category("Data")]
[DefaultValue("")]
[Localizable(true)]
public bool IsCheckBoxChecked
{
get
{
return chkHideContent.Checked;
}
}
[Bindable(true)]
[Category("Data")]
[DefaultValue("")]
[Localizable(true)]
public bool HideInnerPanel
{
set
{
EnsureChildControls();
panelInnerContainer.Visible = value;
}
}
[Bindable(true)]
[Category("Data")]
[DefaultValue("")]
[Localizable(true)]
public ControlCollection InnerPanelControls
{
get
{
EnsureChildControls();
return panelInnerContainer.Controls;
}
}
protected virtual void OnCheckboxChanged(EventArgs e)
{
if (chkHideContent.Checked)
{
panelInnerContainer.Visible = false;
}
else
{
panelInnerContainer.Visible = true;
}
}
private void _checkbox_checkChanged(object sender, EventArgs e)
{
OnCheckboxChanged(EventArgs.Empty);
}
protected override void RecreateChildControls()
{
EnsureChildControls();
}
protected override void CreateChildControls()
{
Controls.Clear();
panelContainer = new Panel();
panelContainer.ID = "panelContainer";
chkHideContent = new CheckBox();
chkHideContent.ID = "chkHideContent";
chkHideContent.CheckedChanged += new EventHandler(_checkbox_checkChanged);
chkHideContent.AutoPostBack = true;
panelInnerContainer = new Panel();
panelInnerContainer.ID = "panelInnerContainer";
this.Controls.Add(panelContainer);
this.Controls.Add(chkHideContent);
this.Controls.Add(panelInnerContainer);
}
protected override void Render(HtmlTextWriter writer)
{
panelContainer.RenderBeginTag(writer);
chkHideContent.RenderControl(writer);
panelInnerContainer.RenderControl(writer);
panelContainer.RenderEndTag(writer);
}
}
}
Default.aspx
<%# Register assembly="Web" namespace="Web" tagprefix="cc1" %>
<cc1:CustomPanel ID="CustomPanel1" runat="server" />
Default.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
Label lbl = new Label();
lbl.Text = "IT WORKS!";
CustomPanel1.CheckBoxText = "Hide my innards!";
CustomPanel1.InnerPanelControls.Add(lbl);
}