536cd135cc
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
486 lines
22 KiB
C#
486 lines
22 KiB
C#
// ==++==
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// ==--==
|
|
//
|
|
// <OWNER>Microsoft</OWNER>
|
|
|
|
using System.Security;
|
|
using System.Collections;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics.Contracts;
|
|
using System.Collections.Specialized;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Windows.Input;
|
|
|
|
namespace System.Runtime.InteropServices.WindowsRuntime
|
|
{
|
|
// Local definition of Windows.UI.Xaml.Interop.INotifyCollectionChangedEventArgs
|
|
[ComImport]
|
|
[Guid("4cf68d33-e3f2-4964-b85e-945b4f7e2f21")]
|
|
[WindowsRuntimeImport]
|
|
internal interface INotifyCollectionChangedEventArgs
|
|
{
|
|
NotifyCollectionChangedAction Action { get; }
|
|
IList NewItems { get; }
|
|
IList OldItems { get; }
|
|
int NewStartingIndex { get; }
|
|
int OldStartingIndex { get; }
|
|
}
|
|
|
|
// Local definition of Windows.UI.Xaml.Data.IPropertyChangedEventArgs
|
|
[ComImport]
|
|
[Guid("4f33a9a0-5cf4-47a4-b16f-d7faaf17457e")]
|
|
[WindowsRuntimeImport]
|
|
internal interface IPropertyChangedEventArgs
|
|
{
|
|
string PropertyName { get; }
|
|
}
|
|
|
|
// Local definition of Windows.UI.Xaml.Interop.INotifyCollectionChanged
|
|
[ComImport]
|
|
[Guid("28b167d5-1a31-465b-9b25-d5c3ae686c40")]
|
|
[WindowsRuntimeImport]
|
|
internal interface INotifyCollectionChanged_WinRT
|
|
{
|
|
EventRegistrationToken add_CollectionChanged(NotifyCollectionChangedEventHandler value);
|
|
void remove_CollectionChanged(EventRegistrationToken token);
|
|
}
|
|
|
|
// Local definition of Windows.UI.Xaml.Data.INotifyPropertyChanged
|
|
[ComImport]
|
|
[Guid("cf75d69c-f2f4-486b-b302-bb4c09baebfa")]
|
|
[WindowsRuntimeImport]
|
|
internal interface INotifyPropertyChanged_WinRT
|
|
{
|
|
EventRegistrationToken add_PropertyChanged(PropertyChangedEventHandler value);
|
|
void remove_PropertyChanged(EventRegistrationToken token);
|
|
}
|
|
|
|
// Local definition of Windows.UI.Xaml.Input.ICommand
|
|
[ComImport]
|
|
[Guid("e5af3542-ca67-4081-995b-709dd13792df")]
|
|
[WindowsRuntimeImport]
|
|
internal interface ICommand_WinRT
|
|
{
|
|
EventRegistrationToken add_CanExecuteChanged(EventHandler<object> value);
|
|
void remove_CanExecuteChanged(EventRegistrationToken token);
|
|
bool CanExecute(object parameter);
|
|
void Execute(object parameter);
|
|
}
|
|
|
|
// Local definition of Windows.UI.Xaml.Interop.NotifyCollectionChangedEventHandler
|
|
[Guid("ca10b37c-f382-4591-8557-5e24965279b0")]
|
|
[WindowsRuntimeImport]
|
|
internal delegate void NotifyCollectionChangedEventHandler_WinRT(object sender, NotifyCollectionChangedEventArgs e);
|
|
|
|
// Local definition of Windows.UI.Xaml.Data.PropertyChangedEventHandler
|
|
[Guid("50f19c16-0a22-4d8e-a089-1ea9951657d2")]
|
|
[WindowsRuntimeImport]
|
|
internal delegate void PropertyChangedEventHandler_WinRT(object sender, PropertyChangedEventArgs e);
|
|
|
|
internal static class NotifyCollectionChangedEventArgsMarshaler
|
|
{
|
|
// Extracts properties from a managed NotifyCollectionChangedEventArgs and passes them to
|
|
// a VM-implemented helper that creates a WinRT NotifyCollectionChangedEventArgs instance.
|
|
// This method is called from IL stubs and needs to have its token stabilized.
|
|
[SecurityCritical]
|
|
static internal IntPtr ConvertToNative(NotifyCollectionChangedEventArgs managedArgs)
|
|
{
|
|
if (managedArgs == null)
|
|
return IntPtr.Zero;
|
|
|
|
return System.StubHelpers.EventArgsMarshaler.CreateNativeNCCEventArgsInstance(
|
|
(int)managedArgs.Action,
|
|
managedArgs.NewItems,
|
|
managedArgs.OldItems,
|
|
managedArgs.NewStartingIndex,
|
|
managedArgs.OldStartingIndex);
|
|
}
|
|
|
|
// Extracts properties from a WinRT NotifyCollectionChangedEventArgs and creates a new
|
|
// managed NotifyCollectionChangedEventArgs instance.
|
|
// This method is called from IL stubs and needs to have its token stabilized.
|
|
[SecurityCritical]
|
|
static internal NotifyCollectionChangedEventArgs ConvertToManaged(IntPtr nativeArgsIP)
|
|
{
|
|
if (nativeArgsIP == IntPtr.Zero)
|
|
return null;
|
|
|
|
object obj = System.StubHelpers.InterfaceMarshaler.ConvertToManagedWithoutUnboxing(nativeArgsIP);
|
|
INotifyCollectionChangedEventArgs nativeArgs = (INotifyCollectionChangedEventArgs)obj;
|
|
|
|
return new NotifyCollectionChangedEventArgs(
|
|
nativeArgs.Action,
|
|
nativeArgs.NewItems,
|
|
nativeArgs.OldItems,
|
|
nativeArgs.NewStartingIndex,
|
|
nativeArgs.OldStartingIndex);
|
|
}
|
|
}
|
|
|
|
internal static class PropertyChangedEventArgsMarshaler
|
|
{
|
|
// Extracts PropertyName from a managed PropertyChangedEventArgs and passes them to
|
|
// a VM-implemented helper that creates a WinRT PropertyChangedEventArgs instance.
|
|
// This method is called from IL stubs and needs to have its token stabilized.
|
|
[SecurityCritical]
|
|
static internal IntPtr ConvertToNative(PropertyChangedEventArgs managedArgs)
|
|
{
|
|
if (managedArgs == null)
|
|
return IntPtr.Zero;
|
|
|
|
return System.StubHelpers.EventArgsMarshaler.CreateNativePCEventArgsInstance(managedArgs.PropertyName);
|
|
}
|
|
|
|
// Extracts properties from a WinRT PropertyChangedEventArgs and creates a new
|
|
// managed PropertyChangedEventArgs instance.
|
|
// This method is called from IL stubs and needs to have its token stabilized.
|
|
[SecurityCritical]
|
|
static internal PropertyChangedEventArgs ConvertToManaged(IntPtr nativeArgsIP)
|
|
{
|
|
if (nativeArgsIP == IntPtr.Zero)
|
|
return null;
|
|
|
|
object obj = System.StubHelpers.InterfaceMarshaler.ConvertToManagedWithoutUnboxing(nativeArgsIP);
|
|
IPropertyChangedEventArgs nativeArgs = (IPropertyChangedEventArgs)obj;
|
|
|
|
return new PropertyChangedEventArgs(nativeArgs.PropertyName);
|
|
}
|
|
}
|
|
|
|
// This is a set of stub methods implementing the support for the managed INotifyCollectionChanged
|
|
// interface on WinRT objects that support the WinRT INotifyCollectionChanged. Used by the interop
|
|
// mashaling infrastructure.
|
|
internal sealed class NotifyCollectionChangedToManagedAdapter
|
|
{
|
|
private NotifyCollectionChangedToManagedAdapter()
|
|
{
|
|
Contract.Assert(false, "This class is never instantiated");
|
|
}
|
|
|
|
internal event NotifyCollectionChangedEventHandler CollectionChanged
|
|
{
|
|
// void CollectionChanged.add(NotifyCollectionChangedEventHandler)
|
|
[SecurityCritical]
|
|
add
|
|
{
|
|
INotifyCollectionChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyCollectionChanged_WinRT>(this);
|
|
|
|
// call the WinRT eventing support in mscorlib to subscribe the event
|
|
Func<NotifyCollectionChangedEventHandler, EventRegistrationToken> addMethod =
|
|
new Func<NotifyCollectionChangedEventHandler, EventRegistrationToken>(_this.add_CollectionChanged);
|
|
Action<EventRegistrationToken> removeMethod =
|
|
new Action<EventRegistrationToken>(_this.remove_CollectionChanged);
|
|
|
|
WindowsRuntimeMarshal.AddEventHandler<NotifyCollectionChangedEventHandler>(addMethod, removeMethod, value);
|
|
}
|
|
|
|
// void CollectionChanged.remove(NotifyCollectionChangedEventHandler)
|
|
[SecurityCritical]
|
|
remove
|
|
{
|
|
INotifyCollectionChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyCollectionChanged_WinRT>(this);
|
|
|
|
// call the WinRT eventing support in mscorlib to unsubscribe the event
|
|
Action<EventRegistrationToken> removeMethod =
|
|
new Action<EventRegistrationToken>(_this.remove_CollectionChanged);
|
|
|
|
WindowsRuntimeMarshal.RemoveEventHandler<NotifyCollectionChangedEventHandler>(removeMethod, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
// This is a set of stub methods implementing the support for the WinRT INotifyCollectionChanged
|
|
// interface on managed objects that support the managed INotifyCollectionChanged. Used by the interop
|
|
// mashaling infrastructure.
|
|
internal sealed class NotifyCollectionChangedToWinRTAdapter
|
|
{
|
|
private NotifyCollectionChangedToWinRTAdapter()
|
|
{
|
|
Contract.Assert(false, "This class is never instantiated");
|
|
}
|
|
|
|
// An instance field typed as EventRegistrationTokenTable is injected into managed classed by the compiler when compiling for /t:winmdobj.
|
|
// Since here the class can be an arbitrary implementation of INotifyCollectionChanged, we have to keep the EventRegistrationTokenTable's
|
|
// separately, associated with the implementations using ConditionalWeakTable.
|
|
private static ConditionalWeakTable<INotifyCollectionChanged, EventRegistrationTokenTable<NotifyCollectionChangedEventHandler>> m_weakTable =
|
|
new ConditionalWeakTable<INotifyCollectionChanged, EventRegistrationTokenTable<NotifyCollectionChangedEventHandler>>();
|
|
|
|
// EventRegistrationToken CollectionChanged.add(NotifyCollectionChangedEventHandler value)
|
|
[SecurityCritical]
|
|
internal EventRegistrationToken add_CollectionChanged(NotifyCollectionChangedEventHandler value)
|
|
{
|
|
INotifyCollectionChanged _this = JitHelpers.UnsafeCast<INotifyCollectionChanged>(this);
|
|
EventRegistrationTokenTable<NotifyCollectionChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
|
|
|
|
EventRegistrationToken token = table.AddEventHandler(value);
|
|
_this.CollectionChanged += value;
|
|
|
|
return token;
|
|
}
|
|
|
|
// void CollectionChanged.remove(EventRegistrationToken token)
|
|
[SecurityCritical]
|
|
internal void remove_CollectionChanged(EventRegistrationToken token)
|
|
{
|
|
INotifyCollectionChanged _this = JitHelpers.UnsafeCast<INotifyCollectionChanged>(this);
|
|
EventRegistrationTokenTable<NotifyCollectionChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
|
|
|
|
NotifyCollectionChangedEventHandler handler = table.ExtractHandler(token);
|
|
if (handler != null)
|
|
{
|
|
_this.CollectionChanged -= handler;
|
|
}
|
|
}
|
|
}
|
|
|
|
// This is a set of stub methods implementing the support for the managed INotifyPropertyChanged
|
|
// interface on WinRT objects that support the WinRT INotifyPropertyChanged. Used by the interop
|
|
// mashaling infrastructure.
|
|
internal sealed class NotifyPropertyChangedToManagedAdapter
|
|
{
|
|
private NotifyPropertyChangedToManagedAdapter()
|
|
{
|
|
Contract.Assert(false, "This class is never instantiated");
|
|
}
|
|
|
|
internal event PropertyChangedEventHandler PropertyChanged
|
|
{
|
|
// void PropertyChanged.add(PropertyChangedEventHandler)
|
|
[SecurityCritical]
|
|
add
|
|
{
|
|
INotifyPropertyChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyPropertyChanged_WinRT>(this);
|
|
|
|
// call the WinRT eventing support in mscorlib to subscribe the event
|
|
Func<PropertyChangedEventHandler, EventRegistrationToken> addMethod =
|
|
new Func<PropertyChangedEventHandler, EventRegistrationToken>(_this.add_PropertyChanged);
|
|
Action<EventRegistrationToken> removeMethod =
|
|
new Action<EventRegistrationToken>(_this.remove_PropertyChanged);
|
|
|
|
WindowsRuntimeMarshal.AddEventHandler<PropertyChangedEventHandler>(addMethod, removeMethod, value);
|
|
}
|
|
|
|
// void PropertyChanged.remove(PropertyChangedEventHandler)
|
|
[SecurityCritical]
|
|
remove
|
|
{
|
|
INotifyPropertyChanged_WinRT _this = JitHelpers.UnsafeCast<INotifyPropertyChanged_WinRT>(this);
|
|
|
|
// call the WinRT eventing support in mscorlib to unsubscribe the event
|
|
Action<EventRegistrationToken> removeMethod =
|
|
new Action<EventRegistrationToken>(_this.remove_PropertyChanged);
|
|
|
|
WindowsRuntimeMarshal.RemoveEventHandler<PropertyChangedEventHandler>(removeMethod, value);
|
|
}
|
|
}
|
|
}
|
|
|
|
// This is a set of stub methods implementing the support for the WinRT INotifyPropertyChanged
|
|
// interface on managed objects that support the managed INotifyPropertyChanged. Used by the interop
|
|
// mashaling infrastructure.
|
|
internal sealed class NotifyPropertyChangedToWinRTAdapter
|
|
{
|
|
private NotifyPropertyChangedToWinRTAdapter()
|
|
{
|
|
Contract.Assert(false, "This class is never instantiated");
|
|
}
|
|
|
|
// An instance field typed as EventRegistrationTokenTable is injected into managed classed by the compiler when compiling for /t:winmdobj.
|
|
// Since here the class can be an arbitrary implementation of INotifyCollectionChanged, we have to keep the EventRegistrationTokenTable's
|
|
// separately, associated with the implementations using ConditionalWeakTable.
|
|
private static ConditionalWeakTable<INotifyPropertyChanged, EventRegistrationTokenTable<PropertyChangedEventHandler>> m_weakTable =
|
|
new ConditionalWeakTable<INotifyPropertyChanged, EventRegistrationTokenTable<PropertyChangedEventHandler>>();
|
|
|
|
// EventRegistrationToken PropertyChanged.add(PropertyChangedEventHandler value)
|
|
[SecurityCritical]
|
|
internal EventRegistrationToken add_PropertyChanged(PropertyChangedEventHandler value)
|
|
{
|
|
INotifyPropertyChanged _this = JitHelpers.UnsafeCast<INotifyPropertyChanged>(this);
|
|
EventRegistrationTokenTable<PropertyChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
|
|
|
|
EventRegistrationToken token = table.AddEventHandler(value);
|
|
_this.PropertyChanged += value;
|
|
|
|
return token;
|
|
}
|
|
|
|
// void PropertyChanged.remove(EventRegistrationToken token)
|
|
[SecurityCritical]
|
|
internal void remove_PropertyChanged(EventRegistrationToken token)
|
|
{
|
|
INotifyPropertyChanged _this = JitHelpers.UnsafeCast<INotifyPropertyChanged>(this);
|
|
EventRegistrationTokenTable<PropertyChangedEventHandler> table = m_weakTable.GetOrCreateValue(_this);
|
|
|
|
PropertyChangedEventHandler handler = table.ExtractHandler(token);
|
|
if (handler != null)
|
|
{
|
|
_this.PropertyChanged -= handler;
|
|
}
|
|
}
|
|
}
|
|
|
|
// This is a set of stub methods implementing the support for the managed ICommand
|
|
// interface on WinRT objects that support the WinRT ICommand_WinRT.
|
|
// Used by the interop mashaling infrastructure.
|
|
// Instances of this are really RCWs of ICommand_WinRT (not ICommandToManagedAdapter or any ICommand).
|
|
[SecurityCritical]
|
|
internal sealed class ICommandToManagedAdapter /*: System.Windows.Input.ICommand*/
|
|
{
|
|
private static ConditionalWeakTable<EventHandler, EventHandler<object>> m_weakTable =
|
|
new ConditionalWeakTable<EventHandler, EventHandler<object>>();
|
|
|
|
private ICommandToManagedAdapter()
|
|
{
|
|
Contract.Assert(false, "This class is never instantiated");
|
|
}
|
|
|
|
private event EventHandler CanExecuteChanged
|
|
{
|
|
// void CanExecuteChanged.add(EventHandler)
|
|
add
|
|
{
|
|
ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
|
|
|
|
// call the WinRT eventing support in mscorlib to subscribe the event
|
|
Func<EventHandler<object>, EventRegistrationToken> addMethod =
|
|
new Func<EventHandler<object>, EventRegistrationToken>(_this.add_CanExecuteChanged);
|
|
Action<EventRegistrationToken> removeMethod =
|
|
new Action<EventRegistrationToken>(_this.remove_CanExecuteChanged);
|
|
|
|
// value is of type System.EventHandler, but ICommand_WinRT (and thus WindowsRuntimeMarshal.AddEventHandler)
|
|
// expects an instance of EventHandler<object>. So we get/create a wrapper of value here.
|
|
EventHandler<object> handler_WinRT = m_weakTable.GetValue(value, ICommandAdapterHelpers.CreateWrapperHandler);
|
|
WindowsRuntimeMarshal.AddEventHandler<EventHandler<object>>(addMethod, removeMethod, handler_WinRT);
|
|
}
|
|
|
|
// void CanExecuteChanged.remove(EventHandler)
|
|
remove
|
|
{
|
|
ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
|
|
|
|
// call the WinRT eventing support in mscorlib to unsubscribe the event
|
|
Action<EventRegistrationToken> removeMethod =
|
|
new Action<EventRegistrationToken>(_this.remove_CanExecuteChanged);
|
|
|
|
// value is of type System.EventHandler, but ICommand_WinRT (and thus WindowsRuntimeMarshal.RemoveEventHandler)
|
|
// expects an instance of EventHandler<object>. So we get/create a wrapper of value here.
|
|
|
|
// Also we do a value check rather than an instance check to ensure that different instances of the same delegates are treated equal.
|
|
EventHandler<object> handler_WinRT = ICommandAdapterHelpers.GetValueFromEquivalentKey(m_weakTable , value, ICommandAdapterHelpers.CreateWrapperHandler);
|
|
WindowsRuntimeMarshal.RemoveEventHandler<EventHandler<object>>(removeMethod, handler_WinRT);
|
|
}
|
|
}
|
|
|
|
private bool CanExecute(object parameter)
|
|
{
|
|
ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
|
|
return _this.CanExecute(parameter);
|
|
}
|
|
|
|
private void Execute(object parameter)
|
|
{
|
|
ICommand_WinRT _this = JitHelpers.UnsafeCast<ICommand_WinRT>(this);
|
|
_this.Execute(parameter);
|
|
}
|
|
}
|
|
|
|
// This is a set of stub methods implementing the support for the WinRT ICommand_WinRT
|
|
// interface on managed objects that support the managed ICommand interface.
|
|
// Used by the interop mashaling infrastructure.
|
|
// Instances of this are really CCWs of ICommand (not ICommandToWinRTAdapter or any ICommand_WinRT).
|
|
[SecurityCritical]
|
|
internal sealed class ICommandToWinRTAdapter /*: ICommand_WinRT*/
|
|
{
|
|
private ICommandToWinRTAdapter()
|
|
{
|
|
Contract.Assert(false, "This class is never instantiated");
|
|
}
|
|
|
|
// An instance field typed as EventRegistrationTokenTable is injected into managed classed by the compiler when compiling for /t:winmdobj.
|
|
// Since here the class can be an arbitrary implementation of ICommand, we have to keep the EventRegistrationTokenTable's
|
|
// separately, associated with the implementations using ConditionalWeakTable.
|
|
private static ConditionalWeakTable<ICommand, EventRegistrationTokenTable<EventHandler>> m_weakTable =
|
|
new ConditionalWeakTable<ICommand, EventRegistrationTokenTable<EventHandler>>();
|
|
|
|
// EventRegistrationToken PropertyChanged.add(EventHandler<object> value)
|
|
private EventRegistrationToken add_CanExecuteChanged(EventHandler<object> value)
|
|
{
|
|
ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
|
|
EventRegistrationTokenTable<EventHandler> table = m_weakTable.GetOrCreateValue(_this);
|
|
|
|
EventHandler handler = ICommandAdapterHelpers.CreateWrapperHandler(value);
|
|
EventRegistrationToken token = table.AddEventHandler(handler);
|
|
_this.CanExecuteChanged += handler;
|
|
|
|
return token;
|
|
}
|
|
|
|
// void PropertyChanged.remove(EventRegistrationToken token)
|
|
private void remove_CanExecuteChanged(EventRegistrationToken token)
|
|
{
|
|
ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
|
|
EventRegistrationTokenTable<EventHandler> table = m_weakTable.GetOrCreateValue(_this);
|
|
|
|
EventHandler handler = table.ExtractHandler(token);
|
|
if (handler != null)
|
|
{
|
|
_this.CanExecuteChanged -= handler;
|
|
}
|
|
}
|
|
|
|
private bool CanExecute(object parameter)
|
|
{
|
|
ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
|
|
return _this.CanExecute(parameter);
|
|
}
|
|
|
|
private void Execute(object parameter)
|
|
{
|
|
ICommand _this = JitHelpers.UnsafeCast<ICommand>(this);
|
|
_this.Execute(parameter);
|
|
}
|
|
|
|
}
|
|
|
|
// A couple of ICommand adapter helpers need to be transparent, and so are in their own type
|
|
internal static class ICommandAdapterHelpers
|
|
{
|
|
internal static EventHandler<object> CreateWrapperHandler(EventHandler handler)
|
|
{
|
|
// Check whether it is a round-tripping case i.e. the sender is of the type eventArgs,
|
|
// If so we use it else we pass EventArgs.Empty
|
|
return (object sender, object e) =>
|
|
{
|
|
EventArgs eventArgs = e as EventArgs;
|
|
handler(sender, (eventArgs == null ? System.EventArgs.Empty : eventArgs));
|
|
};
|
|
}
|
|
|
|
internal static EventHandler CreateWrapperHandler(EventHandler<object> handler)
|
|
{
|
|
return (object sender, EventArgs e) => handler(sender, e);
|
|
}
|
|
|
|
internal static EventHandler<object> GetValueFromEquivalentKey(
|
|
ConditionalWeakTable<EventHandler, EventHandler<object>> table,
|
|
EventHandler key,
|
|
ConditionalWeakTable<EventHandler, EventHandler<object>>.CreateValueCallback callback)
|
|
{
|
|
EventHandler<object> value;
|
|
|
|
// Find the key in the table using a value check rather than an instance check.
|
|
EventHandler existingKey = table.FindEquivalentKeyUnsafe(key, out value);
|
|
if (existingKey == null)
|
|
{
|
|
value = callback(key);
|
|
table.Add(key, value);
|
|
}
|
|
|
|
return value;
|
|
}
|
|
}
|
|
}
|