I have read through a lot of articles to resolve this problem, but I can't get this to work.
The Situation:
I have a WPF MainWindow where I am loading UserControls into it.
The Mainwindow should listen to an EventHandler in a Class called Navigation. The Event will be fired upon certain changes in the UserControls.
So far I can confirm that the UserControls can fire the Event, but the MainWindow does not pickup the Throw.
Navigation Class:
public class Navigation
{
public delegate void EventHandler(object sender, EventArgs args);
public event EventHandler ThrowEvent = delegate { };
public void NavigationUpdateEvent()
{
ThrowEvent(this, new EventArgs());
}
}
UserControl:
public delegate void EventHandler(object sender, EventArgs args);
public event EventHandler ThrowEvent = delegate { };
Navigation myNavigation = new Navigation();
public myUserControl()
{
InitializeComponent();
}
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
if (cbCheckBox.IsChecked.Value)
{
UMENavigation.NavigationUpdateEvent();
}
}
The MainWindow:
private void DoSomething()
{
MessageBox.Show("It worked!");
}
private Navigation _Thrower;
public MainWindow()
{
InitializeComponent();
_Thrower = new Navigation();
_Thrower.ThrowEvent += (sender, args) => { DoSomething(); };
}
However, the _Thrower never picks up the Fired Event..
Any help is greatly appreciated! This is starting to hurt :)
Greetings, Tom
Navigation instances in UserControl and in the MainWindow are different.
UserControl fires the event for its own instance. At the same time, MainWindow listens for the event from its own instance.
Either use single instance of Navigation, or create a proxy-event in UserControl and subscribe it in MainWindow.
Besides, you don't need to declare your EventHandler. It's already declared.
Related
I have a userControl and I've a button there, I'd like to call event when I'm clicking on the button in my main form from userControl. I do this:
UserControl
public UserControlerConstructor()
{
_button.Click += new EventHandler(OnButtonClicked);
}
public delegate void ButtonClickedEventHandler(object sender, EventArgs e);
public event ButtonClickedEventHandler OnUserControlButtonClicked;
private void OnButtonClicked(object sender, EventArgs e)
{
// Delegate the event to the caller
if (OnUserControlButtonClicked != null)
OnUserControlButtonClicked(this, e);
}
Form
public Form1()
{
userControlInstance.OnUserControlButtonClicked += new EventHandler(OnUCButtonClicked);
}
private void OnUCButtonClicked(object sender, EventArgs e)
{
throw new NotImplementedException();
}
It doesn't work because when I click in the form do nothing in the form code, but it does in userControl code. But I'd like to do in form code. I don't know how to call event from userControl to the form.
Well now I don't know if you're explicity want to use the delegate, no? If not, why don't you just do:
public Form1()
{
userControlInstance._button.Click += OnUCButtonClicked;
}
private void OnUCButtonClicked(object sender, EventArgs e)
{
throw new NotImplementedException();
}
up to now your code does not compile. You are using the wrong event handler type. It should show the following compiler error:
EventHandler cannot be converted to ButtonClickedEventHandler
Do the following steps:
1) put the declaration of the delegate outside of the class UserControlerConstructor:
public delegate void ButtonClickedEventHandler(object sender, EventArgs e);
public partial class UserControlerConstructor: UserControl
{
1) then change the type of the handler when registering the event in Form:
public Form1()
{
userControlInstance.OnUserControlButtonClicked += new ButtonClickedEventHandler(OnUCButtonClicked);
}
This way it should work
I have created custom control. I would like to perform in my custom control after that Form.Shown event. I have tried in Control.GotFocus event which has triggered before that Form.Shown event. I want to make the changes in my control after that Form.Shown event.
Is it possible? If yes means, please suggest me how to do this?
Thanks,
You could register to the event:
public class MyControl : UserControl
{
// you need a reference to the hosting Form
public MyControl(Form frmHost)
{
frmHost.Shown += FormHost_Shown;
}
private void FormHost_Shown(object sender, EventArgs e)
{
// Do your work
}
}
When you the create an instance of your control, just pass a reference to the hosting form:
this.Controls.Add(new MyControl(this));
If you need a parameterless constructor you could make the hosting Form a property of your control and set that property before the Shown event happens:
public class MyControl : UserControl
{
private Form frmHost;
public Form FrmHost
{
get
{
return frmHost;
}
set
{
frmHost = value;
frmHost.Shown += FormHost_Shown;
}
}
private void FormHost_Shown(object sender, EventArgs e)
{
// Do your work
}
}
public class MyForm : Form
{
public MyForm()
{
InitializeComponent();
// User control was created elsewhere (perhaps in the designer)
myUserControl.FrmHost = this;
}
}
No, the documented order of events when activating for the first time a windows forms is the following:
Control.HandleCreated
Control.BindingContextChanged
Form.Load
Control.VisibleChanged
Form.Activated
Form.Shown
As you can see, Shown is the last fired event. You would need to implement your own event in your custom base Form:
public event EventHandler AfterShwon;
protected override void OnShown(EventArgs e)
{
base.OnShow(e);
OnAfterShown(e);
}
protected virtual void OnAfterShown(e)
{
AfterShwon?.Invoke(this, e);
}
Had a look on here and found several examples but they don't seem to fit my exact problem and through experimentation I can't work it out.
Current code for form...
public partial class Form1 : Form
{
DualCombo dc = new DualCombo();
public Form1()
{
InitializeComponent();
this.Controls.Add(dc);
}
private void MyMethod()
{
MessageBox.Show(dc.c1.Text + dc.c2.Text);
}
private void Form1_Load(object sender, EventArgs e)
{
}
}
The control that contains 2 of my custom combos...
public class DualCombo : UserControl
{
public CustomCombo c1 = new CustomCombo();
public CustomCombo c2 = new CustomCombo();
public DualCombo()
{
c1.Items.Add("One");
c1.Items.Add("Two");
c1.Items.Add("Three");
c2.Left = c1.Right;
c2.Items.Add("One");
c2.Items.Add("Two");
c2.Items.Add("Three");
this.Controls.Add(c1);
this.Controls.Add(c2);
}
}
I have left the code from the custom combo blank to keep the example simple...
public class CustomCombo : ComboBox
{
}
I would like my custom combo OnSelectedIndex changed to trigger the following method that is in the form...
private void MyMethod()
{
MessageBox.Show(dc.c1.Text + dc.c2.Text);
}
The easiest solution is to subscribe to that event directly:
public Form1()
{
InitializeComponent();
this.Controls.Add(dc);
dc.c1.SelectionChangedEvent += (s, e) => MyMethod();
}
But this is bad idea to make c1 public, read further.
UserControl is encapsulated control with some functionality. If you need to inform someone who is using that UserControl about something simple create an event:
Add event to UserControl
public EventHandler SomeEvent;
protected void OnSomeEvent() => SomeEvent?.Invoke(this, EventArgs.Empty);
Fire it when selection is changed from within UserControl
protected CustomCombo c1 = new CustomCombo();
public DualCombo()
{
c1.SelectedIndexChanged += (s, e) => OnSomeEvent();
...
}
Now you can subscribe to that event in your form (where this UserControl is used):
DualCombo dc = new DualCombo();
public Form1()
{
InitializeComponent();
this.Controls.Add(dc);
dc.SomeEvent += (s, e) => MyMethod(); // call your method
}
Tips: do not make controls inside UserControl public. Think about UserControl as a black box.
I am trying to raise a event in one of classes of userControl, and Fire it in the Main class. I tried two different ways to fire this event, one of them works, But I still want to know why other way cannot work, and how to fix it.
My userContol class:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
{
return;
}
Class1 c = new Class1();
Thread accept = new Thread(
() =>
{
c.connection();
}
);
accept.Start();
}
}
And the Class1:
public class Class1
{
public delegate void myhandler(object sender, EventArgs e);
public event myhandler test;
public Class1()
{
}
public void connection()
{
test(this, new EventArgs());
}
}
In the Main, I just simply add into referent, and add
xmlns:my="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1"
then I try to subscribe this event in the main
public partial class SurfaceWindow1 : SurfaceWindow
{
/// <summary>
/// Default constructor.
/// </summary>
public SurfaceWindow1()
{
InitializeComponent();
Class1 c = new Class1();
c.test+=new Class1.myhandler(c_test);
// Add handlers for window availability events
AddWindowAvailabilityHandlers();
}
public void c_test(object sender, EventArgs e)
{
MessageBox.Show("fire");
}
}
If I only raise this event not into thread, it works fine, but If I try to let it raise in this thread, this test event only return null, and shows:
Object reference not set to an instance of an object.
looks like I did not subscribe it ever. So How to fix it if I must use it in thread.
This is a good example of what you really shouldn't be doing. You are trying to subscribe to an event of a class that is "owned" by another class. You are basically digging through the type hierarchy to find the event you want. This goes against good design.
Especially in UI applications there is a design concept called Event Bubbling. The type that owns the original object raising the event handles that event. In the handling of that event, it raises its own duplicate event. Here is a short-ish program that shows the concept:
public class RootEventClass
{
public event EventHandler SomeKindOfEvent;
protected virtual void OnSomeKindOfEvent(object sender, EventArgs e)
{
EventHandler handler = SomeKindOfEvent;
if (handler != null)
handler(this, e);
}
public void RaiseEvent()
{
Console.WriteLine("Root Event Firing");
OnSomeKindOfEvent(this, EventArgs.Empty);
}
}
public class FirstOwnerClass
{
private RootEventClass _rootClass;
public event EventHandler SomeKindOfEvent;
public FirstOwnerClass()
{
_rootClass = new RootEventClass();
_rootClass.SomeKindOfEvent += _rootClass_SomeKindOfEvent;
}
void _rootClass_SomeKindOfEvent(object sender, EventArgs e)
{
Console.WriteLine("First Owner Class Handling Root Owner Event");
OnSomeKindOfEvent(this, e);
}
protected virtual void OnSomeKindOfEvent(object sender, EventArgs e)
{
EventHandler handler = SomeKindOfEvent;
if (handler != null)
handler(this, e);
}
public void RaiseEvent()
{
_rootClass.RaiseEvent();
}
}
public class SecondOwnerClass
{
private FirstOwnerClass _firstClass;
public event EventHandler SomeKindOfEvent;
public SecondOwnerClass()
{
_firstClass = new FirstOwnerClass();
_firstClass.SomeKindOfEvent +=_firstClass_SomeKindOfEvent;
}
void _firstClass_SomeKindOfEvent(object sender, EventArgs e)
{
Console.WriteLine("Second Owner Class Handling First Owner Event");
OnSomeKindOfEvent(this, e);
}
protected virtual void OnSomeKindOfEvent(object sender, EventArgs e)
{
EventHandler handler = SomeKindOfEvent;
if (handler != null)
handler(this, e);
}
public void RaiseEvent()
{
_firstClass.RaiseEvent();
}
}
public class Program
{
public static void Main(string[] args)
{
SecondOwnerClass secondOwner = new SecondOwnerClass();
secondOwner.SomeKindOfEvent += secondOwner_SomeKindOfEvent;
secondOwner.RaiseEvent();
Console.ReadKey(true);
}
static void secondOwner_SomeKindOfEvent(object sender, EventArgs e)
{
Console.WriteLine("Got an event from the second owner defined in main");
}
}
If you run this program, you will get the following output:
Root Event Firing
First Owner Class Handling Root Owner Event
Second Owner Class Handling First Owner Event
Got an event from the second owner defined in main
So what is happening here. The Main method defines a SecondOwner object and then tells it to raise an event, which just passes it up the ownership chain to the root object. The magic is the event bubbling. The event is intercepted by each owning class and passed on. This way it can decide to pass it on or not.
Also, the Main method only needs to know about the events created in the SecondOwner class, it doesn't have to dig through SecondOwner, FirstOwner and finally RootEventClass.
Its an easy concept to grasp really, don't force your users (or yourself) to dig through types and ownership to get to an event, if users of the class will need that event, duplicate the event and bubble it.
I've got a problem with subscribing from a form to an event in an user control.
MainForm-Code:
public partial class mainForm : Form
{
public mainForm()
{
InitializeComponent();
UserControl menuView = new mnlib.mnlibControl();
newWindow(menuView);
}
public void newWindow(UserControl control)
{
this.mainPanel.Controls.Clear();
this.mainPanel.Controls.Add(control);
}
mnlibControl.OnLearnClick += new EventHandler(ButtonClick); //Error in this line
protected void ButtonClick(object sender, EventArgs e)
{
//handling..
}
}
UserControl-Code:
public partial class mnlibControl : UserControl
{
public mnlibControl()
{
InitializeComponent();
}
private void btn_beenden_Click(object sender, EventArgs e)
{
Application.Exit();
}
public event EventHandler LearnClick;
private void btn_lernen_Click(object sender, EventArgs e)
{
if (this.LearnClick != null)
this.LearnClick(this, e);
}
}
Now, visual studio marks the "mnlibControl.OnLearnClick ..." line as wrong. "mnlibControl" would not be found, maybe a missing using directive etc. .
All this code and both forms are located in the same project file.
I tried around and googled like hell but just can't find a solution for my problem.
In the UserControl form there is a button - when it's clicket it shall trigger the newWindow method in the mainForm and open up another window.
My source for this solution of my problem is: How do I make an Event in the Usercontrol and Have it Handeled in the Main Form?
There is no OnLearnClick in your component. You need to subscribe to LearnClick. You also need to subscribe in function block. You also should use concrete type (mnlib.mnlibControl), not UserControl:
public mainForm()
{
InitializeComponent();
mnlib.mnlibControl menuView = new mnlib.mnlibControl();
menuView.LearnClick += new EventHandler(ButtonClick);
newWindow(menuView);
}
Your code mnlibControl.OnLearnClick += new EventHandler(ButtonClick); must be within any of functional block (i.e. method, property, ...).
You have to place this line inside an actual method:
mnlibControl.LearnClick += new EventHandler(ButtonClick);
Like this:
public mainForm()
{
InitializeComponent();
UserControl menuView = new mnlib.mnlibControl();
newWindow(menuView);
mnlibControl.OnLearnClick += new EventHandler(ButtonClick);
}