From 67304d86f7c27e1ca3d78bd1d2ad9a4a4eabb36b Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 26 Aug 2007 15:27:47 +0000 Subject: [PATCH] Support creating event handlers by double-clicking buttons in the WPF designer. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2670 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Src/Designer/BooDesignerGenerator.cs | 9 ++- .../AbstractDesignerGenerator.cs | 38 +++++++----- .../CSharpDesignerGenerator.cs | 39 ++++++++++-- .../VBNetDesignerGenerator.cs | 8 +-- ...vice.cs => AbstractEventHandlerService.cs} | 59 +++++++++++++------ .../Src/CSharpEventHandlerService.cs | 47 +++++++++++++++ .../WpfDesign.AddIn/Src/WpfViewContent.cs | 6 +- .../WpfDesign.AddIn/WpfDesign.AddIn.csproj | 3 +- .../Project/Xaml/XamlDesignContext.cs | 4 +- .../RefactoringService/RefactoringService.cs | 2 + 10 files changed, 163 insertions(+), 52 deletions(-) rename src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/{EventHandlerService.cs => AbstractEventHandlerService.cs} (63%) create mode 100644 src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/CSharpEventHandlerService.cs diff --git a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/Designer/BooDesignerGenerator.cs b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/Designer/BooDesignerGenerator.cs index de0bb22fce..8923b7beb9 100644 --- a/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/Designer/BooDesignerGenerator.cs +++ b/src/AddIns/BackendBindings/Boo/BooBinding/Project/Src/Designer/BooDesignerGenerator.cs @@ -106,10 +106,10 @@ namespace Grunwald.BooBinding.Designer return null; } - protected override string CreateEventHandler(EventDescriptor edesc, string eventMethodName, string body, string indentation) + protected override string CreateEventHandler(Type eventType, string eventMethodName, string body, string indentation) { if (string.IsNullOrEmpty(body)) body = "pass"; - string param = GenerateParams(edesc); + string param = GenerateParams(eventType); StringBuilder b = new StringBuilder(); b.AppendLine(indentation); @@ -134,10 +134,9 @@ namespace Grunwald.BooBinding.Designer return c.Region.EndLine + 1; } - protected static string GenerateParams(EventDescriptor edesc) + protected static string GenerateParams(Type eventType) { - Type type = edesc.EventType; - MethodInfo mInfo = type.GetMethod("Invoke"); + MethodInfo mInfo = eventType.GetMethod("Invoke"); string param = ""; for (int i = 0; i < mInfo.GetParameters().Length; ++i) { diff --git a/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/AbstractDesignerGenerator.cs b/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/AbstractDesignerGenerator.cs index efbcc2d76a..a12a32798a 100644 --- a/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/AbstractDesignerGenerator.cs +++ b/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/AbstractDesignerGenerator.cs @@ -29,7 +29,7 @@ namespace ICSharpCode.FormsDesigner public abstract class AbstractDesignerGenerator : IDesignerGenerator { /// The currently open part of the class being designed. - IClass c; + protected IClass currentClassPart; /// The complete class being designed. IClass completeClass; /// The class part containing the designer code. @@ -341,9 +341,9 @@ namespace ICSharpCode.FormsDesigner for (int i = 1; i < count; i++) r.ReadLine(); string line = r.ReadLine(); - tabs = line.Substring(0, line.Length - line.TrimStart().Length); + tabs = GetIndentation(line); } - this.c = c; + this.currentClassPart = c; this.completeClass = c.GetCompoundClass(); this.formClass = initializeComponents.DeclaringType; break; @@ -352,7 +352,12 @@ namespace ICSharpCode.FormsDesigner } } - protected abstract string CreateEventHandler(EventDescriptor edesc, string eventMethodName, string body, string indentation); + protected static string GetIndentation(string line) + { + return line.Substring(0, line.Length - line.TrimStart().Length); + } + + protected abstract string CreateEventHandler(Type eventType, string eventMethodName, string body, string indentation); protected virtual int GetCursorLine(IDocument document, IMethod method) { @@ -374,7 +379,7 @@ namespace ICSharpCode.FormsDesigner { if (this.failedDesignerInitialize) { position = 0; - file = c.CompilationUnit.FileName; + file = currentClassPart.CompilationUnit.FileName; return false; } @@ -390,12 +395,12 @@ namespace ICSharpCode.FormsDesigner viewContent.MergeFormChanges(); Reparse(); - file = c.CompilationUnit.FileName; - int line = GetEventHandlerInsertionLine(c); + file = currentClassPart.CompilationUnit.FileName; + int line = GetEventHandlerInsertionLine(currentClassPart); int offset = viewContent.Document.GetLineSegment(line - 1).Offset; - viewContent.Document.Insert(offset, CreateEventHandler(edesc, eventMethodName, body, tabs)); + viewContent.Document.Insert(offset, CreateEventHandler(edesc.EventType, eventMethodName, body, tabs)); position = line + GetCursorLineAfterEventHandlerCreation(); return true; @@ -404,10 +409,10 @@ namespace ICSharpCode.FormsDesigner /// /// Gets a method implementing the signature specified by the event descriptor /// - protected IMethod ConvertDescriptorToDom(EventDescriptor edesc, string methodName) + protected static IMethod ConvertEventInvokeMethodToDom(IClass declaringType, Type eventType, string methodName) { - MethodInfo mInfo = edesc.EventType.GetMethod("Invoke"); - DefaultMethod m = new DefaultMethod(completeClass, methodName); + MethodInfo mInfo = eventType.GetMethod("Invoke"); + DefaultMethod m = new DefaultMethod(declaringType, methodName); m.ReturnType = ReflectionLayer.ReflectionReturnType.Create(m, mInfo.ReturnType, false); foreach (ParameterInfo pInfo in mInfo.GetParameters()) { m.Parameters.Add(new ReflectionLayer.ReflectionParameter(pInfo, m)); @@ -418,12 +423,15 @@ namespace ICSharpCode.FormsDesigner /// /// Gets a method implementing the signature specified by the event descriptor /// - protected ICSharpCode.NRefactory.Ast.MethodDeclaration - ConvertDescriptorToNRefactory(EventDescriptor edesc, string methodName) + protected static ICSharpCode.NRefactory.Ast.MethodDeclaration + ConvertEventInvokeMethodToNRefactory(IClass context, Type eventType, string methodName) { + if (context == null) + throw new ArgumentNullException("context"); + return ICSharpCode.SharpDevelop.Dom.Refactoring.CodeGenerator.ConvertMember( - ConvertDescriptorToDom(edesc, methodName), - new ClassFinder(c, c.BodyRegion.BeginLine + 1, 1) + ConvertEventInvokeMethodToDom(context, eventType, methodName), + new ClassFinder(context, context.BodyRegion.BeginLine + 1, 1) ) as ICSharpCode.NRefactory.Ast.MethodDeclaration; } diff --git a/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/CSharpDesignerGenerator.cs b/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/CSharpDesignerGenerator.cs index db05e3b381..32cb4a49c1 100644 --- a/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/CSharpDesignerGenerator.cs +++ b/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/CSharpDesignerGenerator.cs @@ -14,6 +14,7 @@ using System.Text; using ICSharpCode.Core; using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.TextEditor; +using ICSharpCode.TextEditor.Document; using ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.PrettyPrinter; @@ -21,7 +22,7 @@ namespace ICSharpCode.FormsDesigner { public class CSharpDesignerGenerator : AbstractDesignerGenerator { - protected override DomRegion GetReplaceRegion(ICSharpCode.TextEditor.Document.IDocument document, IMethod method) + protected override DomRegion GetReplaceRegion(IDocument document, IMethod method) { return new DomRegion(GetCursorLine(document, method), 1, method.BodyRegion.EndLine, 1); } @@ -31,9 +32,9 @@ namespace ICSharpCode.FormsDesigner return new Microsoft.CSharp.CSharpCodeProvider(); } - protected override string CreateEventHandler(EventDescriptor edesc, string eventMethodName, string body, string indentation) + protected override string CreateEventHandler(Type eventType, string eventMethodName, string body, string indentation) { - string param = GenerateParams(edesc, true); + string param = GenerateParams(eventType, true); StringBuilder b = new StringBuilder(); b.AppendLine(indentation); @@ -54,7 +55,7 @@ namespace ICSharpCode.FormsDesigner return 3; } - protected override int GetCursorLine(ICSharpCode.TextEditor.Document.IDocument document, IMethod method) + protected override int GetCursorLine(IDocument document, IMethod method) { if (document == null) throw new ArgumentNullException("document"); @@ -76,14 +77,40 @@ namespace ICSharpCode.FormsDesigner return r.BeginLine + 2; } - protected string GenerateParams(EventDescriptor edesc, bool paramNames) + protected string GenerateParams(Type eventType, bool paramNames) { CSharpOutputVisitor v = new CSharpOutputVisitor(); - MethodDeclaration md = ConvertDescriptorToNRefactory(edesc, "name"); + MethodDeclaration md = ConvertEventInvokeMethodToNRefactory(currentClassPart, eventType, "name"); if (md != null) { v.AppendCommaSeparatedList(md.Parameters); } return v.Text; } + + // static method that for use by the WPF designer + public static void CreateComponentEvent( + IClass c, IDocument document, + Type eventType, string eventMethodName, string body, out int lineNumber) + { + if (c == null) + throw new ArgumentNullException("c"); + if (document == null) + throw new ArgumentNullException("document"); + if (eventType == null) + throw new ArgumentNullException("edesc"); + + CSharpDesignerGenerator gen = new CSharpDesignerGenerator(); + + gen.currentClassPart = c; + int line = gen.GetEventHandlerInsertionLine(c); + + int offset = document.GetLineSegment(line - 1).Offset; + + string tabs = SharpDevelop.DefaultEditor.Gui.Editor.SharpDevelopTextEditorProperties.Instance.IndentationString; + tabs += tabs; + + document.Insert(offset, gen.CreateEventHandler(eventType, eventMethodName, body, tabs)); + lineNumber = line + gen.GetCursorLineAfterEventHandlerCreation(); + } } } diff --git a/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/VBNetDesignerGenerator.cs b/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/VBNetDesignerGenerator.cs index 021df0c689..2588cc1187 100644 --- a/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/VBNetDesignerGenerator.cs +++ b/src/AddIns/DisplayBindings/FormsDesigner/Project/Src/DesignerGenerator/VBNetDesignerGenerator.cs @@ -30,9 +30,9 @@ namespace ICSharpCode.FormsDesigner return new DomRegion(r.BeginLine + 1, 1, r.EndLine, 1); } - protected override string CreateEventHandler(EventDescriptor edesc, string eventMethodName, string body, string indentation) + protected override string CreateEventHandler(Type eventType, string eventMethodName, string body, string indentation) { - string param = GenerateParams(edesc); + string param = GenerateParams(eventType); StringBuilder b = new StringBuilder(); b.AppendLine(indentation); @@ -47,10 +47,10 @@ namespace ICSharpCode.FormsDesigner return b.ToString(); } - protected string GenerateParams(EventDescriptor edesc) + protected string GenerateParams(Type eventType) { VBNetOutputVisitor v = new VBNetOutputVisitor(); - MethodDeclaration md = ConvertDescriptorToNRefactory(edesc, "name"); + MethodDeclaration md = ConvertEventInvokeMethodToNRefactory(currentClassPart, eventType, "name"); if (md != null) { v.AppendCommaSeparatedList(md.Parameters); } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/EventHandlerService.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/AbstractEventHandlerService.cs similarity index 63% rename from src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/EventHandlerService.cs rename to src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/AbstractEventHandlerService.cs index 55e4f53a8b..26ce401610 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/EventHandlerService.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/AbstractEventHandlerService.cs @@ -7,26 +7,28 @@ using System; using System.ComponentModel; +using System.IO; +using System.Windows.Controls; + using ICSharpCode.SharpDevelop; -using ICSharpCode.SharpDevelop.Project; using ICSharpCode.SharpDevelop.Dom; -using ICSharpCode.Core; -using System.Windows.Controls; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.SharpDevelop.Project; namespace ICSharpCode.WpfDesign.AddIn { - sealed class EventHandlerService : IEventHandlerService + abstract class AbstractEventHandlerService : IEventHandlerService { WpfViewContent viewContent; - public EventHandlerService(WpfViewContent viewContent) + protected AbstractEventHandlerService(WpfViewContent viewContent) { if (viewContent == null) throw new ArgumentNullException("viewContent"); this.viewContent = viewContent; } - IProjectContent GetProjectContent() + protected IProjectContent GetProjectContent() { IProject p = ProjectService.OpenSolution.FindProjectContainingFile(viewContent.PrimaryFileName); if (p != null) @@ -35,25 +37,47 @@ namespace ICSharpCode.WpfDesign.AddIn return ParserService.DefaultProjectContent; } - public void CreateEventHandler(DesignItem item, DesignItemProperty eventProperty) + protected IClass GetDesignedClass() { - /*Designer.Xaml.XamlDesignContext xamlContext = item.Context as Designer.Xaml.XamlDesignContext; + Designer.Xaml.XamlDesignContext xamlContext = viewContent.DesignContext as Designer.Xaml.XamlDesignContext; if (xamlContext != null) { string className = xamlContext.ClassName; if (!string.IsNullOrEmpty(className)) { - IClass c = GetProjectContent().GetClass(className, 0); - if (c != null && !string.IsNullOrEmpty(c.CompilationUnit.FileName)) { - - } + return GetProjectContent().GetClass(className, 0); } } - - return; - */ - + return null; + } + + protected IClass GetDesignedClassCodeBehindPart(IClass c) + { + CompoundClass compound = c as CompoundClass; + if (compound != null) { + c = null; + foreach (IClass part in compound.GetParts()) { + if (string.IsNullOrEmpty(part.CompilationUnit.FileName)) + continue; + if (".xaml".Equals(Path.GetExtension(part.CompilationUnit.FileName), StringComparison.OrdinalIgnoreCase)) + continue; + if (c == null || c.CompilationUnit.FileName.Length > part.CompilationUnit.FileName.Length) + c = part; + } + } + return c; + } + + protected abstract void CreateEventHandlerInternal(Type eventHandlerType, string handlerName); + + public void CreateEventHandler(DesignItem item, DesignItemProperty eventProperty) + { string handlerName = (string)eventProperty.ValueOnInstance; if (string.IsNullOrEmpty(handlerName)) { if (string.IsNullOrEmpty(item.Name)) { + PadDescriptor padContent = WorkbenchSingleton.Workbench.GetPad(typeof(PropertyPad)); + if (padContent != null) { + padContent.BringPadToFront(); + } + // cannot create event for unnamed controls if (viewContent.PropertyEditor.NameTextBox.Focus()) { IErrorService errorService = item.Context.Services.GetService(); @@ -69,8 +93,7 @@ namespace ICSharpCode.WpfDesign.AddIn handlerName = item.Name + eventProperty.Name; eventProperty.SetValue(handlerName); } - - //viewContent.PrimaryFileName + ".cs" + CreateEventHandlerInternal(eventProperty.ReturnType, handlerName); } public DesignItemProperty GetDefaultEvent(DesignItem item) diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/CSharpEventHandlerService.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/CSharpEventHandlerService.cs new file mode 100644 index 0000000000..466334c493 --- /dev/null +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/CSharpEventHandlerService.cs @@ -0,0 +1,47 @@ +// +// +// +// +// $Revision: 2667$ +// + +using System; +using ICSharpCode.SharpDevelop; +using ICSharpCode.SharpDevelop.Gui; +using ICSharpCode.SharpDevelop.Dom; +using ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor; + +namespace ICSharpCode.WpfDesign.AddIn +{ + sealed class CSharpEventHandlerService : AbstractEventHandlerService + { + public CSharpEventHandlerService(WpfViewContent viewContent) : base(viewContent) + { + } + + protected override void CreateEventHandlerInternal(Type eventHandlerType, string handlerName) + { + IClass c = GetDesignedClass(); + if (c != null) { + foreach (IMethod m in c.Methods) { + if (m.Name == handlerName) { + FileService.JumpToFilePosition(m.DeclaringType.CompilationUnit.FileName, + m.Region.BeginLine - 1, m.Region.BeginColumn - 1); + return; + } + } + } + c = GetDesignedClassCodeBehindPart(c); + if (c != null) { + ITextEditorControlProvider tecp = FileService.OpenFile(c.CompilationUnit.FileName) as ITextEditorControlProvider; + if (tecp != null) { + int lineNumber; + FormsDesigner.CSharpDesignerGenerator.CreateComponentEvent( + c, tecp.TextEditorControl.Document, eventHandlerType, handlerName, null, + out lineNumber); + tecp.TextEditorControl.ActiveTextAreaControl.JumpTo(lineNumber - 1); + } + } + } + } +} diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/WpfViewContent.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/WpfViewContent.cs index 36f00bb2ed..5248fa7565 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/WpfViewContent.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/Src/WpfViewContent.cs @@ -31,6 +31,10 @@ namespace ICSharpCode.WpfDesign.AddIn ElementHost wpfHost; DesignSurface designer; + public DesignContext DesignContext { + get { return designer.DesignContext; } + } + public WpfViewContent(OpenedFile file) : base(file) { this.TabPageText = "${res:FormsDesigner.DesignTabPages.DesignTabPage}"; @@ -55,7 +59,7 @@ namespace ICSharpCode.WpfDesign.AddIn delegate(XamlDesignContext context) { context.Services.AddService(typeof(IUriContext), new FileUriContext(this.PrimaryFile)); context.Services.AddService(typeof(IPropertyDescriptionService), new PropertyDescriptionService(this.PrimaryFile)); - context.Services.AddService(typeof(IEventHandlerService), new EventHandlerService(this)); + context.Services.AddService(typeof(IEventHandlerService), new CSharpEventHandlerService(this)); context.Services.AddService(typeof(ITopLevelWindowService), new WpfAndWinFormsTopLevelWindowService()); }); settings.TypeFinder = MyTypeFinder.Create(this.PrimaryFile); diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/WpfDesign.AddIn.csproj b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/WpfDesign.AddIn.csproj index df70da371e..658e853f03 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/WpfDesign.AddIn.csproj +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.AddIn/WpfDesign.AddIn.csproj @@ -53,7 +53,8 @@ Configuration\GlobalAssemblyInfo.cs - + + diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs index ae14218812..96de92f640 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Xaml/XamlDesignContext.cs @@ -34,8 +34,8 @@ namespace ICSharpCode.WpfDesign.Designer.Xaml /// Gets/Sets the value of the "x:class" property on the root item. /// public string ClassName { - get { return _doc.RootElement.GetXamlAttribute("class"); } - set { _doc.RootElement.SetXamlAttribute("class", value); } + get { return _doc.RootElement.GetXamlAttribute("Class"); } + //set { _doc.RootElement.SetXamlAttribute("Class", value); } } /// diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs b/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs index bf9beb41f6..b21c5280c6 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/RefactoringService.cs @@ -80,6 +80,8 @@ namespace ICSharpCode.SharpDevelop.Refactoring /// public static List FindReferences(IMember member, IProgressMonitor progressMonitor) { + if (member == null) + throw new ArgumentNullException("member"); return RunFindReferences(member.DeclaringType, member, false, progressMonitor); }