Hi i was just wondering if theres a way to give classes there own click event. For instance i have a card class, and is there a way of knowing when the user clicks on the rectangle (that displays the picture of the card) from that class?
or better yet, how do i go about knowing when the cards rectangle is clicked?
To get "mouse was clicked here" messages from Windows, you need to have a window handle; in WinForms, anything deriving from Windows.Forms.Control will have a window handle, and it will get mouse messages. Those messages will be translated automatically into invocations of the .NET MouseDown, MouseUp, MouseClick etc. events.
So probably your card should be a control. If it's not (e.g. if you have a "Hand" control that is responsible for managing and drawing lots of cards) then that control needs to be the one that gets mouse events (e.g. MouseClick) and figures out which card actually got clicked based on the context and the coordinates of the mouse event.
There are actually two parts of your problem: first is creating the event, and second is hooking it up to something.
Creating the event is the easy part:
public class Card {
public event EventHandler<MouseEventArgs> Click;
protected void OnClick(MouseEventArgs e) {
EventHandler<MouseEventArgs> handler = Click;
if(handler != null) {
handler(this, e);
}
}
internal void CheckIfClicked(MouseEventArgs e) {
if(/* this mouse event intersects this Card */) {
OnClick(e);
}
}
}
Then elsewhere you can set up subscribers for that event, like usual:
public class CardWatcher {
private Card card;
public CardWatcher(Card card) {
this.card = card;
this.card.Click += card_Clicked;
}
private void card_Clicked(object sender, MouseEventArgs e) {
// Our Card has been clicked; do something about it
}
}
(Note that we're attaching an event handler manually, but this is pretty much exactly the same code the Visual Studio designer would generate if you used the GUI to attach an event handler to a control.)
And then you need to somewhere capture those click events (actually, this seems like the crux of your issue):
public partial class CardContainer : UserControl {
private List<Card> cards = new List<Card>();
public CardContainer() {
InitializeComponent();
// Initialize cards here...
}
protected override void OnMouseUp(MouseEventArgs e) {
foreach(Card card in cards) {
card.CheckIfClicked(e);
}
base.OnMouseUp(e);
}
}
Notice that there are normally two ways of responding to an event:
Create a subclass class, and override the behavior of the OnEvent method
Attach an event handler delegate
As other answers have pointed out, the Windows operating system takes care of delivering events to objects that are windows (that is, objects that have a window handle). Within .NET, this means objects that are subclasses of Control.
It's easy enough to create such classes yourself, either by subclassing Control directly or by subclassing something like UserControl, which then allows you to create controls that can be containers for other controls that you create in the design view (the same way you create forms).
So, your choices are the following:
Make Card a control itself; then it can be positioned on forms and receive click events (and other events) directly. The drawback is that this can use a lot of resources if you have a lot of these elements active at one time, since each allocates a window handle from Windows.
Make a container for Cards that is a control. This container control can be positioned on forms and receive click events (and other events) directly. The drawback is that you have to figure out manually how to delegate those click events on to the individual cards. Since the actual Click event doesn't carry coordinates with it, you'll probably have to handle the MouseUp event instead.
Put your Cards into some other container (like a Form) and attach a handler to that container's Click (or MouseUp) event. In that handler, figure out if any of your Cards have been clicked on, and delegate the click events accordingly.
Note that all of this is independent of whether or not the Card itself has a Click event that users of the Card can subscribe to. If you look at the first code sample in this answer, there's no reason why the CheckIfClicked method on Card has to actually fire a real event, unless you have classes like CardWatcher which are interested in knowing about click events on Cards. If only the Card itself ever cares about the click event, then you can simply create a method like Card.HasBeenClicked(MouseEventArgs e), put your click-handling code there, and let CheckIfClicked call it directly.
You can easily add events to your class, but the only way the class can know when something was clicked is when it is, or has a component that is, based on a window.
That's what controls are for. If you need to write a class that can detect such events, I would recommend creating a control.
Related
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 having some difficulty using picture boxes as buttons. I'd like to have custom button graphics rather than using the plain-old windows forms Button control.
It works pretty well, except the buttons seem to lag when a single button is pressed rapidly. I'd like the OnClick method to be called immediately every time the Picture Box is clicked, but it seems to be registering a double-click event, even though I am not using that event.
The short version is I'd like to:
(Ideal) Disable the double-click event, since it appears this is what the Control is waiting for on every alternating click of the Picture Box and I never use it. Or,
(Acceptable) Write a generic DoubleClick event I can use for all Picture Boxes I plan to use as buttons.
I did write up a test program which shows that this is, in fact, what's happening. I wrote a MouseUp event that increments a counter by 1, and also added a OnClick even that increments a different counter by 1. When rapidly clicking the Picture Box linked to these events, the MouseUp counter is exactly double that of the OnClick counter.
I then added a DoubleClick event that calls the OnClick event. This, although not ideal, solves the problem perfectly well. If there is a way to write a generic DoubleClick event that all buttons could use, I think this would be acceptable.
Right now my DoubleClick event is just
private void pb_DoubleClick(object sender, EventArgs e)
{
pbOK_Click(sender, e); //This needs to be generic
}
I'd like to at least replace the DoubleClick line with something like
private void pb_DoubleClick(object sender, EventArgs e)
{
(Sender.ToString)_Click(sender, e); // Doesn't work quite like this.
}
I could write a special DoubleClick event for each Picture Box individually, but that is far from ideal and seems quite cumbersome, so I would prefer not to do that if it isn't necessary.
This is my first posted question, so thanks to anyone who takes the time to read this. Any advice would be greatly appreciated.
EDIT: This program is being developed for Windows CE, so the properties and events options for the objects is quite limited. I still may be missing something, but as far as I can tell the Properties list for buttons goes straight from GenerateMember to Location, with none of the Image options available. I apologize for not stating the target platform in the original post.
It is done with the Control.SetStyle() method, like this:
using System;
using System.Windows.Forms;
class MyButton : PictureBox {
public MyButton() {
this.SetStyle(ControlStyles.StandardDoubleClick, false);
}
}
Okay, my original answer was trash. My update:
Here's a link on how to get a controls Method name:
Link
In the link it has a Control c. To get your control (sender) use the following:
PictureBox picbox = (PictureBox) sender;
Next, call a method using a string(your class.Method.Name): Link
Now that should work. Hope it does.
Why don't you create your own control? This way, you don't have to do anything to get the behavior you want.
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public class ButtonPictureBox : PictureBox
{
protected override void OnDoubleClick(System.EventArgs e)
{
OnClick(e);
}
}
}
I don't know if this is possible on Windows CE though.
If you also want to hide the DoubleClick event in the form designer, you can add this to the class:
[Browsable(false)]
public new event EventHandler DoubleClick;
I need to change a certain DataGridView's property (a DataSourceUpdateMode for one of its binding) only when ALL of its initial data bindings are completed.
I tried subscribing to the "DataBindingComplete" event, but it's fired too many times (one or more time for each binding associated to the control); what I need is a more global "AllDataBindingsComplete" event, fired when the control is ready to be displayed to the user.
As a temporary workaround, I'm using the MouseDown event (I've assumed that when the user is able to click the control, it means that the control is displayed... :) and the events I'm playing with - SelectionChanged - are fired after the MouseDown):
protected override void OnMouseDown(MouseEventArgs e)
{
Binding selectedItemsBinding = this.DataBindings["SelectedItems"];
if (selectedItemsBinding != null)
{
selectedItemsBinding.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged;
}
base.OnMouseDown(e);
}
It works, but it smells like an ugly hack A LOT (and it's called too many times, only one time is enough for my needs).
Is there a better way?
(yes, I'm trying to adopt MVVM in a Windows Forms project, and I've added a bindable "SelectedItems" property to the DataGridView...)
What I've done at the Windows Forms form level, and may be improvised down to just the control(s) you want, is to subclass the Windows Forms baseclass into my own. Then, in its constructor, attach an extra event call to the Load() event.
So when everything else is completely loaded, only THEN will it hit my custom method (of the subclass). Since it is the bottom of the call-stack chain being attached to the event queue, I know it's last and everything else is done... Here's a snippet of the concept.
public class MyForm : Form
{
public MyForm()
{
this.Load += AfterEverythingElseLoaded;
}
private void AfterEverythingElseLoaded(object sender, EventArgs e)
{
// Do my own things here...
}
}
This concept can be applied to the Init() function too if that's more appropriate for your control... Let everything else within it get initialized(), then do you the "AfterInitialized()" function.
I'm making a custom control with a panel. I want to be able to drag and drop it so I've implemented that in the MouseDown event of my control. But I want the thing to react when you start drag to give a little feedback to the user. So in the MouseDown even I change the color. Then I want to change it back in the MouseUp event.
My control is not installed into VS2008 but just a class I've written that I instanciate at run time (I don't know in advance how many I need and so on). Now, my control exposes a MouseDown event so as to be able to be dragged. When I subscribe to this event from the parent application to actually perform the drag and drop my control is not repainted on its MouseUp event! In fact, the MouseUp is never invoked. If, on the other hand, I don't subscribe to the event in the parent app it works as intended.
What's going on? Is the parent interrupting the flow so that the MouseUp event never fires in my control? How do I get around this?
I'm not sure if you are using Windows Forms or WPF, but in Windows forms here is what I mean:
public class DerivedPanel : Panel
{
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
Capture = true;
}
protected override void OnMouseUp(MouseEventArgs e)
{
base.OnMouseUp(e);
Capture = false;
// Change your color or whatever here
}
}
In WPF there are two methods, CaptureMouse() and ReleaseMouseCapture() to do the same thing. When the control captures the mouse, it will received mouse events even if the cursor isn't over the control. This could be causing your problem. See MSDN Article
Do you capture the mouse in the custom control on the mousedown event? Try capturing on the mousedown and releasing the capture on the mouseup.
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