Cannot unregister routed event handler (v2.0.1f1, C++)
Just for testing, I registered a MouseMove event handler to an element, then soon unregistered it as follows. However, it seems that unregistering the handler doesn't work and my handler was still being called by the system.
Code: Select all
static auto handler = [](BaseComponent* sender, const MouseEventArgs& args) {
...
};
parent->MouseMove() += handler;
parent->MouseMove() -= handler;
Re: Cannot unregister routed event handler (v2.0.1f1, C++)
Unfortunately when a delegate is built from a lambda, the equality operator always returns false. I am not sure if we can implement this properly (in fact C++ std::function is not comparable at all). You need to use normal functions (free function or member functions) for this to work properly.
Re: Cannot unregister routed event handler (v2.0.1f1, C++)
I see.
I think it's better if you provide another API to subscribe to the event because lambda is so much powerful that it will be pain if it is not supported.
For example in rxcpp (https://github.com/Reactive-Extensions/RxCpp), a 'subscription' is returned when you subscribe to an observable. Then you can call 'unsubscribe' method of the 'subscription' to remove the subscription.
Snippet from: http://reactive-extensions.github.io/Rx ... d208cedfda
I think it's better if you provide another API to subscribe to the event because lambda is so much powerful that it will be pain if it is not supported.
For example in rxcpp (https://github.com/Reactive-Extensions/RxCpp), a 'subscription' is returned when you subscribe to an observable. Then you can call 'unsubscribe' method of the 'subscription' to remove the subscription.
Snippet from: http://reactive-extensions.github.io/Rx ... d208cedfda
Code: Select all
auto values = rxcpp::observable<>::range(1, 3).
concat(rxcpp::observable<>::never<int>()).
finally([](){printf("The final action\n");});
auto subscription = values.subscribe(
[](int v){printf("OnNext: %d\n", v);},
[](){printf("OnCompleted\n");});
subscription.unsubscribe();
Re: Cannot unregister routed event handler (v2.0.1f1, C++)
Could you please file a ticket about it? This is something we need to solve. Thanks!
Re: Cannot unregister routed event handler (v2.0.1f1, C++)
OK, filed an issue here: https://bugs.noesisengine.com/view.php?id=1081
Looking forward for the feature in the next release !
Looking forward for the feature in the next release !
Re: Cannot unregister routed event handler (v2.0.1f1, C++)
Hi, I think I found another issue when using lambda as event handler.
I cannot capture complex object (e.g. NsString, std::string, std::vector).
For example:
emits compiler errors:
I cannot capture complex object (e.g. NsString, std::string, std::vector).
For example:
Code: Select all
std::vector<int> tmp;
element->AddHandler(event, [tmp](BaseComponent* sender, const RoutedEventArgs& args) {
});
1>D:\NNG2\NNG2\Framework\NoesisGUI\Include\NsCore/Delegate.inl(189): error C2338: Insufficient buffer size
1> D:\NNG2\NNG2\Framework\NoesisGUI\Include\NsCore/Delegate.inl(35): note: see reference to function template instantiation 'void Noesis::Core::Delegate<void (Noesis::Core::BaseComponent *,const Noesis::Gui::RoutedEventArgs &)>::FromFunctor<F>(const F &,Ret (__cdecl NoesisTutorial::EventBindingExtension::ProvideValue::<lambda_b5f86aaeec448541f8a10f7abd4dead0>::* )(Noesis::Core::BaseComponent *,const Noesis::Gui::RoutedEventArgs &) const)' being compiled
1> with
1> [
1> F=NoesisTutorial::EventBindingExtension::ProvideValue::<lambda_b5f86aaeec448541f8a10f7abd4dead0>,
1> Ret=void
1> ]
1> D:\NNG2\NNG2\Framework\NoesisGUI\Include\NsCore/Delegate.inl(35): note: see reference to function template instantiation 'void Noesis::Core::Delegate<void (Noesis::Core::BaseComponent *,const Noesis::Gui::RoutedEventArgs &)>::FromFunctor<F>(const F &,Ret (__cdecl NoesisTutorial::EventBindingExtension::ProvideValue::<lambda_b5f86aaeec448541f8a10f7abd4dead0>::* )(Noesis::Core::BaseComponent *,const Noesis::Gui::RoutedEventArgs &) const)' being compiled
1> with
1> [
1> F=NoesisTutorial::EventBindingExtension::ProvideValue::<lambda_b5f86aaeec448541f8a10f7abd4dead0>,
1> Ret=void
1> ]
1> MarkupExtension.cpp(127): note: see reference to function template instantiation 'Noesis::Core::Delegate<void (Noesis::Core::BaseComponent *,const Noesis::Gui::RoutedEventArgs &)>::Delegate<NoesisTutorial::EventBindingExtension::ProvideValue::<lambda_b5f86aaeec448541f8a10f7abd4dead0>,void>(const F &)' being compiled
1> with
1> [
1> F=NoesisTutorial::EventBindingExtension::ProvideValue::<lambda_b5f86aaeec448541f8a10f7abd4dead0>
1> ]
1> MarkupExtension.cpp(126): note: see reference to function template instantiation 'Noesis::Core::Delegate<void (Noesis::Core::BaseComponent *,const Noesis::Gui::RoutedEventArgs &)>::Delegate<NoesisTutorial::EventBindingExtension::ProvideValue::<lambda_b5f86aaeec448541f8a10f7abd4dead0>,void>(const F &)' being compiled
1> with
1> [
1> F=NoesisTutorial::EventBindingExtension::ProvideValue::<lambda_b5f86aaeec448541f8a10f7abd4dead0>
1> ]
Re: Cannot unregister routed event handler (v2.0.1f1, C++)
We implemented Noesis::Delegate because standard alternatives (std::function and similars) were too inefficient (at least not efficient in all our platforms) but it seems there are a few limitations with our implementation we should fix or evaluate again the current state of std::function (at first we don't like using C++11 stdlib features because implementations vary from platform to platform).
Could you please create a ticket about it?
Thanks!
Could you please create a ticket about it?
Thanks!
Re: Cannot unregister routed event handler (v2.0.1f1, C++)
Thanks. I filed the issue here: https://bugs.noesisengine.com/view.php?id=1141
Really appreciate if you can fix this along with https://bugs.noesisengine.com/view.php?id=1081. The ability to pass lambda/std::function as delegate is critical to our team productivity.
Really appreciate if you can fix this along with https://bugs.noesisengine.com/view.php?id=1081. The ability to pass lambda/std::function as delegate is critical to our team productivity.
Re: Cannot unregister routed event handler (v2.0.1f1, C++)
Somehow able to workaround the limitations (using FunctorToDelegate wrapper in the below codes) and created a utility to convert NoesisGUI events to rxcpp's observables.
I can now use it as follows:
Code: Select all
// Utility to get the N-th type from tuple
// Ref: https://stackoverflow.com/questions/16928669/how-to-get-n-th-type-from-a-tuple
template <int N, typename... Ts>
struct get;
template <int N, typename T, typename... Ts>
struct get<N, std::tuple<T, Ts...>>
{
using type = typename get<N - 1, std::tuple<Ts...>>::type;
};
template <typename T, typename... Ts>
struct get<0, std::tuple<T, Ts...>>
{
using type = T;
};
// Utility to strip const/ref/pointer from a type
// Ref https://stackoverflow.com/questions/14522496/remove-reference-with-const-references
template<class T> struct remove_all { typedef T type; };
template<class T> struct remove_all<T*> : remove_all<T> {};
template<class T> struct remove_all<T&> : remove_all<T> {};
template<class T> struct remove_all<T&&> : remove_all<T> {};
template<class T> struct remove_all<T const> : remove_all<T> {};
template<class T> struct remove_all<T volatile> : remove_all<T> {};
template<class T> struct remove_all<T const volatile> : remove_all<T> {};
// Wrap a functor and provide a method that can be used for NoesisGUI Delegate
template<typename Ret, typename ...Args>
class FunctorToDelegate{
public:
FunctorToDelegate(const std::function<Ret(Args...)> & callback) : m_callback(callback) { }
Ret Invoke(Args... args) { return m_callback(args...); }
private:
std::function<Ret(Args...)> m_callback;
};
// FromEvent: Convert NoesisGUI events to rxcpp observables
// When the observable is subscribed -> add a callback to the NoesisGUI event
// When the observable is unsubscribed -> remove the callback from the NoesisGUI event
template<typename Ret, typename ...Args, template<typename Ret, typename ...Args> typename C>
decltype(auto) FromEvent(C<Delegate<Ret(Args...)>> & _ev)
{
// Remove const & from the second Args type
// e.g. const MouseEventArgs & -> MouseEventArgs
// this type will be passed as parameter of the returned observable
using var = std::tuple<Args...> ;
using type = remove_all<get<1, var>::type>::type;
return rxcpp::observable<>::create<type>([_ev](auto && subscriber) {
auto ev = const_cast<C<Delegate<Ret(Args...)>> &>(_ev);
// NoesisGUI currently cannot handle lambda with object captures
// Use FunctorToDelegate to workaround it
auto wrapper = std::make_shared<FunctorToDelegate<Ret, Args...>>([subscriber](Args... args) -> Ret {
auto t = std::make_tuple(args...);
auto param = std::get<1>(t);
subscriber.on_next(param);
});
// Register a callback to NoesisGUI event
ev += MakeDelegate(wrapper.get(), &FunctorToDelegate<Ret, Args...>::Invoke);
subscriber.add([_ev, wrapper]() {
// In the event of unsubscribe, remove the callback from the NoesisGUI event
auto ev = const_cast<C<Delegate<Ret(Args...)>> &>(_ev);
ev -= MakeDelegate(wrapper.get(), &FunctorToDelegate<Ret, Args...>::Invoke);
});
});
}
Code: Select all
auto subscription = FromEvent(element->MouseDown()).subscribe([](auto && param) {
...
});
...
subscription.unsubscribe();
Who is online
Users browsing this forum: Bing [Bot] and 3 guests