I have a delegate
public delegate bool Controller_PDF_FileDone(object sender,
ControllerTaskEventArgs e);
And an event
public event Controller_PDF_FileDone On_Controller_PDF_FileDone;
I need to use this "event" to call the method, Please let me know how.
Thanks in advance
Invoking event (from the same class where it is declared):
var e = On_Controller_PDF_FileDone;
if (e != null) {
e.Invoke(this, new ControllerTaskEventArgs());
}
Subscribing to an event (from the same class where it is declared):
On_Controller_PDF_FileDone += new Controller_PDF_FileDone(
YourHandlingMethod_On_Controller_PDF_FileDone);
Related
How to make a custom control or a custom panel receive events in design time in UWP?
For example, a custom control could receive an event on resizing and a custom panel an event when another control is pushed inside it.
If you want to receive an event when the custom control resized, you could subscribe to the SizeChanged event. When the size of control changed the SizeChanged event will be invoked and then you could handle the new size or previous size from SizeChangedEventArgs.
<Button SizeChanged="Button_SizeChanged"/>
private void Button_SizeChanged(object sender, SizeChangedEventArgs e)
{
// do some stuf
}
You could also create Resize event to listen to the variety of control size based on SizeChanged event.
<local:CustomControl Resize="CustomControl_Resize"/>
public sealed class CustomControl : TextBox
{
public event SizeChangedEventHandler Resize;
public CustomControl()
{
this.SizeChanged += CustomControl_SizeChanged;
}
private void CustomControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
if(this.Resize != null)
{
this.Resize(this, e);
}
}
}
could recieve an event on resize and a custom panel an event when another control is pushed inside it.
You could invoke your custom event in the ArrangeOverride method. Because the necessary pattern of an ArrangeOverride implementation is the loop through each element in Panel.Children. Always call the Arrange method on each of these elements.
public class BoxPanel : StackPanel
{
public event EventHandler<ElementEventArgs> AddedElement;
protected override Size ArrangeOverride(Size finalSize)
{
if (Children.Count > 0)
{
UIElement ele = Children.Last<UIElement>();
if (ele != null && AddedElement != null)
{
this.AddedElement(this, new ElementEventArgs(ele));
}
}
return base.ArrangeOverride(finalSize);
}
}
public class ElementEventArgs : EventArgs
{
private UIElement newElement;
public UIElement NewElement { get => newElement; set => newElement = value; }
public ElementEventArgs(UIElement ele)
{
this.newElement = ele;
}
}
If you have subscribed to the AddedElement event, the AddedElement event will be invoked when the new control pushed inside your custom panel.
<local:BoxPanel x:Name="MyBox" AddedElement="MyBox_AddedElement">
This is code of click event of MainPage
void ItemView_ItemClick(object sender, ItemClickEventArgs e)
{
var item = ((EventItem)e.ClickedItem);
this.Frame.Navigate(typeof(EventPage), new Navigator() { Parent = "Dashboard", Event = item });
}
In image the code of next page
The sender parameter of the loaded event is the control that raised the event (in this case, the current page); so its type is the type of the page, not Navigator.
Apparently you're trying to access the argument that was passed to Frame.Navigate. To do that, you should override the OnNavigatedTo method:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var param = (Navigator)e.Parameter;
...
}
In C# I can check if an event has any listeners:
C# Example:
public static event EventHandler OnClick;
if (OnClick != null)
OnClick(null, new EventArgs() );
In C++/CLI checking if the event is null is not necessary.
C++/CLI Example:
delegate void ClickDelegate( Object^ sender, MyEventArgs^ e );
event ClickDelegate^ OnClick;
OnClick (sender, args);
BUT, in the project I am working on, I don’t want to construct the MyEventArgs object if there are no listeners.
How do I find out if OnClick has any listeners in C++?
Based on the comment discussion with #BenVoigt on #svick's original answer and the new MSDN article on C++/CLI events, I have created a minimal example of how to do this correctly. This code compiles and runs in a Visual Studio 2013 CLR project template targeting .NET 4.5. I haven't tested on other runtimes and targets, but it only uses basic .NET components.
TL;DR:
Make the backing field private
Lock each add, remove, and raise call with System::Threading::Monitor
Use the standard event handler convention:
void MyEventHandler(Object ^sender, MyEventArgs ^e);
Use += and -= except when the backing field is a nullptr
My Solution:
// compile with: /clr
#include "stdafx.h"
using namespace System;
using System::Threading::Monitor;
public delegate void MyDelegate(Object ^sender, EventArgs ^e);
ref class EventSource {
private:
MyDelegate ^myEvent;
Object ^eventLock;
public:
EventSource()
{
eventLock = gcnew Object();
}
event MyDelegate^ Event {
void add(MyDelegate^ handler) {
Monitor::Enter(eventLock);
if (myEvent == nullptr)
{
myEvent = static_cast<MyDelegate^> (
Delegate::Combine(myEvent, handler));
}
else
{
myEvent += handler;
}
Monitor::Exit(eventLock);
}
void remove(MyDelegate^ handler) {
Monitor::Enter(eventLock);
if (myEvent != nullptr)
{
myEvent -= handler;
}
Monitor::Exit(eventLock);
}
void raise(Object ^sender, EventArgs ^e) {
Monitor::Enter(eventLock);
if (myEvent != nullptr)
myEvent->Invoke(sender, e);
Monitor::Exit(eventLock);
}
}
void Raise()
{
Event(this, EventArgs::Empty);
}
};
public ref struct EventReceiver {
void Handler(Object ^sender, EventArgs ^e) {
Console::WriteLine("In event handler");
}
};
int main() {
EventSource ^source = gcnew EventSource;
EventReceiver ^receiver = gcnew EventReceiver;
// hook event handler
source->Event += gcnew MyDelegate(receiver, &EventReceiver::Handler);
// raise event
source->Raise();
// unhook event handler
source->Event -= gcnew MyDelegate(receiver, &EventReceiver::Handler);
// raise event, but no handlers
source->Raise();
}
It seems you can't check that with "trivial events", like you used, because you don't have direct access to the underlying field (as with auto-implemented properties in C#).
If you want to do this, you can specify the event's accessor methods and the backing field explicitly. See How to: Define Event Accessor Methods on how exactly to do that.
In my windows phone app, I need to track some events to get a good flow. But I'm not sure how to handle them in good sequence.
What needs to be done at startup of the app:
Main view is loaded and corresponding view model instantiated
In the constructor of the view model I initiate a login sequence that signals when completed with an eventhandler
Now when the login sequence has finished AND the view is completely loaded I need to startup another sequence.
But here is the problem, the order of these 2 events 'completing' is not always the same...
I've use the EventToCommand from MVVMLight to signal the view model that the view has 'loaded'.
Any thoughts on how to synchronize this.
As you should not use wait handles or something similar on the UI thread. You will have to sync the two method using flags in your view model and check them before progressing.
So, implement two boolean properties in your view model. Now when the login dialog is finished set one of the properties (lets call it IsLoggedIn) to true, and when the initialization sequence is finished you set the other property (how about IsInitialized) to true. The trick now lies in the implementation of the setter of these two properties:
#region [IsInitialized]
public const string IsInitializedPropertyName = "IsInitialized";
private bool _isInitialized = false;
public bool IsInitialized {
get {
return _isInitialized;
}
set {
if (_isInitialized == value)
return;
var oldValue = _isInitialized;
_isInitialized = value;
RaisePropertyChanged(IsInitializedPropertyName);
InitializationComplete();
}
}
#endregion
#region [IsLoggedIn]
public const string IsLoggedInPropertyName = "IsLoggedIn";
private bool _isLoggedIn = false;
public bool IsLoggedIn {
get {
return _isLoggedIn;
}
set {
if (_isLoggedIn == value)
return;
var oldValue = _isLoggedIn;
_isLoggedIn = value;
RaisePropertyChanged(IsLoggedInPropertyName);
InitializationComplete();
}
}
#endregion
public void InitializationComplete() {
if (!(this.IsInitialized && this.IsLoggedIn))
return;
// put your code here
}
Alternatively you can remove the InitializationComplete from the setters and change InitializationComplete to:
public void InitializationComplete() {
// put your code here
}
Then subscribe to the 'PropertyChanged' event use the following implementation:
private void Class1_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) {
if (e.PropertyName == IsInitializedPropertyName || e.PropertyName == IsLoggedInPropertyName) {
if (this.IsInitialized && this.IsLoggedIn)
InitializationComplete();
}
}
I was wondering what's the proper way of raising events from C++/CLI. In C# one should first make a copy of the handler, check if it's not null, and then call it. Is there a similar practice for C++/CLI?
This isn't the whole story! You don't usually have to worry about null event handlers in C++/CLI. The code for these checks is generated for you. Consider the following trivial C++/CLI class.
public ref class MyClass
{
public:
event System::EventHandler ^ MyEvent;
};
If you compile this class, and disassemble it using Reflector, you get the following c# code.
public class MyClass
{
// Fields
private EventHandler <backing_store>MyEvent;
// Events
public event EventHandler MyEvent
{
[MethodImpl(MethodImplOptions.Synchronized)] add
{
this.<backing_store>MyEvent = (EventHandler) Delegate.Combine(this.<backing_store>MyEvent, value);
}
[MethodImpl(MethodImplOptions.Synchronized)] remove
{
this.<backing_store>MyEvent = (EventHandler) Delegate.Remove(this.<backing_store>MyEvent, value);
}
raise
{
EventHandler <tmp> = null;
<tmp> = this.<backing_store>MyEvent;
if (<tmp> != null)
{
<tmp>(value0, value1);
}
}
}
}
The usual checks are being done in the raise method. Unless you really want custom behavior, you should feel comfortable declaring your event as in the above class, and raising it without fear of a null handler.
C++/CLI allows you to override raise in custom event handlers so you don't have to test for null or copy when raising the event. Of course, inside your custom raise you still have to do this.
Example, adapted from the MSDN for correctness:
public delegate void f(int);
public ref struct E {
f ^ _E;
public:
void handler(int i) {
System::Console::WriteLine(i);
}
E() {
_E = nullptr;
}
event f^ Event {
void add(f ^ d) {
_E += d;
}
void remove(f ^ d) {
_E -= d;
}
void raise(int i) {
f^ tmp = _E;
if (tmp) {
tmp->Invoke(i);
}
}
}
static void Go() {
E^ pE = gcnew E;
pE->Event += gcnew f(pE, &E::handler);
pE->Event(17);
}
};
int main() {
E::Go();
}
If your issue is that raise isn't private, then explicitly implement it like the docs say:
http://msdn.microsoft.com/en-us/library/5f3csfsa.aspx
In summary:
If you just use the event keyword, you create a "trivial" event. The compiler generates add/remove/raise and the delegate member for you. The generated raise function (as the docs say) checks for nullptr. Trivial events are documented here:
http://msdn.microsoft.com/en-us/library/4b612y2s.aspx
If you want "more control", for example to make raise private, then you have to explicitly implement the members as shown in the link. You must explicitly declare a data member for the delegate type. Then you use the event keyword to declare the event-related members, as in the Microsoft example:
// event keyword introduces the scope wherein I'm defining the required methods
// "f" is my delegate type
// "Event" is the unrealistic name of the event itself
event f^ Event
{
// add is public (because the event block is public)
// "_E" is the private delegate data member of type "f"
void add(f ^ d) { _E += d; }
// making remove private
private:
void remove(f ^ d) { _E -= d; }
// making raise protected
protected:
void raise(int i)
{
// check for nullptr
if (_E)
{
_E->Invoke(i);
}
}
}// end event block
Wordy, but there it is.
-reilly.