Say I have tvo pages, page1.ascx and page2.ascx. Both pages have code-behind(page1.ascx.cs and page2.ascx.cs respectively).
So page1 and page2 are rendered at the same time in the browser, side by side.
Now page1.ascx has a ListView and its code-behind has a method to populate it(PopulateListbox()). How can I call PopulateListbox() from the page2.ascx code-behind?
page1 p1 = new page1();
p1.PopulateListbox();
...does not work, and findController to find the ID of the listbox returns a null value.
Any guidance would be of great help, thanks.
var p1 = this.Page.FindControl("page1Id") as page1;
if (p1 != null)
p1.PopulateListbox();
You can do this in a different way though. Create an event on the first control for a specific action. In the parent page add an event handler and that event handler will contain the following call
p1.PopulateListbox();
Here a link for how to create your own events
Accessing one user control method directly from another user control doesn't sound like a great design.
What you could do is create a Delegate in your page2.ascx that gets called when your refresh action in the other user control needs to happen.
Your aspx page subscribes to that delegate and makes the call to the page1.ascx PopulateListBox method.
So, your page orchestrates the interaction between both user controls and they don't know about each other.
Related
It is a well known error if you try to add the RadAjaxManager to your page twice:
Only one instance of a RadAjaxManager can be added to the page
Telerik explains how you can solve this for design-time issues with a proxy control.
For most of the controls we use on pages, this error does not fire, even though each of these controls have a RadAjaxManager on them, sometimes even inside a repeater (accidentally, but still, the error doesn't throw). However, with one such control (a dynamic button) we have added it to several places on the page with no problem, possibly because this was all the same control, but nested in another control we receive the error above again, as soon as we add it to the page.
I have tried to solve it by:
adding the control dynamically to the page, but because control events fire before the page events, this leads to some dynamic behavior to not occur anymore.
adding the RadAjaxManager dynamically only once to the control, with built-in extra checks, like so:
private RadAjaxManager GetAjaxManager()
{
var ctl = this.FindControl("ajaxManager");
if (ctl != null)
{
return (RadAjaxManager)ctl;
}
// alternative method
var mgr = RadAjaxManager.GetCurrent(this.Page);
if (mgr != null)
{
return mgr;
}
// control is never found, always returns null
return null;
}
protected override void OnInit(EventArgs e)
{
if (this.GetAjaxManager() == null)
{
// ajax mgr is never found, and this always throws
// "cannot add multiple times" error
var ajaxManager = new RadAjaxManager();
ajaxManager.ID = "ajaxManager";
this.Controls.Add(ajaxManager);
}
}
Several variants of the above
The result is either: the control is never found and is therefore added more than once, resulting in the above error, or the control is added but too late in the process for the other controls in the usercontrol, resulting in several AJAX events not happening.
How should I add the RadAjaxManager to a user-control that is itself used inside several other user-controls, such that the manager only occurs once on the page and/or such that RadAjaxManager.GetCurrent actually works?
Plane A - add the RadAjaxManager to the page level, not to the user controls. Thus, the user controls can have RadAjaxManagerProxy controls, the static GetCurrent() method will work.
Plan B - use RadAjaxPanel controls if you want self-contained user controls. They have an ajaxRequest() client-side method and a server side event for that, and since user controls are usually smallish, you will likely be able to get away with a single panel for them.
Plan C - leave AJAX setup to the parent page. If a parent user control is already AJAX-enabled, its entire content will travel with the postback, so neesting more AJAX settings on inner user controls may not bring you a performance benefit.
Plan D - use only asp:UpdatePanel controls with UpdateMode=Conditional so you will have extremely fine-grained control of your partial rendering.
Currently I have a C# program with a windows form and then a user control template put onto the form. The user control template is really just used as a placeholder. I have a series of other controls which inherit from this user control template.
Each of those controls have navigation buttons like 'Continue' and 'Back' on them and each control knows which control needs to be loaded next. However what I need to figure out is an easier way to have variables that are global to these controls.
The only workaround I have is that I pass the form to each control when they are loaded and use variables inside of the form to read and write to. What would be the proper way to have each of these user control screens be built off of a base control which contained objects all of the controls could get to?
Sorry for the rambling nature of the post but I've been thinking about this problem all morning.
Here is some of the code:
Most of what I have written was based on hiding and showing the user controls so that content in the controls wouldn't be lost during navigation. I won't be needing to do that as eventually it will be loading the fields of data from a database.
Code for initially loading control from form click:
conTemplate1.Controls.Clear();
conInbound Inbound = new conInbound(this);
Inbound.Dock = DockStyle.Fill;
Inbound.Anchor = (AnchorStyles.Left | AnchorStyles.Top);
conTemplate1.Controls.Add(Inbound);
Code for Continue button inside of one of the controls:
if ((Parent.Controls.Count - 1) <= Parent.Controls.IndexOf(this))
{
UserControl nextControl = new conPartialClear();
nextControl.Dock = DockStyle.Fill;
Parent.Controls.Add(nextControl);
this.Hide();
Parent.Controls[Parent.Controls.IndexOf(this) + 1].Show();
}
else
{
this.Hide();
Parent.Controls[Parent.Controls.IndexOf(this) + 1].Show();
}
The best-practice for communicating from a control to a parent is to use events, and for communicating from a parent to a control is to call methods.
However, if you don't want to or can't follow this practice, here's what I would recommend.
Each UserControl has a ParentForm property that returns the Form that contains the control. If you know that the UserControl will always be attached to MyParentForm, you just cast the ParentForm and then you can access all public controls, methods, etc.
Here's what I mean:
public class conTemplate
{
public MyParentForm MyParentForm
{
get
{
return (MyParentForm)this.ParentForm;
}
}
}
This way, you can easily access any public members of MyParentForm. Your conInbound class could have code such as this.MyParentForm.GlobalSettings.etc..., and could even have access to any public controls.
I'm not totally sure I understand your problem. It sounds like you want the user control to "do something" with it's parent form. If that's the case, you may want to consider adding events to the UC and then handle them on the form itself.
Basically, for your UC's "continue", you'll have an event that's fired when it's pressed. You'll want to handle that in your form. I'm not real sure about the syntax from memory, or I'd work something out for you code-wise. But I think that's the route you'll want to take. Think of your UC like any other windows form control. If you add a button to your form, you assign it it's event method. Do the same with the UC.
I found this and thought it may be helpful. Scroll down to where it talks about UC's and events.
http://www.akadia.com/services/dotnet_user_controls.html
Hope this helps.
EDIT after new info from OP.
You could declare a global variable inside the UC of type yourForm and then set that variable to the ParentForm at run-time, if I'm understanding you correctly.
So, inside your UC Class, you could do:
private parentFormInstance;
then inside the constructor of the UC, you could set it as such:
parentFormInstance = this.ParentForm; (or whatever the property name is).
This allows you at design-time to use:
parentFormInstance.DoSomething();
without the compiler yelling at you.
Just basic advice, but if you can go back and make it easier on yourself, even if it takes some additional time re-working things, it'd be worth it. It may save you time in the long run.
I would like to be able to show ContactCard/PopupContactCard control on MouseEnter event of a control.
Does anyone know how to show the contact card?
So far I was not able due to internal/protected modifiers of vital methods.
I can do this with the PresenseIndicator control, but not from my custom code in the event handlers.
So any ideas?
You could create either a new page, or a popup section of your existing page, and host a contact-card object in there. Then, on the mouse-enter, pass through the SIP you want to display and show the popup (/show the other page)
The ContactCard control I would probably choose to display is this one: http://msdn.microsoft.com/en-us/library/microsoft.lync.controls.contactcard_di_2_lyncctrlslmref.aspx
Or do you mean that you wish to expand the ContactCard? I'm not sure if this is possiblem, is the IsExpanded property writable?
I have two pages with similar logic in them. Load the page, click some buttons that will show/hide other buttons, continue to next page. When I hit the next page, if I click the back button I am returned to the previous page.
The difference is that one page (FirstPage) will have the constructor called when I click the back button, which has a call to reset the defaults. The other page (SecondPage) doesn't get the constructor called and I'm not sure why.
public FirstPage()
{
InitializeComponent();
DisplayStuff();
}
FirstPage has KeepAlive set to False.
public SecondPage(object arg1, object arg2)
{
InitializeComponent();
DisplayStuff(arg1, arg2);
}
This page also has KeepAlive set to False. These two pages don't inherit from anything and there is nothing that overrides any of the properties. The only difference I can see is the empty constructor, so I tried giving SecondPage an empty constructor and still no luck.
I'm relatively new to WPF (I work on it for an hour or two every 6 months), so what am I missing?
Here is the back button in case it is relevant.
<Button Command="{x:Static NavigationCommands.BrowseBack}" />
Edit: When I click the back button, SecondPage doesn't keep its state. It just loads an empty page because DisplayStuff hasn't been called yet.
Navigation Code:
NavigateTo(new SecondPage(arg1, arg2));
protected void NavigateTo(Page page)
{
NavigationService.Navigate(page);
}
I created a similar sample application and had similar behaviour. What I figured out that when you go back to a page the constructor is not called unless the page is the first page in the journal
Read this section in Navigation in WPF:
When the page Page is navigated back to, using the journal, the following steps take place:
The Page (the top journal entry on the back stack) is instantiated.
The Page is refreshed with the state that was stored with the journal entry for the Page.
The Page is navigated back to.
Good luck!
After reading Paul Stovell's article on WPF navigation, the way I want to display stuff is not going to work.
When navigating, if you click "Back", WPF can't possibly know what values to pass to the constructor; therefore it must keep the page alive. Here's the trace output:
Since WPF can't call the constructor, it won't. It'll just keep the page alive.
He goes on to mention that KeepAlive doesn't work if you're not navigating via URI, and Loaded and Unloaded are called each time, so I can just move all my logic there and I won't need the constructor to be called on the back navigation.
I have a page that dynamically creates multiple usercontrols on the page_init event, and adds it to a placeholder on the page.
The usercontrols themselves databind to a repeater on page_init to a collection of about 10 strings, which outputs a div for each item.
There's also a "view more" link button on the user control. When I click the "view more" button it databinds another collection to a second repeater, with even more divs.
The problem: After clicking "view more" on one of the usercontrols, if I click "view more" on another usercontrol, the "view more" data is lost on the first usercontrol. I suspect it's because I'm not re-adding the controls, so viewstate isn't re-loaded.
Anyone have any ideas or am I just way off on this one? Thank you.
Problem is you need to re-create the dynamic controls on each postback and recreate their viewstate. Take a look at this article Dynamic Web Controls, Postbacks, and View State
Stan is right.
When you click in the link a postback occurs and you lost everything
I ran across the same problem, my aproach was recreate the dinamics UserControls on every postback.
this article http://www.codeproject.com/KB/user-controls/DynamicUC.aspx shows a example, but i implement a diferent code like this:
my page have the following method which dinammicaly add the controls to an PlaceHolder.
private void AdicionarControlesDinamicamente(int idPergunta)
{
if (idPergunta > 0)
{
this.IdPerguntaAtual = idPergunta;
PerguntaAtual = new Pergunta(this.IdPerguntaAtual);
UserControl uc = LoadControl(PerguntaAtual.TipoResposta.CaminhoUserControl, PerguntaAtual.IdPergunta);
phResposta.Controls.Add(uc);
ViewState["ControlesDinamicosPerguntaCarregados"] = true;
}
}
note this line of code ViewState["ControlesDinamicosPerguntaCarregados"] = true;
i store an information tha says that the controls already have been added to page.
then a ovveride the CreateChildControls to recreate the controls
protected override void CreateChildControls()
{
base.CreateChildControls();
// CHeck if the controls have been added to page, case true, i call IncluirControlesDinamicamente() again
// The Asp.Net will look into viewstate and wil find my controls there, so "he" will recreate their for me
if (ViewState["ControlesDinamicosPerguntaCarregados"] != null)
if (Page.IsPostBack)
AdicionarControlesDinamicamente(this.IdPerguntaAtual);
}
I think this help you.
PS: Sorry my english.