Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Second event handler not called due to cswinrt delegate combining #626

Closed
MilesCohen-MS opened this issue Dec 8, 2020 · 4 comments · Fixed by #997
Closed

Second event handler not called due to cswinrt delegate combining #626

MilesCohen-MS opened this issue Dec 8, 2020 · 4 comments · Fixed by #997
Assignees
Labels
bug Something isn't working fixed Issue has been fixed in an upcoming or existing release pri-2 Non-critical bugs/acceptable workaround
Milestone

Comments

@MilesCohen-MS
Copy link

In Microsoft.UI.Composition, the CompositionScopedBatch.Completed event is designed to fire a given event handler only once. Once this event is fired, the implementation of CompositionScopedBatch removes the event handler from the implementation's list and will no longer fire it.

In previous versions of .NET, if a 2nd event as added to the list after the first event fired, the second event would still be fireable. Using .NET5/cswinrt, the 2nd event does not end up being fired.

I think that reason is that cswinrt appears to manage the list of event handlers itself. The implementation only sees one event handler being passed to it, despite the caller actually having added 2 of them. When the first event is fired, the implementation ends up removing the entire list of event handlers rather than just the first one. So when the second event handler is added, it never gets called.

A workaround as a caller is to remove the first event handler after it is fired, and before adding the second handler. Doing this ensures that the second event handler is fired.

In this version of the calling code, the second handler is not called:
CompositionScopedBatch _batch;

       ...

        TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
        _batch.Completed += (sender, eventArgs) =>
        {
            Log.WriteLine("Completion 1");
            tcs.SetResult(true);                
        };
        await tcs.Task;
        _batch.Completed += (sender, eventArgs) =>
        {
            Log.WriteLine("Completed again!");
        };

In this version of the calling code, the second handler is called:

        TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
        TypedEventHandler<object,CompositionBatchCompletedEventArgs> myHandler = (sender, eventArgs) =>
        {
            Log.WriteLine("Completion 1");
            tcs.SetResult(true);
        };

        _batch.Completed += myHandler;
        await tcs.Task;
        _batch.Completed -= myHandler;

        _batch.Completed += (sender, eventArgs) =>
        {
            Log.WriteLine("Completed again!");
        };
@Scottj1s
Copy link
Member

Need to confirm whether WinRT supports assigning completion handlers after the first one has fired. Many languages with await support can implicitly only assign a single completion handler.

@Scottj1s Scottj1s added this to the Release 1.2.0 milestone Dec 11, 2020
@Scottj1s
Copy link
Member

WinRT appears to not support the above usage pattern of assigning the Completed handler multiple times:
From IAsyncAction.Completed Property:
"The Windows Runtime enforces that this property can only be set once on an action."

The cswinrt behavior of combining delegates is not a problem for event implementations that follow this guidance.

@Scottj1s Scottj1s self-assigned this Dec 11, 2020
@angelazhangmsft angelazhangmsft added bug Something isn't working pri-2 Non-critical bugs/acceptable workaround labels Mar 29, 2021
@angelazhangmsft
Copy link
Contributor

Without this fix, it wouldn’t be safe for customers to reuse a CompositionScopedBatch, in that they will not get called back if they add a second handler after the first handler fires. Might not be a common scenario, but we should have a fix before Reunion 1.0 ships.

@Scottj1s
Copy link
Member

Scottj1s commented Jun 9, 2021

discussing with Mano, solution would be in EventSource.Subscribe, to validate the COM ref count on the CCW for _eventInvoke and if 0, clear and recreate the cached _state

@angelazhangmsft angelazhangmsft added the fixed Issue has been fixed in an upcoming or existing release label Mar 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working fixed Issue has been fixed in an upcoming or existing release pri-2 Non-critical bugs/acceptable workaround
Projects
None yet
5 participants