I'm working on a semi-professional project and needed a custom view for one of my models. As far as I could figure out that meant creating a UserControl-inherited class, like so:
public partial class PopulationView : UserControl
{
...
}
Now this works wonders, and I've been able to do pretty much all I wanted, including custom painting with onPaint but I've noticed none of the events seem to be registering. I've had to attach multiple event listeners and in all instances I end up going back to my form and adding an event listener to my custom component's instance in the form. For example, I'd like to add a Click event listener. What I try first is simply
public partial class PopulationView : UserControl
{
private void PopulationView_Click(object sender, EventArgs e)
{
Debugger.Break();
}
}
of course attaching the function to the Click event through PopulationView.cs [Design]. That doesn't work so I end up adding a Click event listener on the instance of the component and adding the PopulationView_Click function to my form (MainForm.cs [Design]) instead and launching the appropriate function on the control.
I feel that I'm missing something very simple which is preventing me from being able to register events in my control directly and I'd appreciate any help with this. I dug around the interwebs but couldn't find anything relevant.
Update
Some of the comment make me think I should provide more detailed information about what I'm doing. The setup is sort of complicated but here's a summary:
I have a custom control inheriting from UserControl, called PopulationView
I have an instance of that control added to a form
Attaching event listeners through the design view of the form to the instance of the control (listener in form itself) works. Adding them through PopulationView's design view (listener in PopulationView) does not.
What complicates thing is I have a BackgroundWorker in my form which is in charge of generating the PopulationModel for the PopulationView. Once that BackgroundWorker is done, it uses a BeginInvoke to tell the PopulationView it's time to draw.
However, all events behave the way described even before the BackgroundWorker is triggered with RunWorkerAsync. Is it possible it's still interfering?
Editing the PopulationView constructor, I had accidentally deleted the call to InitializeComponent(), where all the Designer code was. Silly, really. If you're ever using the Designer, make sure you call InitializeComponent from your constructor.
Related
I have a windows forms application in which I instantiate another form (from the main form) and call it's Show() method. For some reason I am unable to receive any mouse events on the child form (there are no controls on it). Mouse events work fine on the parent form (in the area with no controls).
However, I can get mouse events to work on the child form if I override the base class method.
protected override void OnMouseDown(MouseEventArgs e)
{
// This works fine
}
This seems totally wrong. What is happening that I'm missing?
I finally figured it out. I created a custom constructor for the child form. It didn't call the
InitializeComponent() method that you see in the normal constructor. Frankly I have no idea what the initializeComponent method does, but I do know that it wont let you have any mouse events. Although this is kinda stupid I hope that it might save somebody else a headache.
I should have chained my overloaded constructors like this:
public ChildForm(... params ...) : this()
{
// code here...
}
Sorry first, because I see another question, but both of the ans. and ques. is not clear enough
How can I raise a parent event from a user control in WPF?
In my MainWindow.xaml, I had a right Panel
<local:RightSideContent x:Name="RightPanel" Grid.Column="1">
So in the MainWindow.xaml.cs, if I want rise an event to this panel, I made the code like this:
public delegate void Event1();
public MainWindow()
{
this.InitializeComponent();
Event1 obj = new Event1(this.RightPanel.func);
obj();
// Insert code required on object creation below this point.
}
And in RightPanel class, I declare the function func
The question is: if I am in the RightPanel Class, how I raise an event to the MainWindow, because I can't wrote something like this.RightPanel.func.....
And by the way I am in another class that do not have xaml file, if I want raise an event to a UserControl, how can I do?
Sorry, I don't quite have enough rep to post a comment to clarify, but as I see it, there are three possible things you are trying to do here.
You are trying to trigger an event on MainWindow, from some code that doesn't reside in MainWindow. In which case, you need to make sure that you have a reference to MainWindow, and that there is a public method on MainWindow that will trigger that event.
You want MainWindow to handle a click etc that comes from RightPanel. In that case you simply put a Button.Click="blah" (or whatever the event is) attribute on your MainWindow, and it will catch any button clicks from below it that are not handled lower down. In fact you can even handle it lower down and make sure that you set the EventArgs so that it is effectively unhandled, so that you can then handle it higher up as well.
You want to be able to handle a custom event generated in RightPanel, in a similar way to the way you would the button click scenario from item 2 above. In this case, I would direct you to http://msdn.microsoft.com/en-us/library/ms742806.aspx which is the documentation for Routed Events in WPF, and you should be able to work out how to create your own RoutedEvent from there.
I'm creating a base class for a button that inherits from Control as opposed to ButtonBase.
I'm using reflector to look at ButtonBase to make sure I don't overlook anything important and I'm puzzled with the contents of the WndProc method.
There's checks in there for things like button up, click and capture changed, which as far as I can tell are all handled within the relevent 'On' methods of the class.
Does anyone know why they are in there?
It is a wrapper for the native Windows button control as well. In a nutshell:
0x00f5 = BM_CLICK: run OnClick()
0x2111 = BN_CLICKED notification : run OnClick()
a bunch of workarounds to deal with OwnerDraw.
You don't have to worry about any of this since you don't wrap a native button and don't need owner draw. Do make sure you implement IButtonControl so your button behaves properly when Enter and Escape is pressed and it is selected as the form's Accept/CancelButton. Not strictly necessary, but it is automatic when you inherit from ButtonBase instead of Control.
I have my own custom control derived from System.Windows.Forms.TreeView which is present on the designer toolbox.
I add an instance of this custom control to my form (using the designer).
The purpose I created an inherited control is that I want to let the control itself handle its events since it's supposed to act as a View in a standard MVC design. I.e. when the node selection in the treeview changes I want the view to handle all interactions with the Model.
The problem is that when I add an event for my custom control (using the designer), the event gets added to my MainForm class. The only option in such case is to forward every event into my custom control, which doesn't feel very optimal.
Is there a way to control which class the event gets added to? I know it's technically possible since I can edit the auto-generated code for my MainForm and make the event being triggered into the custom control. That's clearly not the proper solution though.
Thanks.
why don't you just override some of the methods in your derived class, e.g.:
protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e)
{
}
Tom Frey is right. If you want the behavior on a certain event to be handled by the class that would normally fire the event, the preferred technique is to override the appropriate method that fires the event to perform your task. The eventing infrastructure is overkill and not really designed for what you're trying to do here.
The reason is that you want every instance of your view to perform these actions. You don't want these actions to be dynamically assigned and determined at runtime by things external to your view (which is what events are for).
One important thing to include when you perform such an override, however, is the call to the base's implementation. If you don't, you may encounter strange errors:
protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e)
{
// Do stuff you want done before here
base.OnNodeMouseClick(e);
// Do stuff you want done after here
}
Calling the base class will fire the event and may perform other actions besides. If you want something done before the event fires and any external subscribers do their thing, put it before the call to the base. If you want something done after all the events have fired and been handled, put it after. Contrived example: if your control handled some data binding, then you might want to verify the databinding exists before the call to base and you might want to verify it's valid after (in case a handler munged something).
From MSDN:
The OnNodeMouseClick method also
allows derived classes to handle the
event without attaching a delegate.
This is the preferred technique for handling the event in a derived
class.
Notes to Inheritors:
When overriding OnNodeMouseClick in
a derived class, be sure to call the
base class's OnNodeMouseClick method
so that registered delegates receive
the event.
I've create a WinForms control that inherits from System.Windows.Forms.UserControl...I've got some custom events on the control that I would like the consumer of my control to be able to see. I'm unable to actually get my events to show up in the Events tab of the Properties window during design time. This means the only way to assign the events is to programmatically write
myUserControl.MyCustomEvent += new MyUserControl.MyCustomEventHandler(EventHandlerFunction);
this is fine for me I guess but when someone else comes to use my UserControl they are not going to know that these events exist (unless they read the library doco...yeah right). I know the event will show up using Intellisense but it would be great if it could show in the properties window too.
Make sure your events are exposed as public. For example...
[Browsable(true)]
public event EventHandler MyCustomEvent;
A solution using delegate. For example i used for a custom ListView which handle item added event :
Declare your delegate :
public delegate void ItemAddedHandler(object sender, ItemEventArgs e)
then declare the event which use the delegate :
[Browsable(true)]
public event ItemAddedHandler ItemAdded;
Note : ItemEventArgs is a custom EventArgs
Hope can help you, works fine for me