find UserControl's ParentForm during load - c#

I'm trying to find a UserControl's ParentForm so I can hook some event handlers to it. I tried doing this in a ParentChanged event handler on the UserControl, eg:
ParentChanged += delegate(object sender, EventArgs args)
{
ParentForm.SomeEvent += ...
}
And this works fine if the UserControl's Parent happens to be the form. However, if the UserControl is embedded in a container control (in this case a SplitContainer), the UserControl gets added to the container control before the container control gets added to the top level form's controls (as controlled in the InitializeComponent method). That is, InitializeComponent() builds up the hierarchy from the leaves on up, so the leaves have no idea what form they'll eventually be placed on during construction.
So the ParentForm is null on the UserControl when the ParentChanged event is fired, and I don't get a ParentChanged event when the UserControl's parent's parent changes. I could add listeners for the parent's ParentChanged event, but I'd have to do so on up the entire control hierarchy which isn't particularly elegant.
I'd basically like to get notified of when the ParentForm changes for a UserControl. However there's no such event. I could hook in to things like the Load event, however this says it can get fired every time a control is shown if it's in a MDI container. That MSDN article suggests putting things in the constructor, but that's what I'm doing right now and it's not working out because of the timing for when things get initialized.
Any ideas?

I needed this too in my own customcontrol.
I subclassed a button and in the onclick I need to know the form.
So the trick is actually not getting the form in the load but getting it at the time you need it.
This worked for me :
private Form GetParentForm(Control parent)
{
Form Result = parent as Form;
if (Result == null)
{
if (parent != null)
{
// Recursive is cool
return GetParentForm(parent.Parent);
}
}
return Result;
}
I use it like this
protected override void OnClick(EvnetArgs e)
{
Form form = GetParentForm(Parent);
if (form != null)
{
// do stuff here
}
}

Related

What would be the equivalent or closest match of Activated event of Window in Page in WPF?

There is Activated event in a Window in WPF. What is the the closest match for Activated event for a page. I want to use an event that triggers every time a page is displayed.
How about using the IsVisibleChanged event.
In your window, either your base class definition that you use throughout your app, or just the one you are interested in. Add a call at the opening of it something like
public class MyBaseclassWindow : Window
{
public MyBaseclassWindow()
{
IsVisibleChanged += MyBaseclassWindow_IsVisibleChanged;
}
private void MyBaseclassWindow_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
// e.NewValue will be TRUE when the visibility is coming back on
if ( !e.NewValue )
return;
// do whatever you want every time window becomes visible.
}
}
If this is something you want done throughout your system, then you can just use THIS window as your base window by always using it as forms are created.
There is the Loaded event which occurs when the element (Page) is laid out, rendered, and ready for interaction.
The Frame class, which I guess is used to host your pages, also has a ContentRendered event that you can handle.

C# click on control

I'm trying to create a custom control which fires an even on click.
My control is just a panel with a couple of labels and a picturebox inside.
The click works perfectly, the only issue is that I have to click the background of the control and if I press on the picturebox, is not working.
I've added the on click event to the control, but I would like to press in every place of it to trigger the event, not just the background of the panel.
I thought about adding a transparent object that covers entirely the control. I actually don't like this idea, however, I've tried with a picturebox, but i cannot see through it. It's not transparent. I can just see the panel background but It covers the labels and the image.
Thanks for the support.
If you just have a couple of objects in your panel, you can hook the Click event of all objects it contains to the same event handler, there is nothing wrong doing this.
public class MyUserControl : UserControl
{
public event Action<MyUserControl> MyControlClick
public string ID {get; set;}
public MyUserControl()
{
InitializeComponents();
// The same event handler code will be used for the three controls
myPictureBox.Click += global_Click;
myLabel1.Click += global_Click;
myLabel2.Click += global_Click;
this.Click += global_Click;
}
void global_Click(object sender, EventArgs e)
{
if (MyControlClick != null)
MyControlClick(this);
}
}
If you have a more important amount of objects, you can rely on this answer to create a truly transparent panel that handles clicks. The drawback is that you will have to detect which object has been clicked by using HitTest based on the mouse location.
On the form side :
aControl.MyControlClick += aControl_MyControlClick;
// ...
// This code is triggered when a MyUserControl is clicked
void aControl_MyControlClick(MyUserControl ctl)
{
MessageBox.Show(ctl.ID);
}
Actually! You cannot raise any event to the element in the Usercontrol unless you have to apply own method to your usercontrol or you can disable the element in the usercontrol but it will change the color of that element but It will raise the click event when you click your control.

Call a method in another class from a control within a control?

I have a custom control created, comprised of a bunch of text boxes, 1 button and radio buttons.
I then have a "parent" control which only has this 1 custom control placed on it, and in the code behind I have a reference to this control's Presenter.
The presenter handles the actual code for searching (when the one button is pressed). How do I set up the button click event on the child control to call the Search method from the presenter?
So I have the following:
CtlSearchDetails
ViewSearchScreen
PresenterSearchScreen
The button click event is on CtlSearchDetails and it needs to call the method on PresenterSearchScreen. I cannot figure out how to reveal this method to the instace of the control on ViewSearchScreen.
In your custom child control, you want to expose an event for the button click:
public event Action OnButtonClicked;
Then hook the button clicked event from the designer
private void btn_myButton_Clicked(object sender, EventArgs e)
{
if (OnButtonClicked != null)
OnButtonClicked();
}
Then in your parent container, you want to handle this event from the child control
this.myChildControl.OnButtonClicked += new Action(onChildButtonClicked);
private void onChildButtonClicked()
{
// Do your search here
}

Disabling child control events

The child controls of my custom control are obstruction the mouse events in my custom control. I have worked through the accepted answer and the answer at the bottom of this thread...
exposing-events-of-underlying-control
I haven't gotten them to work (the answer at the bottom seemed most straight forward to me). But really I would like to disable the events of them altogether. I have a pictureBox and a label, I don't need to interact with either of the child controls. Is there a way to disable them so they wont interfere with the events of my custom control?
Edit:
I'm using the custom control to gather and process a number of things and make them available as properties. When I click on it, I need to access to the properties. When the event happens at the child control, I don't have access to the propertied of my custom control. The following code is in my form...
public void Form1_MouseDown(object sender, MouseEventArgs e)
{
var myControl = sender as SubstanceViewer;
richTextBox1.Text = myControl.substanceInfo;
}
so I will need to access the properties of the parent control.
If you need the the events that are normally trapped by the child controls to be handled by the custom control itself, then simply wire up those events at run-time in the constructor of the custom control.
For example if you needed the MouseMove() event of the PictureBox and Label to fire the already wired up event of the UserControl:
public partial class SomeUserControl : UserControl
{
public SomeUserControl()
{
InitializeComponent();
this.pictureBox1.MouseMove += SomeUserControl_MouseMove;
this.label1.MouseMove += SomeUserControl_MouseMove;
}
private void SomeUserControl_MouseMove(object sender, MouseEventArgs e)
{
}
}
Be aware, though, that since different controls are firing the same handler you'll need to take that into account. For example, the e.X and e.Y values in the handler above would be relative to the source control.
*You can also wire these events up at design-time using the IDE itself, but I thought code better illustrated the solution.

Benefits of using Inherit Forms Controls

I tryed to create new components from one base Windows Form, also I found difficulties when I worked with toolstrip components, for example :
how to bind a datagrid.datasource on a child form using events from a button (clicks) on the parent toolstrip?
I have to use some snippets on each child form for doing this, btw why?
// btnSearch
//
this.btnSearch.Click += new System.EventHandler(this.btnExec_Click);
private void btnExec_Click(object sender, EventArgs e)
{
//do stuff
}
Thanks
EDIT: I also know about modifiers issue :
I mean, I have to replace the toolstripbutton with a common button, also have to add more code on designer class (base form) :
grpCommonControls.Height = 20;
dtTScomponent = new ToolStripControlHost(grpCommonControls);
dtTScomponent.Alignment = ToolStripItemAlignment.Right;
toolStrip1.Items.Add(dtTScomponent);
tssbExporta.Alignment = ToolStripItemAlignment.Left;
toolStrip1.Items.Add(tssbExporta);
I was needed to add a simple toolstrip with some toolstrip controls on my base form, but the designer dont allow me to work correctly with those (I cannot route the events from toolstripbutton to my child forms as an example)
When you create a form that inherits another form that contains different controls, there are not event handlers automatically hooked up for you. Instead you need to do that as in your code sample. Another approach is to attach that event handler in your base form, and then have the base form expose events that you can listen to. Example:
In the base form:
public event EventHandler ExecInvoked;
private void btnExec_Click(object sender, EventArgs e)
{
OnExecInvoked(e);
}
protected virtual void OnExecInvoked(EventArgs e)
{
EventHandler evt = ExecInvoked;
if (evt != null)
{
evt(this, e);
}
}
Then, in your inherited form, you can either set up an event handler for the ExecInvoked event (you can probably do this using the events list in the property grid), or you can override the OnExecInvoked method:
protected override void OnExecInvoked(EventArgs e)
{
base.OnExecInvoked(e);
// do what the form should do when Exec is invoked
}
This way you have encapsulated the internals of the base form, so that the child form does not know what kind of control that raises the event (it could even be several different controls leading to the same event being raised), but the base form still provides a clear point where the child form can react on it.
To be able to change properties and subscribe to events of controls inherited from your parent Form (or UserControl), the parent form should set those controls' Modifiers property to protected (or, in general, to any value such that fields generated for controls in parent form are visible to the child form). The default value for Modifiers is private.

Categories

Resources