I am new to WPF, and I am learning using the book Pro WPF C# 2010.
Now in the chapter about events, the book explains how to create events and register events in WPF and it gives, as an example, code from the ButtonBase class which is derived from some other class which the code doesn't mention clearly.
Now to understand the big picture, i have also tried to create my own simple class, and tried to register an event, which i'll try to raise later (just for my own understanding).
Here is the code I have written:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;
namespace WPFRoutedEvents
{
public class EventTest
{
private string variable = "Event has occured";
public static readonly RoutedEvent myTestEvent;
//Constructor
public static EventTest()
{
EventTest.myTestEvent = EventManager.RegisterRoutedEvent("TestEvent", RoutingStrategy.Bubble, typeof (RoutedEventHandler), typeof(EventTest));
}
public string getVariable()
{
return this.variable;
}
public event RoutedEventHandler myTestEvent
{
add
{
//Here is the problem
// I cannot use base.AddHandler () because it does not exist
}
remove
{
//Here is the problem
// I cannot use base.RemoveHandler() because it does not exist
}
}
}// end of class EventTest
}
Now since this class has not been derived from any class, i cannot access the base class function AddHandler.
My questions are the following:
1) Which class has the original AddHandler function implemented from which i need to extend my class?
2) Someone please briefly explain the pipeline from writing and event to finally setting it up to the point where it'll call the handler when it occurs, i.e starting from implementing an event, event handler, registering an event, defining the syntax of the event handler (coding part), and the pipeline from when en event occurs to until it is handled (actual execution of an event and event handler). It'll add more to my understanding of the text.
3) What i find in the book is ClickEvent which has already been implemented somewhere, it is created, registered, and finally handled. What i want to know is how will a programmer register some new type of event which has not yet been implemented (example could be triple click, just for the sake of example, otherwise i know it exists), and then register that event and then design a handler.
4) Is there any type of events, or some other equivalent, that occur on a particular state of a data (some variable, resource etc) instead of some input device event? Like for example while dragging to draw a line, it reaches a particular length?
Thanks!
The RoutedEvent system is centered around the UIElement class and its AddHandler method.
You should only create routed events in classes that inherit UIElement.
All other classes should use ordinary CLR events.
When you register a routed event, UIElement will prepare to store handlers for the event in instances of your class.
When you call AddHandler, UIElement will add the handler to something like a Dictionary<RoutedEvent, Delegate>.
When you add an event handler in XAML, the generated MyFile.xaml.g.cs code will add the handler using the CLR event accessor.
When you call RaiseEvent, UIElement will loop through its dictionary and call each handler.
For more information about field-like and custom events in C#, see my blog.
Related
I have been finding that “Windows Forms App (.NET Core)” projects lack the functionality of normal “.NET framework” apps. I'm specifically using .NET Core 3.1.
I want to be able to raise a form event on an object, but cannot find a way to do this. In my example, I want to call click on a System.Windows.Forms.TextBox. I know calling TextBox.Focus() will essentially emulate the behavior, but that's not the point.
Calling an event handler for the forms apps object does not do the job either. It only calls my custom code, not the actual base event handlers. And Control.RaiseEvent does not exist in .NET core. I don't think Control.Invoke can do the job either, but I haven't tested.
The answer is that control events are callable through subclassed controls. For example
public class TestPictureBox : PictureBox
{
public void CallClick(EventArgs e = null) => base.OnClick(e ?? EventArgs.Empty);
public void CallResize(EventArgs e = null) => base.OnResize(e ?? EventArgs.Empty);
}
With these example functions you can raise the control’s events.
I'm creating an app, there is some class that does some background operations and after all is done, parent object is notified using event. To provide event functionality i use following code:
public delegate void ShopStateChangedEventHandler(object sender, QuantityManagerEventArgs ea);
public event ShopStateChangedEventHandler ShopStateChanged;
protected virtual void WhenShopStateChanged(QuantityManagerEventArgs ea)
{
if (ShopStateChanged != null)
{
ShopStateChanged(this, ea);
}
}
It was working fine in all cases while I was using this piece of code with classes I've made, today I needed to have some custom made event added to one of forms in my application. Unfortunately i'm getting build error saying that compiler was unable to find ShopStateChangedEventHandler in form that is parent to form with custom event, and error is about line that adds listener
qmgr.ShopStateChanged += new ShopStateChangedEventHandler(qmgr_ShopStateChanged);
I really have no clue where to look for source of this error while in all other classes where i use this code all works fine, i suspect is it either because fact that the class i try to add custom event inherits from Form or maybe because it is partial class. As for now im far in the woods if it comes to solving it and I have no idea how to crunch it.
I hope you could suggest me what to do, or how to alter my code to make it all work with form.
thanks in advance
mth
EDIT
error is CS2046
The type or namespace name 'type/namespace' could not be found (are you missing a using directive or an assembly reference?)
all classes and forms belong to the same namespace
and as for qmgr_ShopStateChanged for now its just empty method
void qmgr_ShopStateChanged(object sender, QuantityManagerEventArgs ea)
{
}
qmgr is instance of form that contains custom event code, qmgr and qmgr_ShopStateChanged along with code that creates listener and makes problem, belongs to main form of application (frmMain).
Declare your delegate directly on your namespace outside any class.
I have one WinForms control project that produces a dll. There is a second dll project (also winforms control) that uses the first project. There is a third winforms project, this time a form, that uses the second project. So [Third Project] <>------> [Second Project] <>--------> [First Project]
The first project exposes a static event. I'm trying to subscribe to that event from the third project. The event stays as null (not subscriptions) after the += call.
Why is it not subscribing? Is it because the Winforms controls have their own thread? The FirstProject user control is created on the fly at some point in time. But I will expect the static to work correctly, without doing anything else,
Project 1
namespace Something
{
public partial class FirstClass : UserControl
{
...
public delegate void EventHandler();
public static event EventHandler MyEvent;
...
}
}
Project 3
namespace Another
{
public partial class ThirdClass : Form
{
...
public ThirdClass()
{
....
Something.FirstClass.MyEvent += new Something.FirstClass.EventHandler(MyHandler);
}
public void MyHandler()
{
}
...
}
}
EDIT
I have created a small application with the basics to get the three projects and the static event. And it works. Therefore something else is going on.
EDIT 2
The dll that contained the first project, the one with the event, was being loaded twice. I have just added an alias, but didn't help. And still will not explain when just after the += the event is still null.
EDIT 3 I transformed the event so I have the add/remove accessors pair. It does enter into the add. The Handler method gets the value correctly (and therefore no null), but once it goes outside, is null again.
The static event should work just fine. Try to debug your code to make sure the event registration is being called and that the event itself gets fired as expected. The event does not care about threads. It will accept the registration either way. Threading will, however, cause an exception if you try to edit the form on a thread besides the UI thread.
And the reason will be in my EDIT 2. Because is a static event, loading twice the dll (two different paths) was creating two different static events (or two different handlers). My EDIT 3 clearly showed that the event was being subscribed to.
Once I forced the third project (the one subscribing to the static event) to load the dll from the same location as the project creating the event (I didn't wanted to use the GAC), all worked.
I've got a program I am working on that has multiple windows. The windows are similar in functionality and I want to have a single event handler to cover a button press event for each window in the application. Is this possible?
If you need to bind a handler in code behind you can encapsulate a handler by delegate and inject into the Windows which are required it.
For instance using Action<T>:
Action<string> commonHandler = (parameter) =>
{
// handler code here
};
class MyWindiow
{
public MyWindiow(Action<string> handler)
{
// store to local and assign to button click
// button.CLick += (o, e) => { handler(parameterToBepassed); }
}
}
I'd look into using a framework to help you out here. My favorite is Prism v4.
If you follow the M-V-VM design pattern you're life will be a lot easier. You'll need to understand Data Binding and DataContext.
That being said, if you decide to go this path, you can bind each of your windows to a command:
<Button Command="{Binding DoFooCommand}" Content="DoFoo"/>
You're ViewModel would have a DelegateCommand member to execute.
public class SomeViewModel : NotificationObject
{
public SomeViewModel()
{
DoFooCommand = new DelegateCommand(ExecuteFoo);
}
public DelegateCommand DoFooCommand { get; set; }
private void ExecuteFoo()
{
//Use the EventAggregator to publish a common event
}
}
And finally, somewhere else in your solution you'll have a code file/class that subscribes to the event and waits for someone to publish the event to process it.
public class SomeOtherPlace
{
public SomeOtherPlace()
{
//Use the EventAggregator to subscribe to the common event
}
public void FooBarMethodToCallWhenEventIsPublished(SomePayload payload)
{
//Do whatever you need to do here...
}
}
I realize some of the things were left out (such as what a "SomePayload" is... look into the EventAggregator information), but I did not want to get into it too much. Just give you a guide on where to go for information and some base code to work off of. If you decide to use the EventAggregator then you'll need to ensure that your subscribing call and publishing calls are utilizing the SAME instance of the EventAggregator. You can do this by looking into MEF. Prism is setup to work with MEF perfectly... I'm not going to lie. Doing all this requires a bit of a learning curve, but it will be worthwhile in the end when you can unit test your ViewModels easily and have your code loosely coupled. The EventAggregator is a great way for different classes to communicate to each other without relying on knowing about each other. And MEF is great for having a Container for your services that you want to utilize across your application.
Hope that gave you a bit of insight on how to go about doing what you want to do on the correct path.
I'm trying to work with an old com control (a control array), the following samples: 5435293, 39541, 5497403, 5738092 explain (or at least what I understand) how to handle events of control arrays with .net controls, so they have Sender and EventArgs.
My question will be: How can you handle the events of an old com control array?.
EDIT:
The array will be created dynamically at the start, for example: Q. How many connections do you want? A. 5
example:
the control has this event: control_connected(int status, string description)
I can make some function with the same arguments and asign it to the connected event, but i cant figure out how to do it with a control array.
Ty so much for your help, and sorry about the crappy English... I'm not a navite English speaker
COM events have a different modal, you do not have one handler per event, you have an event sink object that hooks every event the COM server plan to raise. If you just hook the ActiveX events with delegates, event sink RCWs will be created and may cause crashes later, so I assume you are creating your own event sink class.
Since you have your own event sink class, you must follow the event publisher's event signature. The signatures do not have a sender argument, since the COM server assumes you have a reference to the sender, thus there is no need to send it again every time an event is raised.
You can, of cause, cache the server's reference in your event sink object for later use. Your event sink object can declare its own version of managed events with a sender parameter, and pass the cached COM server as the sender argument when it raises events.
Something like
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
[TypeLibType(TypeLibTypeFlags.FHidden)]
[Guid("eventGuid")]
[CLSCompliant(false)]
public interface IEvent
{
[DispId(123)]
void control_connected(int status, string description);
}
public class EventSink:IEvent
{
object control;
public EventSink (object control)
{
this.control=control;
}
public event EventHandler<ControlConnectedEventArgs> ControlConnected;
void control_connected(int status, string description);
{
EventHandler<ControlConnectedEventArgs> temp=this.ControlConnected;
if(temp!=null)
temp(this.control, new ControlConnectedEventArgs(status,description));
}
}
If you have an array of COM servers, just declare an array of event sinks, attach each sink to each COM server with ConnectionPointCookie, and wire the event handlers from the event sink instead of the COM servers.