如何自动生成WPF事件的扩展方法库 - > IObservable

时间:2021-02-02 23:55:22

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.

这些天我几乎只在我的C#WPF应用程序中使用Reactive Extensions。添加和删​​除事件处理程序是一种反模式,我完全嫉妒F#事件实现IObservable这一事实。

To help C# developers the RX folks provide the below method ( and some others of varying type safeness )

为了帮助C#开发人员,RX人员提供了以下方法(以及其他一些不同类型的安全性)

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 ...

这不是火箭科学,我一直在考虑建立一个库,我可以根据需要一次添加这些扩展方法。但是我确信一些智能cookie可以编写一个T4模板,通过反射处理WPF库中的所有控件,并生成我需要的所有扩展方法。我的问题是......

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.

是否有人编写过这样的代码生成器来将事件映射到上面的可观察对象,如果不是,有人会对如何做到这一点有任何建议吗?关于.Net反射,我不是很好,但是一些种子代码可能会让我开始。

1 个解决方案

#1


6  

To get all the types deriving from FrameworkElement, you could use

要获取从FrameworkElement派生的所有类型,您可以使用

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.

然后你可以使用type.GetEvents()来获取每种类型的事件。你得到的EventInfo将让你看到名称,类型,参数等内容。

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.

我在GitHub上放了一个示例程序以及输出示例。

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.

存在一些输出无法正常工作的风险,我还没有尝试过所有这些:)我确实确保它们都构建完成,并且至少其中一些输出正常工作。

#1


6  

To get all the types deriving from FrameworkElement, you could use

要获取从FrameworkElement派生的所有类型,您可以使用

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.

然后你可以使用type.GetEvents()来获取每种类型的事件。你得到的EventInfo将让你看到名称,类型,参数等内容。

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.

我在GitHub上放了一个示例程序以及输出示例。

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.

存在一些输出无法正常工作的风险,我还没有尝试过所有这些:)我确实确保它们都构建完成,并且至少其中一些输出正常工作。