3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // <OWNER>Microsoft</OWNER>
10 using System
.Collections
;
11 using System
.ComponentModel
;
12 using System
.Diagnostics
.Contracts
;
13 using System
.Collections
.Specialized
;
14 using System
.Runtime
.CompilerServices
;
15 using System
.Windows
.Input
;
17 namespace System
.Runtime
.InteropServices
.WindowsRuntime
19 // Local definition of Windows.UI.Xaml.Interop.INotifyCollectionChangedEventArgs
21 [Guid("4cf68d33-e3f2-4964-b85e-945b4f7e2f21")]
22 [WindowsRuntimeImport
]
23 internal interface INotifyCollectionChangedEventArgs
25 NotifyCollectionChangedAction Action { get; }
26 IList NewItems { get; }
27 IList OldItems { get; }
28 int NewStartingIndex { get; }
29 int OldStartingIndex { get; }
32 // Local definition of Windows.UI.Xaml.Data.IPropertyChangedEventArgs
34 [Guid("4f33a9a0-5cf4-47a4-b16f-d7faaf17457e")]
35 [WindowsRuntimeImport
]
36 internal interface IPropertyChangedEventArgs
38 string PropertyName { get; }
41 // Local definition of Windows.UI.Xaml.Interop.INotifyCollectionChanged
43 [Guid("28b167d5-1a31-465b-9b25-d5c3ae686c40")]
44 [WindowsRuntimeImport
]
45 internal interface INotifyCollectionChanged_WinRT
47 EventRegistrationToken
add_CollectionChanged(NotifyCollectionChangedEventHandler
value);
48 void remove_CollectionChanged(EventRegistrationToken token
);
51 // Local definition of Windows.UI.Xaml.Data.INotifyPropertyChanged
53 [Guid("cf75d69c-f2f4-486b-b302-bb4c09baebfa")]
54 [WindowsRuntimeImport
]
55 internal interface INotifyPropertyChanged_WinRT
57 EventRegistrationToken
add_PropertyChanged(PropertyChangedEventHandler
value);
58 void remove_PropertyChanged(EventRegistrationToken token
);
61 // Local definition of Windows.UI.Xaml.Input.ICommand
63 [Guid("e5af3542-ca67-4081-995b-709dd13792df")]
64 [WindowsRuntimeImport
]
65 internal interface ICommand_WinRT
67 EventRegistrationToken
add_CanExecuteChanged(EventHandler
<object> value);
68 void remove_CanExecuteChanged(EventRegistrationToken token
);
69 bool CanExecute(object parameter
);
70 void Execute(object parameter
);
73 // Local definition of Windows.UI.Xaml.Interop.NotifyCollectionChangedEventHandler
74 [Guid("ca10b37c-f382-4591-8557-5e24965279b0")]
75 [WindowsRuntimeImport
]
76 internal delegate void NotifyCollectionChangedEventHandler_WinRT(object sender
, NotifyCollectionChangedEventArgs e
);
78 // Local definition of Windows.UI.Xaml.Data.PropertyChangedEventHandler
79 [Guid("50f19c16-0a22-4d8e-a089-1ea9951657d2")]
80 [WindowsRuntimeImport
]
81 internal delegate void PropertyChangedEventHandler_WinRT(object sender
, PropertyChangedEventArgs e
);
83 internal static class NotifyCollectionChangedEventArgsMarshaler
85 // Extracts properties from a managed NotifyCollectionChangedEventArgs and passes them to
86 // a VM-implemented helper that creates a WinRT NotifyCollectionChangedEventArgs instance.
87 // This method is called from IL stubs and needs to have its token stabilized.
89 static internal IntPtr
ConvertToNative(NotifyCollectionChangedEventArgs managedArgs
)
91 if (managedArgs
== null)
94 return System
.StubHelpers
.EventArgsMarshaler
.CreateNativeNCCEventArgsInstance(
95 (int)managedArgs
.Action
,
98 managedArgs
.NewStartingIndex
,
99 managedArgs
.OldStartingIndex
);
102 // Extracts properties from a WinRT NotifyCollectionChangedEventArgs and creates a new
103 // managed NotifyCollectionChangedEventArgs instance.
104 // This method is called from IL stubs and needs to have its token stabilized.
106 static internal NotifyCollectionChangedEventArgs
ConvertToManaged(IntPtr nativeArgsIP
)
108 if (nativeArgsIP
== IntPtr
.Zero
)
111 object obj
= System
.StubHelpers
.InterfaceMarshaler
.ConvertToManagedWithoutUnboxing(nativeArgsIP
);
112 INotifyCollectionChangedEventArgs nativeArgs
= (INotifyCollectionChangedEventArgs
)obj
;
114 return new NotifyCollectionChangedEventArgs(
118 nativeArgs
.NewStartingIndex
,
119 nativeArgs
.OldStartingIndex
);
123 internal static class PropertyChangedEventArgsMarshaler
125 // Extracts PropertyName from a managed PropertyChangedEventArgs and passes them to
126 // a VM-implemented helper that creates a WinRT PropertyChangedEventArgs instance.
127 // This method is called from IL stubs and needs to have its token stabilized.
129 static internal IntPtr
ConvertToNative(PropertyChangedEventArgs managedArgs
)
131 if (managedArgs
== null)
134 return System
.StubHelpers
.EventArgsMarshaler
.CreateNativePCEventArgsInstance(managedArgs
.PropertyName
);
137 // Extracts properties from a WinRT PropertyChangedEventArgs and creates a new
138 // managed PropertyChangedEventArgs instance.
139 // This method is called from IL stubs and needs to have its token stabilized.
141 static internal PropertyChangedEventArgs
ConvertToManaged(IntPtr nativeArgsIP
)
143 if (nativeArgsIP
== IntPtr
.Zero
)
146 object obj
= System
.StubHelpers
.InterfaceMarshaler
.ConvertToManagedWithoutUnboxing(nativeArgsIP
);
147 IPropertyChangedEventArgs nativeArgs
= (IPropertyChangedEventArgs
)obj
;
149 return new PropertyChangedEventArgs(nativeArgs
.PropertyName
);
153 // This is a set of stub methods implementing the support for the managed INotifyCollectionChanged
154 // interface on WinRT objects that support the WinRT INotifyCollectionChanged. Used by the interop
155 // mashaling infrastructure.
156 internal sealed class NotifyCollectionChangedToManagedAdapter
158 private NotifyCollectionChangedToManagedAdapter()
160 Contract
.Assert(false, "This class is never instantiated");
163 internal event NotifyCollectionChangedEventHandler CollectionChanged
165 // void CollectionChanged.add(NotifyCollectionChangedEventHandler)
169 INotifyCollectionChanged_WinRT _this
= JitHelpers
.UnsafeCast
<INotifyCollectionChanged_WinRT
>(this);
171 // call the WinRT eventing support in mscorlib to subscribe the event
172 Func
<NotifyCollectionChangedEventHandler
, EventRegistrationToken
> addMethod
=
173 new Func
<NotifyCollectionChangedEventHandler
, EventRegistrationToken
>(_this
.add_CollectionChanged
);
174 Action
<EventRegistrationToken
> removeMethod
=
175 new Action
<EventRegistrationToken
>(_this
.remove_CollectionChanged
);
177 WindowsRuntimeMarshal
.AddEventHandler
<NotifyCollectionChangedEventHandler
>(addMethod
, removeMethod
, value);
180 // void CollectionChanged.remove(NotifyCollectionChangedEventHandler)
184 INotifyCollectionChanged_WinRT _this
= JitHelpers
.UnsafeCast
<INotifyCollectionChanged_WinRT
>(this);
186 // call the WinRT eventing support in mscorlib to unsubscribe the event
187 Action
<EventRegistrationToken
> removeMethod
=
188 new Action
<EventRegistrationToken
>(_this
.remove_CollectionChanged
);
190 WindowsRuntimeMarshal
.RemoveEventHandler
<NotifyCollectionChangedEventHandler
>(removeMethod
, value);
195 // This is a set of stub methods implementing the support for the WinRT INotifyCollectionChanged
196 // interface on managed objects that support the managed INotifyCollectionChanged. Used by the interop
197 // mashaling infrastructure.
198 internal sealed class NotifyCollectionChangedToWinRTAdapter
200 private NotifyCollectionChangedToWinRTAdapter()
202 Contract
.Assert(false, "This class is never instantiated");
205 // An instance field typed as EventRegistrationTokenTable is injected into managed classed by the compiler when compiling for /t:winmdobj.
206 // Since here the class can be an arbitrary implementation of INotifyCollectionChanged, we have to keep the EventRegistrationTokenTable's
207 // separately, associated with the implementations using ConditionalWeakTable.
208 private static ConditionalWeakTable
<INotifyCollectionChanged
, EventRegistrationTokenTable
<NotifyCollectionChangedEventHandler
>> m_weakTable
=
209 new ConditionalWeakTable
<INotifyCollectionChanged
, EventRegistrationTokenTable
<NotifyCollectionChangedEventHandler
>>();
211 // EventRegistrationToken CollectionChanged.add(NotifyCollectionChangedEventHandler value)
213 internal EventRegistrationToken
add_CollectionChanged(NotifyCollectionChangedEventHandler
value)
215 INotifyCollectionChanged _this
= JitHelpers
.UnsafeCast
<INotifyCollectionChanged
>(this);
216 EventRegistrationTokenTable
<NotifyCollectionChangedEventHandler
> table
= m_weakTable
.GetOrCreateValue(_this
);
218 EventRegistrationToken token
= table
.AddEventHandler(value);
219 _this
.CollectionChanged
+= value;
224 // void CollectionChanged.remove(EventRegistrationToken token)
226 internal void remove_CollectionChanged(EventRegistrationToken token
)
228 INotifyCollectionChanged _this
= JitHelpers
.UnsafeCast
<INotifyCollectionChanged
>(this);
229 EventRegistrationTokenTable
<NotifyCollectionChangedEventHandler
> table
= m_weakTable
.GetOrCreateValue(_this
);
231 NotifyCollectionChangedEventHandler handler
= table
.ExtractHandler(token
);
234 _this
.CollectionChanged
-= handler
;
239 // This is a set of stub methods implementing the support for the managed INotifyPropertyChanged
240 // interface on WinRT objects that support the WinRT INotifyPropertyChanged. Used by the interop
241 // mashaling infrastructure.
242 internal sealed class NotifyPropertyChangedToManagedAdapter
244 private NotifyPropertyChangedToManagedAdapter()
246 Contract
.Assert(false, "This class is never instantiated");
249 internal event PropertyChangedEventHandler PropertyChanged
251 // void PropertyChanged.add(PropertyChangedEventHandler)
255 INotifyPropertyChanged_WinRT _this
= JitHelpers
.UnsafeCast
<INotifyPropertyChanged_WinRT
>(this);
257 // call the WinRT eventing support in mscorlib to subscribe the event
258 Func
<PropertyChangedEventHandler
, EventRegistrationToken
> addMethod
=
259 new Func
<PropertyChangedEventHandler
, EventRegistrationToken
>(_this
.add_PropertyChanged
);
260 Action
<EventRegistrationToken
> removeMethod
=
261 new Action
<EventRegistrationToken
>(_this
.remove_PropertyChanged
);
263 WindowsRuntimeMarshal
.AddEventHandler
<PropertyChangedEventHandler
>(addMethod
, removeMethod
, value);
266 // void PropertyChanged.remove(PropertyChangedEventHandler)
270 INotifyPropertyChanged_WinRT _this
= JitHelpers
.UnsafeCast
<INotifyPropertyChanged_WinRT
>(this);
272 // call the WinRT eventing support in mscorlib to unsubscribe the event
273 Action
<EventRegistrationToken
> removeMethod
=
274 new Action
<EventRegistrationToken
>(_this
.remove_PropertyChanged
);
276 WindowsRuntimeMarshal
.RemoveEventHandler
<PropertyChangedEventHandler
>(removeMethod
, value);
281 // This is a set of stub methods implementing the support for the WinRT INotifyPropertyChanged
282 // interface on managed objects that support the managed INotifyPropertyChanged. Used by the interop
283 // mashaling infrastructure.
284 internal sealed class NotifyPropertyChangedToWinRTAdapter
286 private NotifyPropertyChangedToWinRTAdapter()
288 Contract
.Assert(false, "This class is never instantiated");
291 // An instance field typed as EventRegistrationTokenTable is injected into managed classed by the compiler when compiling for /t:winmdobj.
292 // Since here the class can be an arbitrary implementation of INotifyCollectionChanged, we have to keep the EventRegistrationTokenTable's
293 // separately, associated with the implementations using ConditionalWeakTable.
294 private static ConditionalWeakTable
<INotifyPropertyChanged
, EventRegistrationTokenTable
<PropertyChangedEventHandler
>> m_weakTable
=
295 new ConditionalWeakTable
<INotifyPropertyChanged
, EventRegistrationTokenTable
<PropertyChangedEventHandler
>>();
297 // EventRegistrationToken PropertyChanged.add(PropertyChangedEventHandler value)
299 internal EventRegistrationToken
add_PropertyChanged(PropertyChangedEventHandler
value)
301 INotifyPropertyChanged _this
= JitHelpers
.UnsafeCast
<INotifyPropertyChanged
>(this);
302 EventRegistrationTokenTable
<PropertyChangedEventHandler
> table
= m_weakTable
.GetOrCreateValue(_this
);
304 EventRegistrationToken token
= table
.AddEventHandler(value);
305 _this
.PropertyChanged
+= value;
310 // void PropertyChanged.remove(EventRegistrationToken token)
312 internal void remove_PropertyChanged(EventRegistrationToken token
)
314 INotifyPropertyChanged _this
= JitHelpers
.UnsafeCast
<INotifyPropertyChanged
>(this);
315 EventRegistrationTokenTable
<PropertyChangedEventHandler
> table
= m_weakTable
.GetOrCreateValue(_this
);
317 PropertyChangedEventHandler handler
= table
.ExtractHandler(token
);
320 _this
.PropertyChanged
-= handler
;
325 // This is a set of stub methods implementing the support for the managed ICommand
326 // interface on WinRT objects that support the WinRT ICommand_WinRT.
327 // Used by the interop mashaling infrastructure.
328 // Instances of this are really RCWs of ICommand_WinRT (not ICommandToManagedAdapter or any ICommand).
330 internal sealed class ICommandToManagedAdapter
/*: System.Windows.Input.ICommand*/
332 private static ConditionalWeakTable
<EventHandler
, EventHandler
<object>> m_weakTable
=
333 new ConditionalWeakTable
<EventHandler
, EventHandler
<object>>();
335 private ICommandToManagedAdapter()
337 Contract
.Assert(false, "This class is never instantiated");
340 private event EventHandler CanExecuteChanged
342 // void CanExecuteChanged.add(EventHandler)
345 ICommand_WinRT _this
= JitHelpers
.UnsafeCast
<ICommand_WinRT
>(this);
347 // call the WinRT eventing support in mscorlib to subscribe the event
348 Func
<EventHandler
<object>, EventRegistrationToken
> addMethod
=
349 new Func
<EventHandler
<object>, EventRegistrationToken
>(_this
.add_CanExecuteChanged
);
350 Action
<EventRegistrationToken
> removeMethod
=
351 new Action
<EventRegistrationToken
>(_this
.remove_CanExecuteChanged
);
353 // value is of type System.EventHandler, but ICommand_WinRT (and thus WindowsRuntimeMarshal.AddEventHandler)
354 // expects an instance of EventHandler<object>. So we get/create a wrapper of value here.
355 EventHandler
<object> handler_WinRT
= m_weakTable
.GetValue(value, ICommandAdapterHelpers
.CreateWrapperHandler
);
356 WindowsRuntimeMarshal
.AddEventHandler
<EventHandler
<object>>(addMethod
, removeMethod
, handler_WinRT
);
359 // void CanExecuteChanged.remove(EventHandler)
362 ICommand_WinRT _this
= JitHelpers
.UnsafeCast
<ICommand_WinRT
>(this);
364 // call the WinRT eventing support in mscorlib to unsubscribe the event
365 Action
<EventRegistrationToken
> removeMethod
=
366 new Action
<EventRegistrationToken
>(_this
.remove_CanExecuteChanged
);
368 // value is of type System.EventHandler, but ICommand_WinRT (and thus WindowsRuntimeMarshal.RemoveEventHandler)
369 // expects an instance of EventHandler<object>. So we get/create a wrapper of value here.
371 // Also we do a value check rather than an instance check to ensure that different instances of the same delegates are treated equal.
372 EventHandler
<object> handler_WinRT
= ICommandAdapterHelpers
.GetValueFromEquivalentKey(m_weakTable
, value, ICommandAdapterHelpers
.CreateWrapperHandler
);
373 WindowsRuntimeMarshal
.RemoveEventHandler
<EventHandler
<object>>(removeMethod
, handler_WinRT
);
377 private bool CanExecute(object parameter
)
379 ICommand_WinRT _this
= JitHelpers
.UnsafeCast
<ICommand_WinRT
>(this);
380 return _this
.CanExecute(parameter
);
383 private void Execute(object parameter
)
385 ICommand_WinRT _this
= JitHelpers
.UnsafeCast
<ICommand_WinRT
>(this);
386 _this
.Execute(parameter
);
390 // This is a set of stub methods implementing the support for the WinRT ICommand_WinRT
391 // interface on managed objects that support the managed ICommand interface.
392 // Used by the interop mashaling infrastructure.
393 // Instances of this are really CCWs of ICommand (not ICommandToWinRTAdapter or any ICommand_WinRT).
395 internal sealed class ICommandToWinRTAdapter
/*: ICommand_WinRT*/
397 private ICommandToWinRTAdapter()
399 Contract
.Assert(false, "This class is never instantiated");
402 // An instance field typed as EventRegistrationTokenTable is injected into managed classed by the compiler when compiling for /t:winmdobj.
403 // Since here the class can be an arbitrary implementation of ICommand, we have to keep the EventRegistrationTokenTable's
404 // separately, associated with the implementations using ConditionalWeakTable.
405 private static ConditionalWeakTable
<ICommand
, EventRegistrationTokenTable
<EventHandler
>> m_weakTable
=
406 new ConditionalWeakTable
<ICommand
, EventRegistrationTokenTable
<EventHandler
>>();
408 // EventRegistrationToken PropertyChanged.add(EventHandler<object> value)
409 private EventRegistrationToken
add_CanExecuteChanged(EventHandler
<object> value)
411 ICommand _this
= JitHelpers
.UnsafeCast
<ICommand
>(this);
412 EventRegistrationTokenTable
<EventHandler
> table
= m_weakTable
.GetOrCreateValue(_this
);
414 EventHandler handler
= ICommandAdapterHelpers
.CreateWrapperHandler(value);
415 EventRegistrationToken token
= table
.AddEventHandler(handler
);
416 _this
.CanExecuteChanged
+= handler
;
421 // void PropertyChanged.remove(EventRegistrationToken token)
422 private void remove_CanExecuteChanged(EventRegistrationToken token
)
424 ICommand _this
= JitHelpers
.UnsafeCast
<ICommand
>(this);
425 EventRegistrationTokenTable
<EventHandler
> table
= m_weakTable
.GetOrCreateValue(_this
);
427 EventHandler handler
= table
.ExtractHandler(token
);
430 _this
.CanExecuteChanged
-= handler
;
434 private bool CanExecute(object parameter
)
436 ICommand _this
= JitHelpers
.UnsafeCast
<ICommand
>(this);
437 return _this
.CanExecute(parameter
);
440 private void Execute(object parameter
)
442 ICommand _this
= JitHelpers
.UnsafeCast
<ICommand
>(this);
443 _this
.Execute(parameter
);
448 // A couple of ICommand adapter helpers need to be transparent, and so are in their own type
449 internal static class ICommandAdapterHelpers
451 internal static EventHandler
<object> CreateWrapperHandler(EventHandler handler
)
453 // Check whether it is a round-tripping case i.e. the sender is of the type eventArgs,
454 // If so we use it else we pass EventArgs.Empty
455 return (object sender
, object e
) =>
457 EventArgs eventArgs
= e
as EventArgs
;
458 handler(sender
, (eventArgs
== null ? System
.EventArgs
.Empty
: eventArgs
));
462 internal static EventHandler
CreateWrapperHandler(EventHandler
<object> handler
)
464 return (object sender
, EventArgs e
) => handler(sender
, e
);
467 internal static EventHandler
<object> GetValueFromEquivalentKey(
468 ConditionalWeakTable
<EventHandler
, EventHandler
<object>> table
,
470 ConditionalWeakTable
<EventHandler
, EventHandler
<object>>.CreateValueCallback callback
)
472 EventHandler
<object> value;
474 // Find the key in the table using a value check rather than an instance check.
475 EventHandler existingKey
= table
.FindEquivalentKeyUnsafe(key
, out value);
476 if (existingKey
== null)
478 value = callback(key
);
479 table
.Add(key
, value);