I have a gridview and usercontrol on the page, I want to alter gridview from usercontrol. how can i do that?
And also how can I call functions in usercontrol's "host" page from the usercontrol?
UPDATE:
I have a dropdownlist inside this usercontrol, when the it's SelectedIndexChanged event is triggered i want the gridview on the host page to DataBind().
(Then, gridview using objectdatasource will read this dropdownlist selected item and use it as select parameter)
Also if it possible to make it as general as it possible, because the altered control is not always a gridview...
Thanks
First of all, you would not want to do neither. That's against the concept of user control.
If you want to modify a gridview using the user control's state, you can expose the control's state and make the gridview to behave according to this state.
// This handles rowdatabound of gridview
OnRowDataBound(object sender, RowDataBoundEventArgs e)
{
var control = e.Row.Find("UserControlId");
if (control.SomeProperty == SomeValue)
someTextBox.Value = "something";
}
If you really need to pass a handle of gridview to a user control, define a property on the user control of grid view type:
// This is a property of user control
public GridView Container { get; set; }
and set the control's container to the gridview, before accessing it.
userControl.Container = gridView;
If the user control is a part of the itemtemplate on the grid, since your user control is created while rows of the gridview are created, you can only this after you bind your gridview.
Finally, for calling a function on the container page, you can expose an event inside of your user control and bind to that event.
public delegate void SomethingHappenedEventHandler(object sender, EventArgs e);
// In user control:
public event SomethingHappenedEventHandler SomethingHappened;
// Trigger inside a method in user control:
SomethingHappenedEventHandler eh = SomethingHappened;
if (eh != null) eh(this, EventArgs.Empty);
// In page:
userControl.SomethingHappened = new SomethingHappendEventHandler(OnSomething);
private void OnSomething(object sender, EventArgs e)
{
// When something happens on user control, this will be called.
}
Simply add a public method to your usercontrol's code-behind, then you can call this from the page and pass the gridview as a parameter:
public class MyUserControl : UserControl
{
public void MyMethod(GridView gridview)
{
// do stuff with the gridview
}
...
}
The second question is a bit more complicated. Because if you make your usercontrol depend on a specific page, it will no longer be reusable on other pages, e.g:
public class MyUserControl : UserControl
{
public void AnotherMethod()
{
//get the current page and cast it to its type
MyPage page = this.Page as MyPage;
// now I can call the public methods of MyPage
page.SomeMethod();
}
...
}
A better solution would be to define an interface, which is implemented by the page. Then you can methods of that interface by casting the current page to the interface (and the controls can still be reused on other pages implementing the same interface):
public interface IMyInterface
{
void SomeMethod();
}
public class MyPage : IMyInterface
{
public void SomeMethod() { ... }
}
public class MyUserControl : UserControl
{
public void AnotherMethod()
{
//get the current page and cast it to the interface
IMyInterface page = this.Page as IMyInterface;
// now I can call the methods of the interface
if (page != null) page.SomeMethod();
}
}
EDIT: In your user control, simply create a public property to hold the grid. That property will then hold a reference to grid in the host page. For example, you could add the following to your UserControl's code behind.
public string CurrentGridID
{
get;
set;
}
public void ModifyGrid()
{
//make changes to the grid properties
GridView grid = Page.FindControl(CurrentGridID);
grid.AutoGenerateColumns = false;
}
From your the page hosting the control, you could do something like this.
protected void Page_Load(object source, EventArgs e)
{
this.myUserControl1.CurrentGridID = this.gridView1.ID;
}
You should expose a public property that accepts the id of the server control you want to reference. You could then grab that control by querying Control.NamingContainer. You should not query Page, since you want to grab the control in your current context (you could be in a usercontrol with controls named the same as the page).
Dont forget the often overlooked IDReferencePropertyAttribute. It tells your designhost (usually Visual Studio) to provide autocompletion for the value using all controls in the current context.
To call stuff on your containing Page, just use the Page property. You need to cast this to your specific page class if you need to access your own methods.
Related
IDE: Visual Studio, C# .net 4.0
I have two identical user control uc1 and uc2 and both are having a textbox called txtbox1
now see this code and textbox1 is public in designer so it is assessable in form1.cs, Form 1 is simple windows form which is having uc1 and uc2.
In form1 see this function which i am calling in onLoad_form1 method.
UserControl currentUC; //Global variable;
public void loadUC(string p1)
{
//Here I want:
if(p1 == "UC1)
{
currentUC = uc1;
}
if(p1 == "UC2)
{
currentUC = uc2;
}
}
Than another function which calls update the textbox1 based on currentUC value
//on load
currentUC.textbox1.text = "UC1 called";
//Here I am getting error "currentUc does not contains definition for textbox1"
If i do:
uc1.textbox1.text = "UC1 text";
uc2.textbox1.text = "UC1 text"; //it works, But based on p1 string variable I want to make control as uc1 or uc2 than I want to access its child control. please suggest how to perform this.
please don't tell if else blocks, because This functionality I have to use in various places.
Thanks.
#Lee Answer: - works just for textbox, but I am having two usercontrols i.e. two different usercontrols not instance of it. UserControlLeft and UserControlRight and both are having same textboxes, listboxes etc (with minor design changes), and I want to access/load this based on some string "left" and "right".
Since the textboxes have the same name you can look them up in the Controls collection:
TextBox tb = (TextBox)currentUC.Controls["textbox1"];
tb.Text = "UC1 called";
a better solution would be to add a property to your user control class which sets the internal text property e.g.
public class MyUserControl : UserControl
{
public string Caption
{
get { return this.textbox1.Text; }
set { this.textbox1.Text = value; }
}
}
I think you're mixing a couple of things here.
First of all, you say that you have 2 exactly the same usercontrols, do you mean the ascx files are the same, or that you have 2 instances of the same usercontrol on the page?
Let's go with all the valid options:
1. To find a control and cast it:
Assume you have the following aspx snippet:
<div>
<uc1:MyCustomUserControl id="myControl" runat="server" />
<uc1:MyCustomUserControl id="myControl2" runat="server" />
</div>
If you now want to access the control, you should do the following:
public void Page_Load()
{
var myControl ((MyCustomUserControl)FindControl("MyControlName"));
// On 'myControl' you can now access all the public properties like your textbox.
}
In WPF you can do it like this:
//on load MAINFORM
public void SetText(string text)
{
CLASSOFYOURCONTROL ctrl = currentUC as CLASSOFYOURCONTROL ;
ctrl.SetText(text);
}
// in your control SUB
public void SetText(string text)
{
textbox1.text = "UC1 called"
}
i think this should work in winforms also. And is more clean than accessing the controls from your sub-control directly
#Lee's method is good. Another method will be to use a public property with a public setter (and textbox doesn't need to be public this way).
or an interface (this way you don't care what class you have at the given moment - and no ifs):
public interface IMyInterface
{
void SetTextBoxText(string text);
}
public partial class UC1: UserControl, IMyInterface
{
public void SetTextBoxText((string text)
{
textBox1.Text=text;
}
//...
}
public partial class UC2: UserControl, IMyInterface
{
public void SetTextBoxText((string text)
{
textBox1.Text=text;
}
//...
}
using the code:
((IMyInterface)instanceOfUC1).SetTextBoxText("My text to set");
((IMyInterface)instanceOfUC2).SetTextBoxText("My text to set");
I have a listBox that I would like to carry out a method when its loaded up, although I can't use the Form "On_Load" trigger, since the ListBox is within a TabControl.
Is there a way of getting a method to execute when the object initializes?
The closest analog for controls is the HandleCreated event. This will fire when the underlying control handle is created, which is slightly before the Loaded event of the parent window would fire.
As #SLaks stated, you could put in your class's constructor. However, if what you want to prepare relies on other elements in the form, you can add to the event handler queue at the end of a form loading, but before its actually presented to the user.
In the constructor code of your form (not the designer code), add to the load event, then add your own custom function
public partial class frmYourForm : Form
{
public frmYourForm()
{
Load += YourPreparationHandler;
}
private void YourPreparationHandler(object sender, EventArgs e)
{
// Do you code to prepare list, combos, query, bind, whatever
}
}
Have the same problem, the previous answers apply well, for a single case.
But, I require to do something in most controls, in several forms, in an app.
Solved by using an interface:
interface IOnLoad
{
void OnLoad();
}
And added to descendant control:
public partial class MyButton : Button, IOnLoad
{
void OnLoad() { // call "OnLoadDelegate" }
}
public partial class MyForm : Form
{
public void MyForm_Load(...) {
foreach(Control eachControl in Controls) {
if (eachControl is IOnLoad) {
IOnLoad eachOnLoadControl = (IOnLoad)eachControl;
eachOnLoadControl.OnLoad();
}
} // foreach
}
} // class
Its more complex, but it suit my requirements.
You can use OnHandleCreated(EventArgs e). However, it triggers during design time too. You can override it too.
Can you use the HandleCreated event?
You can just put your code in the constructor.
You usually don't need to wait for any initialization.
I have a Class that contains: A DataGrid, A Pager
I am trying to make User Control that contains both of them and have all property that links to both of them.
So something:
public class MyGridViewPager : ltcGrid
{
public GridView aGridView;
public DataPager aDataPager;
public bool AutoGenerateColumns {
get { return this.aGridView.AutoGenerateColumns; }
set { this.aGridView.AutoGenerateColumns = value; } }
}
So I can use the property from them in my MyGridViewPager UserControl and in case of any choice change on the GridView or DataPager I can modify only the layer...or is it called wrapper-class? Not so sure about the naming...
But... how do I do the same thing for EventHandler?
I can see it defines in:
public delegate void SelectionChangedEventHandler(object sender, SelectionChangedEventArgs e);
How can I expose this handler from my user control?
Note: I don't really want to do MyGridViewPager.aGridView.SelectionChangedEventArgs.
There is a myriad of ways to do this:
Exposing events of underlying control
Event Bubbling in C#
I have a child UserControl which is dynamically loaded into a parent page.
ChildControl childcontrol = this.LoadControl("") as ChildControl;
I have to call one of the methods in the parent page from this childUserControl. How do we do that?
Thanks
You shouldn't write a control that relies on a method being on the page, so the best thing to do would be to expose and handle an event from the child control. Add the following to your child control:
public event OnSomethingHandler Something;
public delegate void OnSomethingHandler(ChildControl sender);
Then when you want to fire the page method in question, fire off the event:
public void FireParentMethod()
{
if (Something != null)
{
Something(this);
}
}
The all you need to do is handle the event on the page (in markup or in code as follows):
childUserControl.Something+=
new ChildControl.OnSomethingHandler(ChildControl_OnSomething);
And add the handler to the code behind:
protected void ChildControl_OnSomething(ChildControl sender)
{
FirePageMethod();
}
Cast the parent of the control as the specific type of your page and then call the method.
I have a control that handles commenting. In this control, I have set a delegate event handler for sending an email.
I then have various types of controls, e.g. blog, articles etc, each of which may or may not have the commenting control added (which is done dynamically with me not knowing the id's), i.e. the commenting control is added outside this control. Each of these controls handles it's emailing differently(hence the event).
What I'm trying to determine, is how to assign the event in the parent control. At the moment, I'm having to recursively search through all the controls on the page until I find the comment control, and set it that way. Example below explains:
COMMENTING CONTROL
public delegate void Commenting_OnSendEmail();
public partial class Commenting : UserControl
{
public Commenting_OnSendEmail OnComment_SendEmail();
private void Page_Load(object sender, EventArgs e)
{
if(OnComment_SendEmail != null)
{
OnComment_SendEmail();
}
}
}
PARENT CONTROL
public partial class Blog : UserControl
{
private void Page_Load(object sender, EventArgs e)
{
Commenting comControl = (Commenting)this.FindControl<Commenting>(this);
if(comControl != null)
{
comCtrol.OnComment_SendEmail += new Commenting_OnSendMail(Blog_Comment_OnSendEmail);
}
}
}
Is there an easier way?
EDIT:
The reason I ask is that if I search from this.Page as the initial control, I am worried about time taken to search down the control tree to find it. Each different type of page would be different in how many control it would have. On some testing, it returns back quite quickly the result.
You could override the AddedControl event of your Blog class and check if the added control is instance of type Commenting. Something like:
public partial class Blog : UserControl {
protected override void AddedControl(Control control, int index) {
base.AddedControl(control, index);
Commenting commentingControl = control as Commenting;
if (commentingControl == null) return;
commentingControl.OnComment_SendEmail += new Commenting_OnSendMail(Blog_Comment_OnSendEmail);
}
}
Of course, you can put this code on a base class of all your "commentable" user controls and have an abstract method to actually handle the event.
Just one thing: the AddControl event happens AFTER the Page_Load, so be careful.
Cheers,
André