Is there a way to access page controls from user control . I have some controls in my page and i want to access these controls from the user control .
YourControlType ltMetaTags = null;
Control ctl = this.Parent;
while (true)
{
ltMetaTags = (ControlType)ctl.FindControl("ControlName");
if (ltMetaTags == null)
{
ctl = ctl.Parent;
if(ctl.Parent == null)
{
return;
}
continue;
}
break;
}
Example
System.Web.UI.WebControls.Literal ltMetaTags = null;
Control ctl = this.Parent;
while (true)
{
ltMetaTags = (System.Web.UI.WebControls.Literal)ctl.FindControl("ltMetaTags");
if (ltMetaTags == null)
{
if(ctl.Parent == null)
{
return;
}
ctl = ctl.Parent;
continue;
}
break;
}
There are actually several ways to accomplish this:
Create a public property in your user control
public Button PageButton { get; set; }
Then assign it in the page's OnInit or OnLoad method
myUserControl.PageButton = myPageButton;
You can make the control public and unbox Page:
public Button PageButton { get { return this.myPageButton; } }
In the user control:
MyPage myPage = (MyPage)this.Page;
myPage.PageButton.Text = "Hello";
The slowest, but easiest way would be to use FindControl:
this.Page.FindControl("myPageButton");
Parent.FindControl("hdnValue")
its work for me :
I declare Label in My .aspx page
<asp:Label ID="lblpage" runat="server" Text="this is my page"></asp:Label>
<asp:Panel ID="pnlUC" runat="server"></asp:Panel>
In .aspx.cs I have add UserControl through Panel
UserControl objControl = (UserControl)Page.LoadControl("~/ts1.ascx");
pnlUC.Controls.Add(objControl);
and access from in .ascx UserControl like this :
Page page = this.Page;
Label lbl = page.FindControl("lblpage") as Label;
string textval = lbl.Text;
Related
I'm a newbie and I decided to enhance my program's GUI using Krypton Toolkit.
I was able to load it into my project.
The issue that I have created a control with name mycontrol which have a KryptonDataGridView with name mydatagrid.
In my form, I have the following code:
public partial class Form1 : KryptonForm
{
private KryptonPage[] mycontrolpage;
private Control mycontrolcontent;
public Form1()
{
InitializeComponent();
}
private KryptonPage NewmycontrolPage()
{
mycontrolcontent = new mycontrol();
KryptonPage page = new KryptonPage("mypage", null, "OS mypage");
// Add the control for display inside the page
mycontrolcontent.Dock = DockStyle.Fill;
page.Controls.Add(mycontrolcontent);
// Document pages cannot be docked or auto hidden
page.ClearFlags(KryptonPageFlags.DockingAllowAutoHidden | KryptonPageFlags.DockingAllowDocked);
return page;
}
private void Form1_Load(object sender, EventArgs e)
{
// Setup docking functionality
KryptonDockingWorkspace w = kryptonDockingManager.ManageWorkspace(kryptonDockableWorkspace);
kryptonDockingManager.ManageControl(kryptonPanel, w);
kryptonDockingManager.ManageFloating(this);
mycontrolpage = new KryptonPage[] { NewmycontrolPage() };
kryptonDockingManager.AddToWorkspace("Workspace", mycontrolpage);
}
}
My problem is how to access the grid in mycontrol?
Without some code, You could always view the Examples..
Or
Some code snippets:
internal ComponentFactory.Krypton.Toolkit.KryptonDataGridView dgvRules;
Then...
int offset = dgvRules.Rows.Add((bool)condition, name, description, applied);
KryptonDataGridViewCheckBoxCell dataGridViewCell = dgvRules.Rows[offset].Cells[0] as KryptonDataGridViewCheckBoxCell;
if (condition == Tribool.Unknown
|| accumulationRules[offset] == Tribool.Unknown)
{
dataGridViewCell.ReadOnly = condition == Tribool.Unknown;
dataGridViewCell.ThreeState = true;
dataGridViewCell.Value = CheckState.Indeterminate;
}
else
{
dataGridViewCell.Value = (CheckState)accumulationRules[offset];
}
So my program is generating a bunch of buttons like so:
foreach (var subdir in dir.GetDirectories()) {
var path = subdir.Name;
var button = new Button {
Text = getFlavor(path) + "\t(" + path + ")",
Width = Width,
Height = 35,
Top = y
};
button.Click += buttonClick;
Controls.Add(button);
if (button.Text.Contains("Kittens")
i++;
}
I want to try something like this
if (i == 1) {
[Button.ThatContains("Kitten)].Click;
}
"ThatContains" is not a real method. How do I get references to buttons I've created programmatically ?
You could use OfType<Button> to find all buttons in the container control where you've added them(f.e. a Panel). Then a liitle bit LINQ power gives you the correct button(s):
var kittenButtons = panel.Controls.OfType<Button>()
.Where(btn => btn.Text.Contains("Kittens"));
foreach(Button btn in kittenButtons)
btn.PerformClick();
If you just want to click the first:
Button kittenButton = panel.Controls.OfType<Button>()
.FirstOrDefault(btn => btn.Text.Contains("Kittens"));
if(kittenButton != null)
kittenButton.PerformClick();
For what it's worth, here is also an extension method that returns controls recursively via deferred execution which allows to use only the first found Buttton or consume all down the road:
public static IEnumerable<T> GetChildControlsRecursive<T>(this Control root) where T : Control
{
if (root == null) throw new ArgumentNullException("root");
var stack = new Stack<Control>();
stack.Push(root);
while (stack.Count > 0)
{
Control parent = stack.Pop();
foreach (Control child in parent.Controls)
{
if (child is T)
yield return (T)child;
stack.Push(child);
}
}
yield break;
}
Now you can use similar code as above to get for example the first matching button or all:
var kittenButtons = this.GetChildControlsRecursive<Button>()
.Where(b => b.Text.Contains("Kittens"));
// search just until the first button is found
Button firstKittenButton = kittenButtons.FirstOrDefault();
if(firstKittenButton != null) firstKittenButton.PerformClick;
// loop all
foreach(Button btn in kittenButtons)
btn.PerformClick();
Either create a subclass of Button to store the information you want and instantiate that instead or use the Tag property
public class MyButton : Button
{
public int ButtonID { get; set; }
}
public class MyApplication
{
public void DoSomething()
{
int i; // todo: loop stuff
var button = new MyButton
{
Text = getFlavor(path) + "\t(" + path + ")",
Width = Width,
Height = 35,
Top = y,
ButtonID = i
};
}
}
Or why not cast the sender parameter of the button click event as a Button and check the text?
public class MyApplication
{
public void DoSomething()
{
var b = new Button();
b.Click += b_Click;
}
public void b_Click(object sender, EventArgs e)
{
Button b = (Button)sender;
switch (b.Text) {
case "Kittens":
return;
default:
return;
}
}
}
Something like this
var button = FirstOrDefault(y => y is Button && y.Text.Contains("Kittens"));
if(button != null)
button.PerformClick();
In order to get the references, you may need to what you would do with getting references of any other type - store them somewhere, which does not seem to be the case here at all. Normally, you would register your buttons for interaction from a user by attaching them to a Form. Assuming you're not doing this by the looks of your sample code, I'm going to recommend storing them into a Dictionary<string, Button>.
You could use a dictionary or you could use a simple recursive loop (in case you are sticking the buttons into different containers).
private bool ClickButton(string buttonName, Control control) {
if (control is Button && control.Text.Contains(buttonName) {
((Button)control)PerformClick();
return true;
}
if (control.HasChildren) {
foreach (Control childControl in control.Controls) {
if (ClickButton(buttonName, childControl)) {
return true;
}
}
}
return false;
}
Usage: ClickButton("Kittens", this);
Or you could use a dictionary, as some have suggested.
private Dictionary<string, Button> DynamicButtons = new Dictionary<string, Button>();
private void ClickDictionaryButton(string buttonName) {
var matches = DynamicButtons.Where(x => x.Key.Contains(buttonName));
foreach (var match in matches) {
match.Value.PerformClick();
}
}
Usage: ClickDictionaryButton("Kittens", this);
I have created a custom gridview control that inherits the asp.net gridview. I am required to use item templates in this gridview. I create a method in my custom gridview that generates the item template.
public void addTemplateField(Control headerTemplateControl, Control itemTemplateControl, EventHandler bindHandler, EventHandler initHandler, string headerText, string sortExpression, bool isVisible, int? heightPx, int? widthPercent)
{
TemplateField tField = new TemplateField();
if (headerTemplateControl != null)
tField.HeaderTemplate = new GridViewTemplate(ListItemType.Header, headerTemplateControl);
if (bindHandler != null && initHandler != null)
tField.ItemTemplate = new GridViewTemplate(ListItemType.Item, itemTemplateControl, bindHandler, initHandler);
else if (bindHandler != null)
tField.ItemTemplate = new GridViewTemplate(ListItemType.Item, itemTemplateControl, bindHandler, false);
else if (initHandler != null)
tField.ItemTemplate = new GridViewTemplate(ListItemType.Item, itemTemplateControl, initHandler, true);
else
tField.ItemTemplate = new GridViewTemplate(ListItemType.Item, itemTemplateControl);
if (sortExpression != null)
tField.SortExpression = sortExpression;
tField.Visible = isVisible;
if (headerText != null)
tField.HeaderText = headerText;
if (heightPx.HasValue)
tField.HeaderStyle.Height = new Unit(heightPx.Value, UnitType.Pixel);
if (widthPercent.HasValue)
tField.HeaderStyle.Height = new Unit(widthPercent.Value, UnitType.Percentage);
addColumnField(tField);
}
And this is how I have implemented ITemplate
public class GridViewTemplate : ITemplate
{
int _controlCount = 0;
ListItemType _templateType;
EventHandler _bindHandler;
EventHandler _initHandler;
Control _control;
public GridViewTemplate(ListItemType type, Control control)
{
this._templateType = type;
this._control = control;
}
public GridViewTemplate(ListItemType type, Control control, EventHandler Handler, bool isInitHandler)
{
this._templateType = type;
this._control = control;
if (isInitHandler)
this._initHandler = Handler;
else
this._bindHandler = Handler;
}
public GridViewTemplate(ListItemType type, Control control, EventHandler bindHandler, EventHandler initHandler)
{
this._templateType = type;
this._control = control;
this._bindHandler = bindHandler;
this._initHandler = initHandler;
}
public Control Copy(Control ctrlSource)
{
Type _type = ctrlSource.GetType();
Control ctrlDest = (Control)Activator.CreateInstance(_type);
foreach (PropertyInfo prop in _type.GetProperties())
{
if (prop.CanWrite)
{
if (prop.Name == "ID")
{
ctrlDest.ID = ctrlSource.ID + "_copy_" + _controlCount;
}
else
{
prop.SetValue(ctrlDest, prop.GetValue(ctrlSource, null), null);
}
}
}
_controlCount++;
return ctrlDest;
}
public void InstantiateIn(Control container)
{
switch (_templateType)
{
case ListItemType.Header:
container.Controls.Add(_control);
break;
case ListItemType.Item:
Control temp = Copy(_control);
if(_bindHandler != null)
temp.DataBinding += _bindHandler;
if (_initHandler != null)
temp.Init += _initHandler;
container.Controls.Add(temp);
break;
}
}
}
In the page that needs say Default.aspx.cs, I create this gridview onPreInit and attach its event handlers onInit.
I add a checkbox to the grid by calling the addTemplateField().
cbl = new CheckBox();
cbl.AutoPostBack = true;
init = new EventHandler(cbl_Init);
grd.addTemplateField(null, cbl, null, init, "SERVER", null, true, 20, 20);
void cbl_Init(object sender, EventArgs e)
{
CheckBox c = (CheckBox)sender;
c.CheckedChanged +=new EventHandler(cbl_CheckedChanged);
}
void cbl_CheckedChanged(object sender, EventArgs e)
{
// Modify datasource
// databind();
// if i remove this databind, checkchanged is handled every time. If i keep the databind, event is handled only alternate times.
}
The issue is the checkbox checkchanged event is fired for alternate times. Every other time, the page post backs but the checkchanged event is not handled. I am lost in finding the cause, let alone the solution.!?!?!
I found the root cause of the problem. It was in the Copy method of the gridviewtemplate class. The problem being for each postback, the controls generated were being done in a unique id. So on postback the event triggered by the control, had changed its id, so no event was triggered.
To be more crystal...
Page loads initially with controls having a unique id,
Click on the control to trigger an event
The page post backs with the controls being generated with the same id.
Click on the control to trigger the event.
The page posts back, but the controls are generated with a different it that does not match the event source of step 4.
Solution was to remove the control count variable.
I have a user control with multiple pictureboxes and labels on them.
I need to put each Label (lb) on his own Picturebox (pbParent), and the label Backcolor must be transparent to improve PictureBox Image visibility under this picture box.
Picture boxes are named TabFrame0 to TabFrameN, and the Labels are named Label0 to LabelN.
I have a function GetLabelByTag that must return the label searched by its name. It works fine until I make the Label's parent the PictureBox (see row 8). So, my questions is: how do I find the label if it's parent become a pictureBox, not my UserControl, which collection do contain it?
void CreateControls()
{
...
newLabel.Name = TAB_PIC_BOX_LABEL_NAME + _id.ToString(); //1
newLabel.Text = _text;//2
newLabel.Tag = _id;//3
newLabel.AutoSize = true;//4
Controls.Add(newLabel);//5
Label lb = GetLabelByTag(_id, TAB_PIC_BOX_LABEL_NAME);//6
PictureBox pbParent = GetPicBoxByTag(_id, TAB_PIC_BOX_CONTROL_NAME);//7
lb.Parent=pbParent;//8
lb.BringToFront();//9
...
}
...
Label GetLabelByTag(int _tag, string _family)
{
Label rez = new Label();
foreach (Control lb in Controls)
{
if (lb.Tag != null)
{
if (((int)lb.Tag == _tag) && (lb.Name == _family + _tag.ToString()))
{
rez = (Label)lb;
}
}
}
return rez;
}
You need to recursively iterate the children's children if there are any. E.g. like this:
Label GetLabelByTag(int _tag, string _family)
{
return FindLabelByTag(_tag, _family, this);
}
Label FindLabelByTag(int _tag, string _family, Control _control)
{
Label rez = null;
foreach (Control lb in _control.Controls)
{
if (lb.Tag != null)
{
if (((int)lb.Tag == _tag) && (lb.Name == _family + _tag.ToString()))
{
return (Label)lb;
}
}
var inControl = FindLabelByTag(_tag, _family, lb);
if (inControl != null)
return inControl;
}
return null;
}
I have a Custom WebControl. Inside this control I add a button and I want it to access an EventHandler that is on the WebForm where the control is included. The handler handles with controls from the WebForm, so it has to be there. I could probably manage to take the button out of the control, but it would be better to keep it on the control, for organization sake.
public class LanguageSelection : WebControl
{
private List<Language> _Languages;
private CSSImageButton btnOk = new CSSImageButton();
private CSSImageButton btnClose = new CSSImageButton();
public List<Language> Languages
{
set { _Languages = value; }
get { if (_Languages != null) return _Languages; else; _Languages = LanguageManager.Select(); return _Languages; }
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
Control parent;
Control container;
btnClose.CssClass = "sprReprove";
btnClose.DivClass = "float-right";
btnClose.OnClientClick = "$('#languagesOptions').hide('slow')";
btnOk.CssClass = "sprApprove";
btnOk.DivClass = "float-right";
btnOk.Click += new ImageClickEventHandler("btnSave_Click"); // this method here is on the webform where i included the control
// Get a reference to the ScriptManager object for the page
// if one exists.
ScriptManager sm = ScriptManager.GetCurrent(Page);
if (sm == null || !sm.EnablePartialRendering)
{
// If partial rendering is not enabled, set the parent
// and container as a basic control.
container = new Control();
parent = container;
}
else
{
// If partial rendering is enabled, set the parent as
// a new UpdatePanel object and the container to the
// content template of the UpdatePanel object.
UpdatePanel up = new UpdatePanel();
container = up.ContentTemplateContainer;
parent = up;
}
container.Controls.Add(new LiteralControl("<div id=\"languagesOptions\" class=\"divSelectLanguages\">"));
container.Controls.Add(new LiteralControl(" <strong>Salvar conteúdo nestes idiomas?</strong>"));
container.Controls.Add(new LiteralControl("<table class=\"tblSelectLanguages\">"));
int i = 0;
foreach (Language l in Languages)
{
CheckBox cb = new CheckBox();
cb.Enabled = false;
if(i % 2 == 0) container.Controls.Add(new LiteralControl("</tr><tr>"));
container.Controls.Add(new LiteralControl("<td>"));
container.Controls.Add(cb);
container.Controls.Add(new LiteralControl(l.FullName));
container.Controls.Add(new LiteralControl("</td>"));
i++;
}
container.Controls.Add(new LiteralControl("</tr>"));
container.Controls.Add(new LiteralControl("</table>"));
container.Controls.Add(btnOk);
container.Controls.Add(btnClose);
container.Controls.Add(new LiteralControl("</div>"));
Controls.Add(parent);
}}
Having your button handled by an event on the containing webform is not advisable. Ideally, your control should be completely self-contained. Instead, what you can do is have your button click event handled inside your control and then raise another event, which can be handled by the WebForm.
// This event will be handled by the webform
public event EventHandler OkButtonClicked;
protected void btnOk_Click(object sender, EventArgs e)
{
// Raise the okButtonClicked event
if (OkButtonClicked != null)
OkButtonClicked(sender, e);
}
// The btnOk button will be wired to our new event handler
btnOk.Click += new ImageClickEventHandler(btnOk_Click);
On your webform, you can have something like this:
<app:LanguageSelection ID="LanguageSelection1" OnOkButtonClicked="btnSave_Click" runat="server"/>
When the button is clicked inside the webcontrol, it would be handled by the btnOk_Click method inside the webcontrol. This would then raise the OkButtonClicked event which would be handled by the btnSave_Click method in WebForm containing the control.