While debugging, can I look into textBox1.TextChanged to see the number of event subscriptions? If yes, then how do I drill to it? I need to know how many subscriptions there are at a given time for debugging because it looks like an event is triggered multiple times, but I suspect this bug is really because textBox1.TextChanged += handler is being mismanaged in the application, so there are too many subscribers.
Here is a simplified version of what I think is happening. If possible, I just want to set a breakpoint and count up the number of subscriptions to "textBox1.TextChanged":
private void textBox1_TextChanged(object sender, EventArgs e)
{
textBox1.TextChanged += textBox1_TextChanged;
MessageBox.Show("asdf");
textBox1.TextChanged -= textBox1_TextChanged;
textBox1.Text = DateTime.Now.ToString();
textBox1.TextChanged += textBox1_TextChanged;
}
Is that possible or is it more complicated?
If you're only concerned with doing it under the debugger, rather than programmatically, then this is perhaps a simpler, non-invasive way:
class _24003458
{
event EventHandler MyEvent;
public void Test()
{
MyEvent += Handler1;
MyEvent += Handler2;
MyEvent(this, EventArgs.Empty);
}
void Handler1(object sender, EventArgs e)
{
throw new NotImplementedException();
}
void Handler2(object sender, EventArgs e)
{
throw new NotImplementedException();
}
}
Put a breakpoint on either of the event handlers, and when it breaks, look at the Locals tab. The event, when expanded, will show the invocation count and event handlers:
You will have to use Reflection to get to the invocation list of the event delegate:
textBox1.TextChanged += textBox1_TextChanged;
MessageBox.Show("asdf");
textBox1.TextChanged -= textBox1_TextChanged;
textBox1.Text = DateTime.Now.ToString();
textBox1.TextChanged += textBox1_TextChanged;
var eventField = textBox1.GetType().GetField("TextChanged", BindingFlags.GetField
| BindingFlags.NonPublic
| BindingFlags.Instance);
var subscriberCount = ((EventHandler)eventField.GetValue(textBox1))
.GetInvocationList().Length;
It is not possible with an event like this (for good reason), however, it is possable via reflection as Selman22 says, above) if you are using an event directly you can do so:
private event EventHandler handler;
var delegates = handler.GetInvocationList();
You can create a member method which you add to the object which implements the INotifyPropertyChanged interface. It makes debugging very easy:
#if DEBUG
public System.Delegate[] GetInvocationList()
{
return PropertyChanged?.GetInvocationList();
}
#endif
Related
I'm trying to add a RightTapped event to each CalendarViewDayItem. DoubleTapped event works fine, but RightTapped is not raised despite of that it's created.
This is how I have created them:
private void calviewSun_CalendarViewDayItemChanging(CalendarView sender, CalendarViewDayItemChangingEventArgs args)
{
args.Item.DoubleTapped += CalendarViewDayItem_DoubleTapped;
args.Item.RightTapped += CalendarViewDayItem_RightTapped;
}
I have tried setting breakpoints to check if they were raised but they had any other problems, but they are never raised. I have check that args.Item.IsRightTapEnbaled is set to true.
I don't know why is not raising the event.
Please try to use UIElement.AddHandler() Method to add right tapped event for the CalendarViewDayItem.
The code looks like this:
private void CalendarView_CalendarViewDayItemChanging(CalendarView sender, CalendarViewDayItemChangingEventArgs args)
{
args.Item.IsRightTapEnabled = true;
args.Item.DoubleTapped += Item_DoubleTapped;
// args.Item.RightTapped += Item_RightTapped;
args.Item.AddHandler(UIElement.RightTappedEvent, new RightTappedEventHandler(Item_RightTapped), true);
}
private void Item_RightTapped(object sender, RightTappedRoutedEventArgs e)
{
Debug.WriteLine("RightTapped");
}
Is it possible to trigger Window_Loaded on the Timer.Tick event like this ?
DispatcherTimer timer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(1)
};
timer.Tick += Window_Loaded;
timer.Start();
Or is there another way to do it ?
Your question probably confuses events and event handlers. In C#, events can only be raised from within the class they were declared in, unless they expose an internal or public method that can be called from outside. However, the Loaded event defined in FrameworkElement is not exposed that way, meaning you cannot raise it from your code.
What your code does is add your Window_Loaded event handler for the Loaded event, which is just a method. However, the sigatures of the corresponding Tick and the Loaded delegates do not match.
Tick - public delegate void EventHandler(object? sender, EventArgs e);
Loaded - public delegate void RoutedEventHandler(object sender, RoutedEventArgs e);
In order to add the window loaded event handler to the Tick event, you have to create a method or lambda that matches the Tick delegate and calls Window_Loaded with appropriate arguments, e.g.:
timer.Tick += OnTick;
private void OnTick(object sender, EventArgs e)
{
var routedEventArgs = new RoutedEventArgs();
// ...set the routed event args properties.
Window_Loaded(sender, routedEventArgs);
}
A word of caution. Although this might solve your problem it is most likely not the right approach for what you want to achieve. The Loaded event is called by the framework in the control's lifecycle.
Occurs when the element is laid out, rendered, and ready for interaction.
Whatever you are doing in your Window_loaded event handler should not be done periodically, because that does not comply with the sematics of this event. Maybe this is an XY problem.
public MainWindow()
{
InitializeComponent();
DispatcherTimer timer = new DispatcherTimer
{
Interval = TimeSpan.FromSeconds(1)
};
timer.Tick += Window_Loaded;
timer.Start();
}
private void Window_Loaded(object sender, EventArgs e)
{
}
How does addition assignment operator behaves here -
btn.Click += delegate(object sender, EventArgs e)
It adds an event handler to the event Click.
When Click event is raised all the handlers method added to it are called.
For example:
void BtnClickHandler1(object sender, EventArgs e)
{
MessageBox.Show("BtnClickHandler1");
}
void BtnClickHandler2(object sender, EventArgs e)
{
MessageBox.Show("BtnClickHandler2");
}
And you add these methods to Click event like this:
btn.Click += BtnClickHandler1
btn.Click += BtnClickHandler2
When button is clicked the methods will be called in the order you added them, so the message box will be:
BtnClickHandler1
BtnClickHandler2
If you want specific info about += operator, MSDN says:
The += operator is also used to specify a method that will be called
in response to an event; such methods are called event handlers. The
use of the += operator in this context is referred to as subscribing
to an event.
For more info look at:
https://msdn.microsoft.com/en-us/library/edzehd2t%28v=vs.110%29.aspx
http://www.dotnetperls.com/event
I'm trying to understand events better, and i've seen some lines of code that made me confused..
I know that, for example, when I want to declare an event and later subscribe to it i will do like this:
public event EventHandler MyEvent;
...
MyEvent += MyFunction;
MyEvent += new SomeClass().SomeFunction;
So here I declared the event and subscrbed some functions to it. It's easy.
Later I found this piece of code:
protected void Page_Load(object sender, EventArgs e)
{
for(int i =0; i<5; i++)
{
Button btn = new Button();
btn.Text = "Button " + i.ToString();
Panel1.Controls.Add(btn);
btn.Click += new EventHandler(this.BtnFunction);
}
}
void BtnFunction(object sender, EventArgs e)
{
Button btn = (Button)sender;
Label1.Text = btn.Text;
}
Now what I can't understand is this line here: btn.Click += new EventHandler(this.BtnFunction);
The questions are:
Why do I use the new EventHandler(this.BtnFuncion)? Isn't the Click event of a type EventHandler?
Does EventHandler have a constructor and why does it takes now the function that should subscribe to this event?
.Net BCL's event and User defined event are not different. Click Event is like the following:
public event EventHandler Click;
EventHandler is a delegate type, which is used in .Net BCL's event. I think you have seen some event handlers, like void function(object sender, EventArgs e). EventHandler is like the follwing:
public delegate void EventHandler(object sender, EventArgs e);
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
The second delegate, EventHandler<TEventArgs> is used when event required to send some information. For example:
public event EventHandler<SomeClass> MyEvent;
edit: Notice that SomeClass is recommended to inherit EventArgs for covariance
There is no difference. This is called syntax sugar. You don't have to help because the compiler can figure out that you meant to use a delegate. This sugar is important because without it you would have to write this to unsubscribe the event:
btn.Click -= new EventHandler(this.BtnFunction);
Which sets off major alarm bells to an unsuspecting new C# programmer that's learning the language: "Create a new delegate to remove an event handler??" Yes. Really. Nobody blows a fuse over:
btn.Click -= this.BtnFunction;
Even the delegate constructor call is syntax sugar, it actually requires two arguments under the hood. One that sets the Target property and another that sets the Method. The target is inferred by the compiler, it is this. The two argument constructor syntax is not legal in C#, a language like C++/CLI has it.
This is the short notation of assign an Event Handler:
MyEvent += MyFunction;
And this is the long notation:
btn.Click += new EventHandler(this.BtnFunction);
This line can be written like this:
btn.Click += this.BtnFunction;
As the title really, I'm in one part of my code and I would like to invoke any methods that have been added to the Button.Click handler.
How can I do this?
Do you mean you need to access it from elsewhere in your code? It may be an idea to refactor that section to it's own method then call that method whenever you need to access it (including in the Click event)
AVOID. Really. Seems like you handle some important logic right in the event handler.
Move the logic out of the handler.
You can do it via reflection..
Type t = typeof(Button);
object[] p = new object[1];
p[0] = EventArgs.Empty;
MethodInfo m = t.GetMethod("OnClick", BindingFlags.NonPublic | BindingFlags.Instance);
m.Invoke(btnYourButton, p);
You will need an event to act as a proxy, but you are pretty much better off just refactoring your code.
private EventHandler ButtonClick;
protected override void CreateChildControls()
{
base.CreateChildControls();
m_Button = new Button{Text = "Do something"};
m_Button.Click += ButtonClick;
ButtonClick += button_Click;
Controls.Add(m_Button);
}
private void MakeButtonDoStuff()
{
ButtonClick.Invoke(this, new EventArgs());
}
private void button_Click(object sender, EventArgs e)
{
}
Do not do this if you really dont need it. It will make a mess of your code.