private static Func <object> GetCommandExecutionProviderConstructor(CommandExecutionProviderKey key) { Func <object> constructor; if (!CompiledConstructors.TryGetValue(key, out constructor)) { var executionProviderType = typeof(CommandExecutionProvider <>).MakeGenericType(key.TargetType); var executionProviderCtor = executionProviderType.GetConstructor(new[] { typeof(Type), typeof(string), typeof(string) }); var executionProviderCtorParamaters = new Expression[] { Expression.Constant(key.TargetType), Expression.Constant(key.CanExecuteMethodName, typeof(string)), Expression.Constant(key.ExecutedMethodName, typeof(string)) }; Debug.Assert(executionProviderCtor != null, "executionProviderCtor != null"); var executionProviderCtorExpression = Expression.New( executionProviderCtor, executionProviderCtorParamaters); constructor = Expression.Lambda <Func <object> >(executionProviderCtorExpression).Compile(); } return(constructor); }
private static ICommandExecutionProvider GetCommandExecutionProvider( object target, string canExecuteMethodName, string executedMethodName) { if (target == _disconnectedItemSentinelValue) { return(null); } var key = new CommandExecutionProviderKey(target.GetType(), canExecuteMethodName, executedMethodName); ICommandExecutionProvider executionProvider; if (!ExecutionProviders.TryGetValue(key, out executionProvider)) { try { executionProvider = (ICommandExecutionProvider)GetCommandExecutionProviderConstructor(key)(); } catch (TargetInvocationException) { // Thanks to Mark Bergan for finding this issue! // Unfortunately we have some nastiness around a performance optimization in C# 4.0. // Because we are listening to DataContext events we may end up being provided a DataContext // value that is an internal place holder for the DataContext of disconnected containers WPF. // There is no easy way to detect this object, hence the reflection. Basically we just want to // ignore any disconnected DataContext items. The best documentation I have found is located in // Answer 10 on the forum located here: // http://www.go4answers.com/Example/disconnecteditem-causing-it-115624.aspx if (_disconnectedItemSentinelValue == null) { if (IsDisconnected(target)) { _disconnectedItemSentinelValue = target; } ////var targetType = target.GetType(); ////if (targetType.FullName == "MS.Internal.NamedObject") ////{ //// var nameField = targetType.GetField("_name", BindingFlags.Instance | BindingFlags.NonPublic); //// if (nameField != null) //// if ((string)nameField.GetValue(target) == "DisconnectedItem") //// { //// _DisconnectedItemSentinelValue = target; //// } ////} } if (target != _disconnectedItemSentinelValue) { throw; } } ExecutionProviders.TryAdd(key, executionProvider); } return(executionProvider); }
private static ICommandExecutionProvider GetCommandExecutionProvider(object target, string canExecuteMethodName, string executedMethodName) { if (target == _DisconnectedItemSentinelValue) { return(null); } var key = new CommandExecutionProviderKey(target.GetType(), canExecuteMethodName, executedMethodName); ICommandExecutionProvider executionProvider = null; _Lock.EnterUpgradeableReadLock(); try { if (!_ExecutionProviders.TryGetValue(key, out executionProvider)) { _Lock.EnterWriteLock(); try { if (!_ExecutionProviders.TryGetValue(key, out executionProvider)) { var executionProviderType = typeof(CommandExecutionProvider <>).MakeGenericType(key.TargetType); var executionProviderCtor = executionProviderType.GetConstructor(new Type[] { typeof(Type), typeof(string), typeof(string) }); try { executionProvider = (ICommandExecutionProvider)executionProviderCtor.Invoke(new object[] { key.TargetType, key.CanExecuteMethodName, key.ExecutedMethodName }); } catch (TargetInvocationException) { // // Thanks to Mark Bergan for finding this issue! // Unfortunately we have some nastiness around a performance optimization in C# 4.0. // Because we are listening to DataContext events we may end up being provided a DataContext // value that is an internal place holder for the DataContext of disconnected containers WPF. // There is no easy way to detect this object, hence the reflection. Basically we just want to // ignore any disconnected DataContext items. The best documentation I have found is located in // Answer 10 on the forum located here: // http://www.go4answers.com/Example/disconnecteditem-causing-it-115624.aspx if (_DisconnectedItemSentinelValue == null) { var targetType = target.GetType(); if (targetType.FullName == "MS.Internal.NamedObject") { var nameField = targetType.GetField("_name", BindingFlags.Instance | BindingFlags.NonPublic); if (nameField != null) { if ((string)nameField.GetValue(target) == "DisconnectedItem") { _DisconnectedItemSentinelValue = target; } } } } if (target != _DisconnectedItemSentinelValue) { throw; } } _ExecutionProviders.Add(key, executionProvider); } } finally { _Lock.ExitWriteLock(); } } } finally { _Lock.ExitUpgradeableReadLock(); } return(executionProvider); }