diff --git a/AddIns/ICSharpCode.SharpDevelop.addin b/AddIns/ICSharpCode.SharpDevelop.addin index 2704c381b5..6bf30ae0fe 100644 --- a/AddIns/ICSharpCode.SharpDevelop.addin +++ b/AddIns/ICSharpCode.SharpDevelop.addin @@ -52,7 +52,6 @@ - + @@ -136,7 +135,6 @@ - diff --git a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs index 2f1bd22834..83ce02ea27 100644 --- a/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs +++ b/src/AddIns/DisplayBindings/AvalonEdit.AddIn/Src/CodeEditor.cs @@ -117,7 +117,13 @@ namespace ICSharpCode.AvalonEdit.AddIn public CodeEditor() { - this.CommandBindings.Add(new CommandBinding(SharpDevelopRoutedCommands.SplitView, OnSplitView)); + var contextName = this.GetType().FullName; + CommandsRegistry.RegisterCommandBindingsUpdateHandler(contextName, this, CommandsRegistry.CreateCommandBindingUpdateHandler(CommandBindings, contextName, this)); + CommandsRegistry.RegisterInputBindingUpdateHandler(contextName, this, CommandsRegistry.CreateInputBindingUpdateHandler(InputBindings, contextName, this)); + CommandsRegistry.RegisterCommandBinding(contextName, this, "SDWindowCommands.SplitView", OnSplitView, OnCanSplitView); + + CommandsRegistry.InvokeCommandBindingUpdateHandlers(contextName, this); + CommandsRegistry.InvokeInputBindingUpdateHandlers(contextName, this); textMarkerService = new TextMarkerService(this); iconBarManager = new IconBarManager(); @@ -198,6 +204,10 @@ namespace ICSharpCode.AvalonEdit.AddIn primaryTextEditor.Save(stream); } + void OnCanSplitView(object sender, CanExecuteRoutedEventArgs e) + { + e.CanExecute = true; + } void OnSplitView(object sender, ExecutedRoutedEventArgs e) { if (secondaryTextEditor == null) { diff --git a/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs b/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs index 9f6c0e6c2e..251b151887 100644 --- a/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs +++ b/src/Main/Base/Project/Src/Commands/MenuItemBuilders.cs @@ -456,6 +456,8 @@ namespace ICSharpCode.SharpDevelop.Commands get; } + public List bindingsAssigned = new List(); + public ICollection BuildItems(Codon codon, object owner) { ArrayList list = new ArrayList(); @@ -467,33 +469,32 @@ namespace ICSharpCode.SharpDevelop.Commands item.Icon = PresentationResourceService.GetPixelSnappedImage(padContent.Icon); } - // Dynamicaly create routed UI command for loaded pad var routedCommandName = "SDViewCommands.ShowView_" + padContent.Class; var routedCommandText = "Show view " + MenuService.ConvertLabel(StringParser.Parse(padContent.Title)); - CommandsRegistry.RegisterRoutedUICommand(routedCommandName, routedCommandText); - - // Register command which will activate loaded tab - CommandsRegistry.LoadCommand(routedCommandName, new BringPadToFrontCommand(padContent)); - - // Register command binding in workbench - CommandsRegistry.RegisterCommandBinding(CommandsRegistry.DefaultContext, routedCommandName, routedCommandName, null, false); - CommandsRegistry.InvokeCommandBindingUpdateHandlers(CommandsRegistry.DefaultContext); - - item.Command = CommandsRegistry.GetRoutedUICommand(routedCommandName); - // If pad have shortcut specified add input binding - if (!string.IsNullOrEmpty(padContent.Shortcut)) { - var gestures = (InputGestureCollection)new InputGestureCollectionConverter().ConvertFromString(padContent.Shortcut); - foreach(InputGesture gesture in gestures) { - CommandsRegistry.RegisterInputBinding(CommandsRegistry.DefaultContext, routedCommandName, gesture); + // TODO: fix this hack + if(!bindingsAssigned.Contains(routedCommandName)) { + // Dynamicaly create routed UI command to loaded pad and bindings for it + CommandsRegistry.RegisterRoutedUICommand(routedCommandName, routedCommandText); + CommandsRegistry.LoadCommand(routedCommandName, new BringPadToFrontCommand(padContent)); + CommandsRegistry.RegisterCommandBinding(CommandsRegistry.DefaultContext, null, routedCommandName, routedCommandName, null, false); + + // If pad have shortcut specified add input binding + if (!string.IsNullOrEmpty(padContent.Shortcut)) { + var gestures = (InputGestureCollection)new InputGestureCollectionConverter().ConvertFromString(padContent.Shortcut); + foreach(InputGesture gesture in gestures) { + CommandsRegistry.RegisterInputBinding(CommandsRegistry.DefaultContext, null, routedCommandName, gesture); + } } - item.InputGestureText = "M: " + padContent.Shortcut; - } else { - item.InputGestureText = "M: "; + bindingsAssigned.Add(routedCommandName); } - CommandsRegistry.InvokeInputBindingUpdateHandlers(CommandsRegistry.DefaultContext); + CommandsRegistry.InvokeCommandBindingUpdateHandlers(CommandsRegistry.DefaultContext, null); + CommandsRegistry.InvokeInputBindingUpdateHandlers(CommandsRegistry.DefaultContext, null); + + item.InputGestureText = padContent.Shortcut; + item.Command = CommandsRegistry.GetRoutedUICommand(routedCommandName); // item.Command = new BringPadToFrontCommand(padContent); // if (!string.IsNullOrEmpty(padContent.Shortcut)) { diff --git a/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonPadContent.cs b/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonPadContent.cs index 56b671b5d6..710745bef2 100644 --- a/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonPadContent.cs +++ b/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonPadContent.cs @@ -91,19 +91,10 @@ namespace ICSharpCode.SharpDevelop.Gui CommandsRegistry.LoadContext(contextName, (UIElement)Content); - CommandsRegistry.RegisterCommandBindingsUpdateHandler(contextName, delegate { - var bindings = CommandsRegistry.GetCommandBindings(contextName, null, null); - CommandsRegistry.RemoveManagedCommandBindings(CommandBindings); - CommandBindings.AddRange(bindings); - }); - - CommandsRegistry.RegisterInputBindingUpdateHandler(contextName, delegate { - var bindings = CommandsRegistry.GetInputBindings(contextName, null, null); - CommandsRegistry.RemoveManagedInputBindings(InputBindings); - InputBindings.AddRange(bindings); - }); - CommandsRegistry.InvokeCommandBindingUpdateHandlers(contextName); - CommandsRegistry.InvokeInputBindingUpdateHandlers(contextName); + CommandsRegistry.RegisterCommandBindingsUpdateHandler(contextName, null, CommandsRegistry.CreateCommandBindingUpdateHandler(CommandBindings, contextName, null)); + CommandsRegistry.RegisterInputBindingUpdateHandler(contextName, null, CommandsRegistry.CreateInputBindingUpdateHandler(InputBindings, contextName, null)); + CommandsRegistry.InvokeCommandBindingUpdateHandlers(contextName, null); + CommandsRegistry.InvokeInputBindingUpdateHandlers(contextName, null); } } } diff --git a/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs b/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs index c7ed197943..3dd774d97f 100644 --- a/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs +++ b/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs @@ -97,23 +97,11 @@ namespace ICSharpCode.SharpDevelop.Gui CommandsRegistry.LoadContext(contextName, (UIElement)Content); - CommandsRegistry.RegisterCommandBindingsUpdateHandler( - contextName, - delegate { - var bindings = CommandsRegistry.GetCommandBindings(contextName, null, null); - CommandsRegistry.RemoveManagedCommandBindings(CommandBindings); - CommandBindings.AddRange(bindings); - }); - CommandsRegistry.RegisterInputBindingUpdateHandler( - contextName, - delegate { - var bindings = CommandsRegistry.GetInputBindings(contextName, null, null); - CommandsRegistry.RemoveManagedInputBindings(InputBindings); - InputBindings.AddRange(bindings); - }); - CommandsRegistry.InvokeCommandBindingUpdateHandlers(contextName); - CommandsRegistry.InvokeInputBindingUpdateHandlers(contextName); + CommandsRegistry.RegisterCommandBindingsUpdateHandler(contextName, null, CommandsRegistry.CreateCommandBindingUpdateHandler(CommandBindings, contextName, null)); + CommandsRegistry.RegisterInputBindingUpdateHandler(contextName, null, CommandsRegistry.CreateInputBindingUpdateHandler(InputBindings, contextName, null)); + CommandsRegistry.InvokeCommandBindingUpdateHandlers(contextName, null); + CommandsRegistry.InvokeInputBindingUpdateHandlers(contextName, null); } } diff --git a/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs index fca7208fdf..a8e5c9a48f 100644 --- a/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs +++ b/src/Main/Base/Project/Src/Gui/Workbench/WpfWorkbench.cs @@ -92,20 +92,10 @@ namespace ICSharpCode.SharpDevelop.Gui // Register context and load all commands from addin CommandsRegistry.LoadAddinCommands(AddInTree.AddIns.FirstOrDefault(a => a.Name == "SharpDevelop")); - CommandsRegistry.RegisterCommandBindingsUpdateHandler(CommandsRegistry.DefaultContext, delegate { - var bindings = CommandsRegistry.GetCommandBindings(CommandsRegistry.DefaultContext, null, null); - CommandsRegistry.RemoveManagedCommandBindings(CommandBindings); - CommandBindings.AddRange(bindings); - }); - - CommandsRegistry.RegisterInputBindingUpdateHandler(CommandsRegistry.DefaultContext, delegate { - var bindings = CommandsRegistry.GetInputBindings(CommandsRegistry.DefaultContext, null, null); - CommandsRegistry.RemoveManagedInputBindings(InputBindings); - InputBindings.AddRange(bindings); - }); - - CommandsRegistry.InvokeCommandBindingUpdateHandlers(CommandsRegistry.DefaultContext); - CommandsRegistry.InvokeInputBindingUpdateHandlers(CommandsRegistry.DefaultContext); + CommandsRegistry.RegisterCommandBindingsUpdateHandler(CommandsRegistry.DefaultContext, null, CommandsRegistry.CreateCommandBindingUpdateHandler(CommandBindings, CommandsRegistry.DefaultContext, null)); + CommandsRegistry.RegisterInputBindingUpdateHandler(CommandsRegistry.DefaultContext, null, CommandsRegistry.CreateInputBindingUpdateHandler(InputBindings, CommandsRegistry.DefaultContext, null)); + CommandsRegistry.InvokeCommandBindingUpdateHandlers(CommandsRegistry.DefaultContext, null); + CommandsRegistry.InvokeInputBindingUpdateHandlers(CommandsRegistry.DefaultContext, null); mainMenu.ItemsSource = MenuService.CreateMenuItems(this, this, mainMenuPath); diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandBindingInfo.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandBindingInfo.cs index 21a9b1fa56..bfca7ba074 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandBindingInfo.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandBindingInfo.cs @@ -9,6 +9,8 @@ namespace ICSharpCode.Core.Presentation /// public class CommandBindingInfo { + private UIElement contextInstance; + /// /// Constructor /// @@ -24,6 +26,30 @@ namespace ICSharpCode.Core.Presentation IsLazy = isLazy; AddIn = addIn; } + + public CommandBindingInfo(string contextName, UIElement contextInstance, string routedCommandName, string className, AddIn addIn, bool isLazy) { + RoutedCommandName = routedCommandName; + ContextName = contextName; + ClassName = className; + IsLazy = isLazy; + AddIn = addIn; + this.contextInstance = contextInstance; + } + + public CommandBindingInfo(string contextName, string routedCommandName, ExecutedRoutedEventHandler executedHandler, CanExecuteRoutedEventHandler canExecuteHandler) { + RoutedCommandName = routedCommandName; + ContextName = contextName; + this.executedEventHandler = executedHandler; + this.canExecutedEventHandler = canExecuteHandler; + } + + public CommandBindingInfo(string contextName, UIElement contextInstance, string routedCommandName, ExecutedRoutedEventHandler executedHandler, CanExecuteRoutedEventHandler canExecuteHandler) { + RoutedCommandName = routedCommandName; + ContextName = contextName; + this.executedEventHandler = executedHandler; + this.canExecutedEventHandler = canExecuteHandler; + this.contextInstance = contextInstance; + } /// /// Routed command name @@ -101,10 +127,14 @@ namespace ICSharpCode.Core.Presentation /// public UIElement Context { get { - UIElement context; - CommandsRegistry.contexts.TryGetValue(ContextName, out context); - - return context; + if(contextInstance != null) { + return contextInstance; + } else { + UIElement context; + CommandsRegistry.contexts.TryGetValue(ContextName, out context); + + return context; + } } } @@ -118,5 +148,38 @@ namespace ICSharpCode.Core.Presentation public bool IsLazy{ get; private set; } + + private ExecutedRoutedEventHandler executedEventHandler; + public void ExecutedEventHandler(object sender, ExecutedRoutedEventArgs e) { + if(executedEventHandler != null) { + executedEventHandler.Invoke(sender, e); + } else { + if(IsLazy && Class == null) { + AddIn.LoadRuntimeAssemblies(); + + var command = (ICommand)AddIn.CreateObject(ClassName); + CommandsRegistry.LoadCommand(ClassName, command); + } + + if(Class != null) { + Class.Execute(e.Parameter); + } + } + } + + private CanExecuteRoutedEventHandler canExecutedEventHandler; + public void CanExecuteEventHandler(object sender, CanExecuteRoutedEventArgs e) { + if(canExecutedEventHandler != null) { + canExecutedEventHandler.Invoke(sender, e); + } else { + if(IsLazy && Class == null) { + e.CanExecute = true; + } else if(Class == null) { + e.CanExecute = false; + } else { + e.CanExecute = Class.CanExecute(e.Parameter); + } + } + } } } diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsRegistry.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsRegistry.cs index e4f285943e..cefd146e7e 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsRegistry.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsRegistry.cs @@ -14,6 +14,11 @@ namespace ICSharpCode.Core.Presentation /// public static class CommandsRegistry { + /// + /// This element is used to represent null key in dictionary + /// + private static UIElement NullUIElement = new UIElement(); + /// /// Default application context. /// @@ -30,8 +35,8 @@ namespace ICSharpCode.Core.Presentation internal static Dictionary commands = new Dictionary(); internal static Dictionary contexts = new Dictionary(); - private static Dictionary> commandBindingsUpdateHandlers = new Dictionary>(); - private static Dictionary> inputBindingsUpdateHandlers = new Dictionary>(); + private static Dictionary>> commandBindingsUpdateHandlers = new Dictionary>>(); + private static Dictionary>> inputBindingsUpdateHandlers = new Dictionary>>(); /// /// Get reference to routed UI command by name @@ -45,20 +50,48 @@ namespace ICSharpCode.Core.Presentation return null; } + + /// + /// Checks whether routed UI command registered + /// + /// Routed command name + /// Returns value specifting whether routed UI command is registered + public static bool IsRoutedUICommandRegistered(string routedCommandName) { + return GetRoutedUICommand(routedCommandName) != null; + } /// /// Register new routed command in the global registry /// - /// Routed command name should be uniq in SharpDevelop scope. - /// Use "." to emulate namespaces + /// Routed command name should be unique in SharpDevelop scope. + /// Use "." to organize commands into groups /// /// Routed command name /// Short text describing command functionality public static void RegisterRoutedUICommand(string routedCommandName, string text) { - var routedCommand = new RoutedUICommand(text, routedCommandName, typeof(UIElement)); + var routedCommand = new RoutedUICommand(text, routedCommandName, typeof(CommandsRegistry)); if(!routedCommands.ContainsKey(routedCommandName)) { routedCommands.Add(routedCommandName, routedCommand); + } else { + var test = routedCommands[routedCommandName]; + throw new IndexOutOfRangeException("Routed UI command with name " + routedCommandName + " is already registered"); + } + } + + /// + /// Register existing routed command in the global registry + /// + /// Routed command then can be accessed + /// Routed command name should be uniq in SharpDevelop scope. + /// Use "." to organize commands into groups + /// + /// Existing routed command + public static void RegisterRoutedUICommand(RoutedUICommand existingRoutedUICommand) { + string routedCommandName = existingRoutedUICommand.OwnerType.Name + "." + existingRoutedUICommand.Name; + + if(!routedCommands.ContainsKey(routedCommandName)) { + routedCommands.Add(existingRoutedUICommand.OwnerType.Name + "." + existingRoutedUICommand.Name, existingRoutedUICommand); } else { throw new IndexOutOfRangeException("Routed UI command with name " + routedCommandName + " is already registered"); } @@ -75,16 +108,17 @@ namespace ICSharpCode.Core.Presentation } /// - /// Register several input bindings with the same + /// Register input binding in context /// - /// Registering input binding means that when provided gesture is met in specified - /// context routed command will be invoked + /// Registering input binding means that when specified gesture is met in specified + /// context routed command is invoked /// /// Context class full name + /// Context class instance. If instance is provided this input binding only applies to provided UI element /// Routed UI command invoked on gesture run /// Gesture - public static void RegisterInputBinding(string contextName, string routedCommandName, InputGesture gesture) { - var inputBindingInfo = new InputBindingInfo(contextName, routedCommandName, gesture); + public static void RegisterInputBinding(string contextName, UIElement contextInstance, string routedCommandName, InputGesture gesture) { + var inputBindingInfo = new InputBindingInfo(contextName, contextInstance, routedCommandName, gesture); inputBidnings.Add(inputBindingInfo); } @@ -94,11 +128,13 @@ namespace ICSharpCode.Core.Presentation /// Null arguments are ignored /// /// Context class full name + /// Unregister binding assigned to specific context instance /// Routed UI command name /// Gesture - public static void UnregisterInputBindings(string contextName, string routedCommandName, InputGesture gesture) { + public static void UnregisterInputBindings(string contextName, UIElement contextInstance, string routedCommandName, InputGesture gesture) { for(int i = inputBidnings.Count - 1; i >= 0; i--) { if((contextName == null || inputBidnings[i].ContextName == contextName) + && (contextInstance == null || inputBidnings[i].Context == null || inputBidnings[i].Context == contextInstance) && (routedCommandName == null || inputBidnings[i].RoutedCommandName == routedCommandName) && (gesture == null || inputBidnings[i].Gesture == gesture)) { inputBidnings.RemoveAt(i); @@ -110,25 +146,40 @@ namespace ICSharpCode.Core.Presentation /// Register delegate which will be invoked on change in input bindings in specified context /// /// Context class full name + /// Register update handler which will trigger only if input bindings registered for this object where triggered /// Update handler delegate - public static void RegisterInputBindingUpdateHandler(string contextName, BindingsUpdatedHandler handler) { + public static void RegisterInputBindingUpdateHandler(string contextName, UIElement contextInstance, BindingsUpdatedHandler handler) { + if(contextInstance == null) { + contextInstance = NullUIElement; + } + if(!inputBindingsUpdateHandlers.ContainsKey(contextName)) { - inputBindingsUpdateHandlers.Add(contextName, new List()); + inputBindingsUpdateHandlers.Add(contextName, new Dictionary>()); } - inputBindingsUpdateHandlers[contextName].Add(new WeakReference(handler)); + if(!inputBindingsUpdateHandlers[contextName].ContainsKey(contextInstance)) { + inputBindingsUpdateHandlers[contextName].Add(contextInstance, new List()); + } + + inputBindingsUpdateHandlers[contextName][contextInstance].Add(handler); } /// /// Remove input bindings update handler /// /// Context class full name + /// Unregister update handler which was triggered only if input bindings registered for specific instance where updated /// Update handler delegate - public static void UnregisterInputBindingUpdateHandler(string contextName, BindingsUpdatedHandler handler) { + public static void UnregisterInputBindingUpdateHandler(string contextName, UIElement contextInstance, BindingsUpdatedHandler handler) { + if(contextInstance == null) { + contextInstance = NullUIElement; + } if(!inputBindingsUpdateHandlers.ContainsKey(contextName)) { - for(int i = inputBindingsUpdateHandlers[contextName].Count - 1; i >= 0; i++) { - if(inputBindingsUpdateHandlers[contextName][i].Target == handler) { - inputBindingsUpdateHandlers[contextName].RemoveAt(i); + if(!inputBindingsUpdateHandlers[contextName].ContainsKey(contextInstance)) { + for(int i = inputBindingsUpdateHandlers[contextName][contextInstance].Count - 1; i >= 0; i++) { + if(inputBindingsUpdateHandlers[contextName][contextInstance][i] == handler) { + inputBindingsUpdateHandlers[contextName][contextInstance].RemoveAt(i); + } } } } @@ -139,20 +190,36 @@ namespace ICSharpCode.Core.Presentation /// Invoke registered input bindings update handlers registered in specified context /// /// Context class full name - public static void InvokeInputBindingUpdateHandlers(string contextName) { + public static void InvokeInputBindingUpdateHandlers(string contextName, UIElement contextInstance) { + if(contextInstance == null) { + contextInstance = NullUIElement; + } + if(contextName != null) { if(inputBindingsUpdateHandlers.ContainsKey(contextName)) { - foreach(var handler in inputBindingsUpdateHandlers[contextName]) { - if(handler != null && handler.Target != null) { - ((BindingsUpdatedHandler)handler.Target).Invoke(); + if(contextInstance == NullUIElement) { + foreach(var instanceHandlers in inputBindingsUpdateHandlers[contextName]) { + foreach(var handler in instanceHandlers.Value) { + if(handler != null) { + ((BindingsUpdatedHandler)handler).Invoke(); + } + } } } + } else if(inputBindingsUpdateHandlers[contextName].ContainsKey(contextInstance)) { + foreach(var handler in inputBindingsUpdateHandlers[contextName][contextInstance]) { + if(handler != null) { + ((BindingsUpdatedHandler)handler).Invoke(); + } + } } } else { foreach(var contextHandlers in inputBindingsUpdateHandlers) { - foreach(var handler in contextHandlers.Value) { - if(handler != null && handler.Target != null) { - ((BindingsUpdatedHandler)handler.Target).Invoke(); + foreach(var instanceHandlers in contextHandlers.Value) { + foreach(var handler in instanceHandlers.Value) { + if(handler != null) { + ((BindingsUpdatedHandler)handler).Invoke(); + } } } } @@ -178,12 +245,26 @@ namespace ICSharpCode.Core.Presentation /// in specified context event is routed to specified command (implementing ICommand class) /// /// Context class full name + /// Register update handler which is triggered only if input bindings registered for specific instance are updated /// Routed UI command name /// Command full name to which invokation event is routed /// Add-in in which hosts the command /// Load add-in referenced assemblies on command invocation - public static void RegisterCommandBinding(string contextName, string routedCommandName, string className, AddIn addIn, bool isLazy) { - var commandBindingInfo = new CommandBindingInfo(contextName, routedCommandName, className, addIn, isLazy); + public static void RegisterCommandBinding(string contextName, UIElement contextInstance, string routedCommandName, string className, AddIn addIn, bool isLazy) { + var commandBindingInfo = new CommandBindingInfo(contextName, contextInstance, routedCommandName, className, addIn, isLazy); + commandBindings.Add(commandBindingInfo); + } + + /// + /// Register command binding which when triggered provided delegates are invoked + /// + /// Context class full name + /// Register update handler which is triggered only if input bindings registered for specific instance are updated + /// Routed UI command name + /// Delegate which is called when binding is triggered + /// Delegate which is called to check whether executedEventHandler can be invoked + public static void RegisterCommandBinding(string contextName, UIElement contextInstance, string routedCommandName, ExecutedRoutedEventHandler executedEventHandler, CanExecuteRoutedEventHandler canExecuteEventHandler) { + var commandBindingInfo = new CommandBindingInfo(contextName, contextInstance, routedCommandName, executedEventHandler, canExecuteEventHandler); commandBindings.Add(commandBindingInfo); } @@ -193,11 +274,13 @@ namespace ICSharpCode.Core.Presentation /// Null arguments are ignored /// /// Context class full name + /// Unregister update handler which was triggered only if command bindings registered for specific instance where updated /// Routed UI command name /// Command full name to which invokation event is routed - public static void UnregisterCommandBindings(string contextName, string routedCommandName, string className) { + public static void UnregisterCommandBindings(string contextName, UIElement contextInstance, string routedCommandName, string className) { for(int i = commandBindings.Count - 1; i >= 0; i--) { if((contextName == null || commandBindings[i].ContextName == contextName) + && (contextInstance == null || commandBindings[i].Context == null || commandBindings[i].Context == contextInstance) && (routedCommandName == null || commandBindings[i].RoutedCommandName == routedCommandName) && (className == null || commandBindings[i].ClassName == className)) { inputBidnings.RemoveAt(i); @@ -209,25 +292,39 @@ namespace ICSharpCode.Core.Presentation /// Register delegate which will be invoked on any chage in command bindings of specified context /// /// Context class full name + /// Register update handler which is triggered only if input bindings registered for specific instance are updated /// Update handler delegate - public static void RegisterCommandBindingsUpdateHandler(string contextName, BindingsUpdatedHandler handler) { + public static void RegisterCommandBindingsUpdateHandler(string contextName, UIElement contextInstance, BindingsUpdatedHandler handler) { + if(contextInstance == null) { + contextInstance = NullUIElement; + } if(!commandBindingsUpdateHandlers.ContainsKey(contextName)) { - commandBindingsUpdateHandlers.Add(contextName, new List()); + commandBindingsUpdateHandlers.Add(contextName, new Dictionary>()); + } + + if(!commandBindingsUpdateHandlers[contextName].ContainsKey(contextInstance)) { + commandBindingsUpdateHandlers[contextName].Add(contextInstance, new List()); } - commandBindingsUpdateHandlers[contextName].Add(new WeakReference(handler)); + commandBindingsUpdateHandlers[contextName][contextInstance].Add(handler); } /// /// Remove handler command bindings update handler /// /// Context class full name + /// Unregister update handler which was triggered only if input bindings registered for specific instance were updated /// Update handler delegate - public static void UnregisterCommandBindingsUpdateHandler(string contextName, BindingsUpdatedHandler handler) { + public static void UnregisterCommandBindingsUpdateHandler(string contextName, UIElement contextInstance, BindingsUpdatedHandler handler) { + if(contextInstance == null) { + contextInstance = NullUIElement; + } if(commandBindingsUpdateHandlers.ContainsKey(contextName)) { - for(int i = commandBindingsUpdateHandlers[contextName].Count - 1; i >= 0; i--) { - if(commandBindingsUpdateHandlers[contextName][i].Target == handler) { - commandBindingsUpdateHandlers[contextName].RemoveAt(i); + if(commandBindingsUpdateHandlers[contextName].ContainsKey(contextInstance)) { + for(int i = commandBindingsUpdateHandlers[contextName][contextInstance].Count - 1; i >= 0; i--) { + if(commandBindingsUpdateHandlers[contextName][contextInstance][i] == handler) { + commandBindingsUpdateHandlers[contextName][contextInstance].RemoveAt(i); + } } } } @@ -237,20 +334,37 @@ namespace ICSharpCode.Core.Presentation /// Invoke registered command bindings update handlers registered in specified context /// /// Context class full name - public static void InvokeCommandBindingUpdateHandlers(string contextName) { + /// Invoke update handlers which handle update only in specifyc context + public static void InvokeCommandBindingUpdateHandlers(string contextName, UIElement contextInstance) { + if(contextInstance == null) { + contextInstance = NullUIElement; + } + if(contextName != null) { if(commandBindingsUpdateHandlers.ContainsKey(contextName)) { - foreach(var handler in commandBindingsUpdateHandlers[contextName]) { - if(handler != null && handler.Target != null) { - ((BindingsUpdatedHandler)handler.Target).Invoke(); + if(contextInstance == NullUIElement) { + foreach(var instanceHandlers in commandBindingsUpdateHandlers[contextName]) { + foreach(var handler in instanceHandlers.Value) { + if(handler != null) { + ((BindingsUpdatedHandler)handler).Invoke(); + } + } + } + } else if(commandBindingsUpdateHandlers[contextName].ContainsKey(contextInstance)) { + foreach(var handler in commandBindingsUpdateHandlers[contextName][contextInstance]) { + if(handler != null) { + ((BindingsUpdatedHandler)handler).Invoke(); + } } } } } else { foreach(var contextHandlers in commandBindingsUpdateHandlers) { - foreach(var handler in contextHandlers.Value) { - if(handler != null && handler.Target != null) { - ((BindingsUpdatedHandler)handler.Target).Invoke(); + foreach(var instanceHandlers in contextHandlers.Value) { + foreach(var handler in instanceHandlers.Value) { + if(handler != null) { + ((BindingsUpdatedHandler)handler).Invoke(); + } } } } @@ -305,7 +419,6 @@ namespace ICSharpCode.Core.Presentation } } - /// /// Load context /// @@ -322,22 +435,22 @@ namespace ICSharpCode.Core.Presentation /// Null arguments are ignored /// /// Context class full name + /// Get command bindings assigned only to specific context /// Context class full name /// Context class full name /// Collection of managed command bindings - public static CommandBindingCollection GetCommandBindings(string contextName, string routedCommandName, string className) { + public static CommandBindingCollection GetCommandBindings(string contextName, UIElement contextInstance, string routedCommandName, string className) { var bindings = new CommandBindingCollection(); foreach(var binding in commandBindings) { if((contextName == null || binding.ContextName == contextName) + && (contextInstance == null || binding.Context == null || binding.Context == contextInstance) && (routedCommandName == null || binding.RoutedCommandName == routedCommandName) && (className == null || binding.ClassName == className)) { - var handlers = new CommandBindingHandlersContainer(binding); - var managedCommandBinding = new ManagedCommandBinding(binding.RoutedCommand); - managedCommandBinding.CanExecute += handlers.CanExecuteHandler; - managedCommandBinding.Executed += handlers.ExecutedHanler; + managedCommandBinding.CanExecute += binding.CanExecuteEventHandler; + managedCommandBinding.Executed += binding.ExecutedEventHandler; bindings.Add(managedCommandBinding); } @@ -352,13 +465,15 @@ namespace ICSharpCode.Core.Presentation /// Null arguments are ignored /// /// Context class full name + /// Get input bindings assigned only to specific context /// Routed UI command name /// Gesture - public static InputBindingCollection GetInputBindings(string contextName, string routedCommandName, InputGesture gesture) { + public static InputBindingCollection GetInputBindings(string contextName, UIElement contextInstance, string routedCommandName, InputGesture gesture) { var bindings = new InputBindingCollection(); foreach(var binding in inputBidnings) { if((contextName == null || binding.ContextName == contextName) + && (contextInstance == null || binding.Context == null || binding.Context == contextInstance) && (routedCommandName == null || binding.RoutedCommandName == routedCommandName) && (gesture == null || binding.Gesture == gesture)) { @@ -369,16 +484,17 @@ namespace ICSharpCode.Core.Presentation return bindings; } -/// + /// /// Get list of input gestures from all input bindings which satisfy provided parameters /// /// Null arguments are ignored /// /// Context class full name + /// Get gestures assigned only to specific context /// Routed UI command name /// Gesture - public static InputGestureCollection GetInputGestures(string contextName, string routedCommandName, InputGesture gesture) { - var bindings = GetInputBindings(contextName, routedCommandName, gesture); + public static InputGestureCollection GetInputGestures(string contextName, UIElement contextInstance, string routedCommandName, InputGesture gesture) { + var bindings = GetInputBindings(contextName, contextInstance, routedCommandName, gesture); var gestures = new InputGestureCollection(); foreach(InputBinding binding in bindings) { @@ -389,52 +505,64 @@ namespace ICSharpCode.Core.Presentation } /// - /// Stores Executed and CanExecute event handlers used in command bindings + /// Create default BindingUpdateHandler which will update command bindings in specified context + /// + /// Collection which should be updated with latest bindings + /// Context name which was used to register command bindings + /// Reference to instance which is used to find command bindings registered in specific context instance + /// Bindings updated handler + public static BindingsUpdatedHandler CreateCommandBindingUpdateHandler(CommandBindingCollection bindingsCollection, string contextName, UIElement contextInstance) { + return new CommonCommandBindingUpdateDelegate(bindingsCollection, contextName, contextInstance).UpdateCommandBinding; + } + + /// + /// Create default BindingUpdateHandler which will update input bindings in specified context /// - class CommandBindingHandlersContainer + /// Collection which should be updated with latest bindings + /// Context name which was used to register input bindings + /// Reference to instance which is used to find command bindings registered in specific context instance + /// Bindings updated handler + public static BindingsUpdatedHandler CreateInputBindingUpdateHandler(InputBindingCollection bindingsCollection, string contextName, UIElement contextInstance) { + return new CommonInputBindingUpdateDelegate(bindingsCollection, contextName, contextInstance).UpdateInputBinding; + } + + class CommonCommandBindingUpdateDelegate { - private CommandBindingInfo binding; + CommandBindingCollection bindingsCollection; + string contextName; + UIElement contextInstance; - /// - /// Constructor - /// - /// Reference to object holding command bining details - public CommandBindingHandlersContainer(CommandBindingInfo binding) { - this.binding = binding; - } - - /// - /// CanExecute event handler - /// - /// Object which raised this event - /// Event arguments - public void CanExecuteHandler(Object sender, CanExecuteRoutedEventArgs e) { - if(binding.IsLazy && binding.Class == null) { - e.CanExecute = true; - } else if(binding.Class == null) { - e.CanExecute = false; - } else { - e.CanExecute = binding.Class.CanExecute(e.Parameter); - } + public CommonCommandBindingUpdateDelegate(CommandBindingCollection bindingsCollection, string contextName, UIElement contextInstance) { + this.bindingsCollection = bindingsCollection; + this.contextName = contextName; + this.contextInstance = contextInstance; } - /// - /// Executed event handler - /// - /// Object which raised this event - /// Event arguments - public void ExecutedHanler(Object sender, ExecutedRoutedEventArgs e) { - if(binding.IsLazy && binding.Class == null) { - binding.AddIn.LoadRuntimeAssemblies(); - - var command = (ICommand)binding.AddIn.CreateObject(binding.ClassName); - CommandsRegistry.LoadCommand(binding.ClassName, command); - } - - if(binding.Class != null) { - binding.Class.Execute(e.Parameter); - } + public void UpdateCommandBinding() { + var newBindings = CommandsRegistry.GetCommandBindings(contextName, contextInstance, null, null); + CommandsRegistry.RemoveManagedCommandBindings(bindingsCollection); + bindingsCollection.AddRange(newBindings); } } + + + class CommonInputBindingUpdateDelegate + { + InputBindingCollection bindingsCollection; + string contextName; + UIElement contextInstance; + + public CommonInputBindingUpdateDelegate(InputBindingCollection bindingsCollection, string contextName, UIElement contextInstance) { + this.bindingsCollection = bindingsCollection; + this.contextName = contextName; + this.contextInstance = contextInstance; + } + + public void UpdateInputBinding() { + var newBindings = CommandsRegistry.GetInputBindings(contextName, contextInstance, null, null); + CommandsRegistry.RemoveManagedInputBindings(bindingsCollection); + bindingsCollection.AddRange(newBindings); + } + } } } diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs index 6c33e823a0..26821428a7 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/CommandsService.cs @@ -11,11 +11,11 @@ namespace ICSharpCode.Core.Presentation /// public static class CommandsService { - private static void RegisterRoutedCommands(Type type) { + public static void RegisterRoutedCommands(Type type) { var typeProperties = type.GetProperties(BindingFlags.Static | BindingFlags.Public); foreach(var property in typeProperties) { var command = (RoutedUICommand)property.GetValue(null, null); - CommandsRegistry.RegisterRoutedUICommand(type.Name + "." + command.Name, command.Text); + CommandsRegistry.RegisterRoutedUICommand(command); } } @@ -46,13 +46,13 @@ namespace ICSharpCode.Core.Presentation CommandsRegistry.RegisterRoutedUICommand(desc.Command, desc.Command); } - CommandsRegistry.RegisterCommandBinding(contextName, desc.Command, desc.Class, desc.Codon.AddIn, desc.Lazy); + CommandsRegistry.RegisterCommandBinding(contextName, null, desc.Command, desc.Class, desc.Codon.AddIn, desc.Lazy); // If gestures are provided register input binding in the same context if(!string.IsNullOrEmpty(desc.Gestures)) { var gestures = (InputGestureCollection)new InputGestureCollectionConverter().ConvertFromString(desc.Gestures); foreach(InputGesture gesture in gestures) { - CommandsRegistry.RegisterInputBinding(contextName, desc.Command, gesture); + CommandsRegistry.RegisterInputBinding(contextName, null, desc.Command, gesture); } } } @@ -65,7 +65,7 @@ namespace ICSharpCode.Core.Presentation var contextName = !string.IsNullOrEmpty(desc.Context) ? desc.Context : CommandsRegistry.DefaultContext; var gesture = (KeyGesture)new KeyGestureConverter().ConvertFromInvariantString(desc.Gesture); - CommandsRegistry.RegisterInputBinding(contextName, desc.Command, gesture); + CommandsRegistry.RegisterInputBinding(contextName, null, desc.Command, gesture); } } } diff --git a/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs b/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs index b80765dc8c..229aaaaf1d 100644 --- a/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs +++ b/src/Main/ICSharpCode.Core.Presentation/CommandsService/InputBindingInfo.cs @@ -9,6 +9,8 @@ namespace ICSharpCode.Core.Presentation /// public class InputBindingInfo { + private UIElement contextInstance; + /// /// Constructor /// @@ -21,6 +23,14 @@ namespace ICSharpCode.Core.Presentation Gesture = gesture; } + public InputBindingInfo(string contextName, UIElement contextInstance, string routedCommandName, InputGesture gesture) { + ContextName = contextName; + RoutedCommandName = routedCommandName; + Gesture = gesture; + this.contextInstance = contextInstance; + } + + /// /// Context class full name /// @@ -37,10 +47,14 @@ namespace ICSharpCode.Core.Presentation /// public UIElement Context { get { - UIElement context; - CommandsRegistry.contexts.TryGetValue(ContextName, out context); - - return context; + if(contextInstance != null) { + return contextInstance; + } else { + UIElement context; + CommandsRegistry.contexts.TryGetValue(ContextName, out context); + + return context; + } } } diff --git a/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs b/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs index 43c2a6b5e9..29f1138f5e 100644 --- a/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs +++ b/src/Main/ICSharpCode.Core.Presentation/Menu/MenuCommand.cs @@ -127,9 +127,9 @@ namespace ICSharpCode.Core.Presentation } else { this.Command = routedCommand; - var gestures = CommandsRegistry.GetInputGestures(CommandsRegistry.DefaultContext, routedCommand.Name, null); + var gestures = CommandsRegistry.GetInputGestures(CommandsRegistry.DefaultContext, null, routedCommand.Name, null); var gesturesString = (string)new InputGestureCollectionConverter().ConvertToInvariantString(gestures); - this.InputGestureText = "M: " + gesturesString; + this.InputGestureText = gesturesString; } } else { this.Command = CommandWrapper.GetCommand(codon, caller, createCommand);