I almost exclusively use Reactive Extensions in my C# WPF apps these days. Adding and removing event handlers is an anti pattern and I'm completely jealous of the fact that F# events implement IObservable.
To help C# developers the RX folks provide the below method ( and some others of varying type safeness )
public static
IObservable<EventPattern<TEventArgs>>
FromEventPattern<TDelegate, TEventArgs>
( Action<TDelegate> addHandler
, Action<TDelegate> removeHandler
)
where TEventArgs : EventArgs
http://msdn.microsoft.com/en-us/library/hh211731(v=vs.103).aspx
I would use it like so
var movingEvents = Observable.FromEventPattern<MouseEventHandler,
MouseEventArgs>(h => this.MouseMove += h, h => this.MouseMove -= h);
However this is tedious. What I'd like to be able to do is
var movingEvents = h.MouseMoveObserver();
and be done with it. Such an extension method would look like
IObservable<MouseEventArgs> MouseMoveObserver(this Canvas This){
return Observable.FromEventPattern<MouseEventHandler,
MouseEventArgs>(h => This.MouseMove += h, h => This.MouseMove -= h);
}
It's not rocket science and I've been considering setting up a library where I add these extension methods one at a time as I need them. However I am sure some smart cookie could write a T4 template that processes all the controls in the WPF library via reflection and generates all the extension methods I would ever need. My question is ...
Has anybody written such a code generator to map events to observables as above and if not would someone have any suggestions on how to do this? I'm not so good with regards to .Net reflection but some seed code might get me started.
To get all the types deriving from FrameworkElement, you could use
var typesToDo = from t in Assembly.GetAssembly(typeof(FrameworkElement)).GetTypes()
where t.IsSubclassOf(typeof(FrameworkElement))
&& t.IsPublic
&& t.GetEvents().Any()
select t;
and then you can use type.GetEvents() to get the events of each type. The EventInfo you get back will let you look at things like name, type, arguments etc.
You need to do a bit of extra work to cope with generic events, but it's not a huge amount.
I've put an example program up on GitHub along with an example of the output.
There is a risk that some of the output doesn't work properly, I haven't tried them all :) I did make sure they all build, and that at least some of them work correctly.
Related
This may be a remedial question, but my research is spinning me in circles right now (especially as a Java developer) and looking at several different Rx wrapper libraries. All I want is to take a ListView<MusicNote>.SelectedItem and wrap it into an IObservable, emitting a stream of the current single selected value. What is the easiest means to do this? Should I use the ReactiveProperty, Rx-XAML, or some library? Or is there an easy built-in way to do this with Rx.NET? I would prefer to not use a traditional event method stub that VS generates. Although I could push values in that, it feels messy and is not the paradigm I want.
this.keySelector.SelectedItem // turn this ListView's SelectedItem into an IObservable
One way of doing it in Rx.Net is the following:
var whenSelectionChange = Observable.FromEventPattern(h => listView.SelectedIndexChanged += h,
h => listView.SelectedIndexChanged -= h)
.Select(_ => listView.SelectedItem);
Basically, FromEventPattern() generates an observable sequence from the SelectedIndexChanged events triggered by your ListView. The Select() will be called each time an event is triggered, so you can get the selected index from your list and return it. The whenSelectionChange will be an IObservable<int> where each added element is the new selected index.
I have never used it, but you can take a look at http://reactiveui.net/ It's a MVVM framework that seems to integrate well with RX.Net and it is supported on all mobile platforms.
Thanks for all your help guys. This is ultimately what I ended up doing. Although I didn't want to do it this way initially it seems to be the simplest. And here is the final product of my work https://goo.gl/HTF3zd
private readonly ReplaySubject<TuningChangeEvent> tuningChange = new ReplaySubject<TuningChangeEvent>();
private void OneTuner_ValueChanged(object sender, RangeBaseValueChangedEventArgs e) {
tuningChange.OnNext(TuningChangeEvent.tune(1,Convert.ToInt32(OneTuner.Value)));
}
I have a simple Windows Phone 8 app with a button and a textbox. How do I use Reactive Extensions for the button Tap and Hold event to change the TextBox text?
void AttachRx()
{
IScheduler cs = new DispatcherScheduler(Deployment.Current.Dispatcher);
Observable.FromEvent<System.Windows.Input.KeyEventArgs>(btn, "Tap").Throttle(TimeSpan.FromSeconds(.5), cs)
.Do(a => ChangeText()).Subscribe();
}
error message:
{System.InvalidOperationException: The event delegate must be of the form void Handler(object, T) where T : EventArgs.
at Microsoft.Phone.Reactive.Observable.FromEvent[TEventArgs](Object target, String eventName)
at PhoneApp4.MainPage.AttachRx()
at PhoneApp4.MainPage..ctor()}
There are a few issues to address here.
The error you've reported is specifically saying that the delegate you are trying to add to the Tap event is not compatible - which makes sense because I don't imagine the Tap event has a KeyEventArgs payload (I think it is GestureEventArgs)? You are also probably better off using Observable.FromEventPattern as used in my example below. It's easier as you can get away with inferring the EventArgs type.
Caveat - As I have only WP8.1 SDK on my laptop at the moment, I have only the Win RT Tapped Event which is different from Tap, so I've just read the docs on Tap and not run the example below.
Assuming a Button called btn and a TextBox called txt and a function string GetText() that gets the text to set, do this:
Observable.FromEventPattern<GestureEventArgs>(btn, "Tap")
.Throttle(TimeSpan.FromSeconds(0.5))
.Select(_ => GetText())
.ObserveOnDispatcher()
.Subscribe(x => this.txt.Text = x);
Note a few things here:
Use FromEventPattern when standard .NET events are available - it better suited for this than FromEvent which really exists to handle non-conforming delegates.
Don't use Do like this. It works as a side-effect and isn't really idiomatic functional reactive programming. Doing this is in general could also cause unintended problems in more complex queries. Instead, project the input event to the desired result with a Select.
Don't run the Throttle on the dispatcher - use the default scheduler (or parameterize for testability with .Throttle(TimeSpan.FromSeconds(0.5), Scheduler.Default). You don't need the Throttle to run on the dispatcher - it's better off in the background. You only want to transfer to the dispatcher when you are ready to update the UI.
If you import nuget package rx-xaml you can use ObservableOnDispatcher to grab the current dispatcher. Although, for testability, you may wish to use the overload of ObserveOn (also in rx-xaml) that takes a dependency object like the page you are running on - e.g. ObserveOn(this) if you set up the subscription in the page code-behind for example, the page itself will do.
The example above assumes that GetText is synchronous. If you need to make an asynchronous call to get the text you wish to display, use the following pattern (assuming that GetText has a Task<String> return type):
Observable.FromEventPattern<GestureEventArgs>(btn, "Tap")
.Throttle(TimeSpan.FromSeconds(0.5), Scheduler.Default)
.Select(_ => Observable.FromAsync(GetText)
.ObserveOn(this))
.Switch()
.Subscribe(x => this.Name.Text = x);
Note the strange looking placement of ObserveOn inside the Select. The reasons for this are quite complex to explain briefly (and I'm not sure how relevant it is to this question), but basically it avoids a race condition where if a long running async GetText call for an earlier event could over-write the results of a short running call due to a later event.
For a simple example, if I had some sort of button UI class, could I write a function that takes an expression that points to its Click event handler:
SomeMethod<SomeButtonClass>(button => button.Click);
I'm trying to eliminate some magic strings currently being used for a system to make events awaitable. The code in question is derived from a blog post by Frank Krueger (a worthwhile read, if you want some background).
public static Task<TEventArgs> GetEventAsync<TEventArgs>(this object eventSource, string eventName) where TEventArgs : EventArgs {
//...
Type type = eventSource.GetType();
EventInfo ev = type.GetEvent(eventName);
//...
}
While the specifics inside probably aren't important, the full method allows you to use an Event triggering as the completion source for a Task, making it easier to manage with await. For some class that raises an event, you can tie into a Task based on that event with a simple call.
Task<EventArgs> eventTask = someEventCausingObject.GetEventAsync<EventArgs>("SomeEventHandler");
// traditionally used as someEventCausingObject.SomeEventHandler += ...;
await eventTask;
// Proceed back here when SomeEventHandler event is raised.
I have been using this happily for a couple projects, but it has its drawbacks, one of the biggest being the use of hard-coded event name strings. This makes event name changes turn into runtime exceptions, and determining usage of the event is difficult.
I started trying to make a version that would allow the EventHandler to be passed in as part of an Expression with the goal of something like this:
await someEventCausingObject.GetEventAsync<EventCausingClass, EventArgs>(x => x.SomeEventHandler);
...with the corresponding method signature...
public static Task<TEventArgs> GetEventAsync<TSource, TEventArgs>(this TSource eventSource, Expression<Func<TSource, EventHandler>> eventHandlerExpression) where TEventArgs : EventArgs {
//...
}
Unfortunately, the lambda expression in the calling code causes a compile error:
Error CS0070: The event `SomeEventHandler' can only appear on the left hand side of += or -= when used outside of the type `EventCausingClass'.
This makes some sense given how event handlers are typically used, but I was hoping to find a better solution going forward than the pre-specified string name. It seems searches for combinations of "expression" and "eventhandler" all tend to be polluted with people describing lambda expressions for beginning += event handler assignment. I'm hoping I am missing something obvious here.
No, it is not possible to target an event. Basically event is not a real type member, but just C# syntax which produces add_EventName and remove_EventName methods pair.
You could try refer to these internal methods name, but it's not possible in C# - http://msdn.microsoft.com/en-us/library/z47a7kdw.aspx
There are many similar questions in SO, with the same answer NO - like this one from Jon Skeet https://stackoverflow.com/a/4756021/2170171
If you're real crazy, you can try something like
private static void Subscribe(Action addHandler)
{
var IL = addHandler.Method.GetMethodBody().GetILAsByteArray();
// Magic here, in which we understand ClassName and EventName
???
}
with usage like
Subscribe(() => new Button().Click += null);
You could try using Cecil http://www.mono-project.com/Cecil for analyzing IL, or implement your own logic as it should not be too hard for predictable line of code.
I don't think that it is good solution though, as it just replaces one headache (proper event naming) with another one (proper Subscribe calling). Though, it will help with rename stuff.
When I use Reactive Extensions (Rx) with linq filter what happen under the hood?
Is this,
var move = Observable.FromEventPattern<MouseEventArgs>(frm, "MouseMove");
IObservable<System.Drawing.Point> points = from evt in move
select evt.EventArgs.Location;
var overfirstbisector = from pos in points
where pos.X == pos.Y
select pos;
var movesub = overfirstbisector.Subscribe(pos => Console.WriteLine("mouse at " + pos));
more efficient from this?
private void MouseMove(object sender, EventArgs args)
{
if (args.Location.X == args.LocationY)
Console.WriteLine("mouse at " + args.Location);
}
I dont talk about the filtering logic itself but about the events behavior of the methods.
In Rx do the event raised exactly the same way of the regular event but with warapper or there is somthing special under the hood?
In this case, there's no algorithmic performance benefit for using the Rx query over the typical event handler - in fact, your Rx query may actually be marginally slower than the typical event handler. "Under the hood" the Rx query is basically doing the same thing as the typical event handler, but in a cleaner way.
The Rx query is not more efficient than the directly subscribing the events. Under the hood, the Rx query is still subscribing to the events and adding a bit of logic (e.g. for the schedulers), so I would say you are trading a bit of performance for increased readability, flexibility (since you can quickly change and adapt the query) and testability (since the Rx query can be much more easily unit-tested).
There is nothing "special" about Rx. Rx is just a library, not a language feature. If you wanted to, you could have built Rx yourself in a normal old C# project, it just happened that the smart people at Microsoft thought of it first. The code is open source now so you can just download it and see how it all works (admittedly it got a lot more complex in v2)
In your example, the Rx code will need to do the following:
Reflectively look for an event called "MouseMove" on the frm object
Create an observable sequence (IObservable<MouseEventArgs>) from the event
Ensure the safe semantics of the implicit IObservable contract e.g. that values are sequential, the subscriptions are thread safe etc..
Do the condition check
Subscribe to the sequence (safely)
Print to the console when a value is pushed.
In contrast, the non-rx code does the following:
Recieves a virtual call from a base class
does the condition check
Prints the value to the console.
So no reflection & no safety checks, but the same result. In practice the performance will be very fast for both so you are unlikely to see any performance difference.
With regards to Unit testing, I think any argument for or against is nonsense. We are talking about a MouseMove event, how are you going to unit test that? Putting all that Rx in your code base doesn't appear to pay for itself in my opinion (slower, more code, another framework for a dev to understand, etc...)
I want a WinForm to register the OnLoad event with another object - something like:
SomeObject.RegisterEvent(action => this.OnLoad += (o,e) => action(o,e));
Is this possible? I don't mind creating delegates or expressions for 'helpers' on the 'SomeObject' side to do this, but I'm trying to figure out what my method signature would even look like for the RegisterEvent(...).
The RegisterEvent method would need to look like this:
void RegisterEvent(Action<EventHandler> addEventHandler)
{
addEventHandler((sender, e) =>
{
// loaded
});
}
Usage:
someObject.RegisterEvent(handler => { this.OnLoad += handler; });
SomeObject.RegisterEvent(action => { this.OnLoad += (o,e) => {action(o,e);}; });
If you really need to have something like that (always a good question, usually things like this are a tell signs of something a bit odd-ish about the design, but doesn't have to be),
I'd say you should look at The Reactive Extensions (Rx)....
They provide the ease with dealing and firing off your own 'events' more or less like properties or methods (and w/o the typical pain of delegates, add/subscribe or private limitations etc., over simplified a bit).
...and this could look like...
someObjectInstance.MyEvent.Subscribe(d=>
{
// ... your lambda more or less
});
...and in the class there is if simplified just one Subject<MyEventData> _myEvent; and _myEvent.OnNext(data) (goes inside the method you want to rise from) + the property to expose that field (IObservable<MyEventData> MyEvent {get{return _myEvent;}}).
which is what you want really.
You can install them from NuGet and use in minutes. Though there is a learning curve for more tricky cases.
Plus you get the benefit of combining events in the future and lot more.
(not 'one of them', just a very good new piece of technology)