/// <summary> /// Split this up in to sections so I can more easliy re-use it in the future. /// </summary> /// <param name="className"></param> public static void Generate(string className, string outputAssemblyName, CompilerFlags flags, List <String> assemblies) { string prefix = (flags.IsAbstract ? ABSTRACT_PREFIX : String.Empty); //this *can* generate more than one entry ControlTree[] trees = GenerateTree(className, outputAssemblyName, assemblies); if (trees != null && trees.Length == 1) { ControlTree tree = trees[0]; string s = ClassGenerator(tree, flags); string infill = (flags.AppendDesignedToFilename ? ".Designer" : String.Empty); //add in the Designed string fileName = System.IO.Path.Combine(flags.OutputPath, String.Format("{1}{0}Controller{2}.cs", tree.ClassName, prefix, infill)); //added a check to see if file exists, otherwise we might get weird streaming issues //if it does, I delete it for now. if (File.Exists(fileName)) { File.Delete(fileName); } WriteFile(s, fileName); if (flags.CreateEmptyNonDesignedFile) { string stubFileName = System.IO.Path.Combine(flags.OutputPath, String.Format("{1}{0}Controller.cs", tree.ClassName, prefix)); if (!System.IO.File.Exists(stubFileName)) { WriteFile(CreateStubFile(tree, flags), stubFileName); } } } }
/// <summary> /// Creates a stub file with the same makeup of the main file /// </summary> /// <param name="tree"></param> /// <param name="flags"></param> /// <returns></returns> private static string CreateStubFile(ControlTree tree, CompilerFlags flags) { string prefix = (flags.IsAbstract ? ABSTRACT_PREFIX : String.Empty); StringBuilder code = new StringBuilder(); code.AppendLine("/*This stub code was generated by the MvcFramework compiler, created by RatCow Soft - \r\n See http://code.google.com/p/ratcowsoftopensource/ */ \r\n\r\nusing System; \r\nusing System.Windows.Forms;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Reflection;\r\n\r\n//3rd Party\r\nusing RatCow.MvcFramework;\r\n"); code.AppendFormat("namespace {0}\r\n", tree.NamespaceName); code.AppendLine("{"); code.AppendFormat("\tinternal partial class {1}{0}Controller: BaseController<{0}>\r\n", tree.ClassName, prefix); code.AppendLine("\t{"); code.AppendLine("\t}"); code.AppendLine("}"); return(code.ToString()); }
private static void Main(string[] args) { //System.Diagnostics.Debugger.Break(); //Use this for force debugging XmlConfigurator.Configure(new System.IO.FileInfo("mvctool.exe.config")); CompilerFlags flags = new CompilerFlags(_log); //generate a list of assemblies in the associated mvcmap var assemblies = new List <String>(); string className = null; //This is new - we try to interpret the compiler params if (args.Length == 0) { Console.WriteLine("USAGE - mvctool [options] classname"); Console.WriteLine("\r\nOPTIONS:"); Console.WriteLine(" --abstract / -a : prefix controllers with \"Abstract\" prefix"); Console.WriteLine(" --partial-methods / -p : use partial methods (.Net 3.5+)"); Console.WriteLine(" -e : send the controller to event handlers"); Console.WriteLine(" -v : add pad code to protect list views"); Console.WriteLine(" -c : create a new action config file called \"default.mvcmap\" (this can't be used with any other params)"); Console.WriteLine(" -C : create a new action config file with view name passed (this can't be used with any other params)"); Console.WriteLine(" -r : use the default mvcmap when creating actions"); Console.WriteLine(" -R : use the mvcmap with the same name as the form passed when creating actions"); Console.WriteLine(" -d : append the .Designer tag to the file name (e.g. Form1.Designer.cs)"); Console.WriteLine(" -D : same as -d, but also creates a stub file if one doesn't exist."); Console.WriteLine(" -I : The location of the files to process. e.g. -I=c:\\projects\\views"); Console.WriteLine(" -O : The location of where the files are to be put. e.g. -I=c:\\projects\\controllers"); //Console.WriteLine( " -i : ignore any RESX file in the same scope (do not link resources)" ); Console.WriteLine(); return; } else if (args.Length > 1) { bool foundFormName = false; if (args[0].Contains("-C")) { CreateNewActionConfig(String.Format("{0}.mvcmap", args[1])); return; } foreach (string arg in args) { Console.WriteLine(arg); Log.Debug(arg); if (arg.StartsWith("-")) { Log.DebugFormat("Parsing param : {0}", arg); //assume it's a param if (arg.Contains("-a")) { flags.IsAbstract = true; //okay, this is a bit of a cheat } if (arg.Contains("-p")) { flags.UsePartialMethods = true; } if (arg.Contains("-e")) { flags.PassControllerToEvents = true; } if (arg.Contains("-v")) { flags.ProtectListViews = true; } if (arg.Contains("-r")) { flags.RestrictActions = true; flags.UseDefaultActionsFile = true; } if (arg.Contains("-d")) { flags.AppendDesignedToFilename = true; } if (arg.Contains("-D")) { flags.AppendDesignedToFilename = true; flags.CreateEmptyNonDesignedFile = true; } if (arg.Contains("-R")) { flags.RestrictActions = true; //flags.UseDefaultActionsFile = false; //this should default to false... } if (arg.StartsWith("-i=")) { string[] list = new StringBuilder(arg).Replace("-i=", String.Empty).Replace("\"", String.Empty).ToString().Split(','); assemblies.AddRange(list); } if (arg.StartsWith("-I=")) { flags.InputPath = arg.Replace("-I=", String.Empty); } if (arg.StartsWith("-O=")) { flags.OutputPath = arg.Replace("-O=", String.Empty); } } else { //assume it's the form name if (foundFormName) { var s = String.Format("Did not understand \"{0}\", already found \"{1}\", ignoring.", className, arg); Console.WriteLine(s); Log.Error(s); } else { if (arg.Contains(System.IO.Path.DirectorySeparatorChar)) { className = arg.Substring(arg.LastIndexOf(System.IO.Path.DirectorySeparatorChar) + 1); if (className.Contains(".")) { className = className.Remove(className.IndexOf(".")); } } else { className = arg; } foundFormName = true; Log.DebugFormat("Found {0}", className); } } } Console.WriteLine(flags); Log.Debug(flags); if (!foundFormName) { Console.WriteLine("Could not find the form name in the params! Aborted"); Log.Error("Could not find the form name in the params! Aborted"); return; } } else if (args.Length == 1 && args[0].Contains("-c")) { Log.Debug("Creating default.mvcmap"); CreateNewActionConfig("default.mvcmap"); return; } else //assume one param is form name { //this fixes a bug where user was unable to create a non abstract controller flags.IsAbstract = false; flags.UsePartialMethods = false; flags.PassControllerToEvents = false; flags.ProtectListViews = false; className = args[0]; } string outputAssemblyName = String.Format("{0}_{1}.dll", className, DateTime.Now.Ticks); Log.Debug(outputAssemblyName); //we currently assume this is one param and that is the name of the class //we also assume the files will be named in a standard C# naming convention. //i.e. MainForm -> MainForm.Designer.cs Log.Debug("Compiling class bootstrap"); if (ControllerCreationEngine.Compile(className, outputAssemblyName, flags, assemblies)) { Log.Debug("Generating code"); //if we get here, we created the desired assembly above ControllerCreationEngine.Generate(className, outputAssemblyName, flags, assemblies); Log.Debug("Successfully generated code"); } else { Console.WriteLine("Error! The file could not be generated."); Log.Error("Error! The file could not be generated."); return; } //Console.ReadLine(); //DEBUG - stop app before close }
/// <summary> /// This adds is a standard hook for the ListView and creates a ListViewHelper attached to it. /// </summary> /// <param name="controlName"></param> /// <param name="hook"></param> /// <param name="action"></param> private static void AddListViewHandler(string controlName, StringBuilder hook, StringBuilder action, CompilerFlags flags) { hook.AppendFormat("\t\tprotected ListViewHelper<T> Get{0}Helper<T>() where T : class\r\n", controlName); hook.AppendLine("\t\t{\r\n\t\t\t//Auto generated call"); hook.AppendFormat("\t\t\tvar lvh = new ListViewHelper<T>({0});\r\n", controlName); hook.AppendLine("\t\t\treturn lvh;"); hook.AppendLine("\t\t}\r\n"); //add in the handler for the virtual list item hook.AppendFormat("\t\t[Action(\"{0}\", \"RetrieveVirtualItem\")]\r\n\t\tpublic void F{0}_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)\r\n", controlName); hook.AppendLine("\t\t{\r\n\t\t\t//Auto generated call"); action.AppendFormat("\t\tprotected virtual void {0}RetrieveVirtualItem(RetrieveVirtualItemEventArgs e)\r\n", controlName); //added "protected virtual" so that I can descend and not have to alter this class at all. action.AppendLine("\t\t{"); action.AppendLine("\t\t\t/*we will first try to get an item from the partial method*/"); action.AppendLine("\t\t\tListViewItem item = null; //set to a known value"); if (flags.UsePartialMethods) { action.AppendFormat("\t\t\t{0}GetItem(ref item, e); //try to get the value from partial implementation\r\n", controlName); } if (flags.ProtectListViews) { action.AppendLine("\t\t\tif (item == null) //if, null, save ourselves from crashing \r\n\t\t\t{"); action.AppendLine("\t\t\t/*default placeholder to avoid crashes*/\r\n\t\t\titem = new ListViewItem();\r\n"); action.AppendLine("\t\t\t/*we need to provide a value for each column*/"); action.AppendFormat("\t\t\tint count = ({0}.Columns.Count);\r\n", controlName); action.AppendLine("\t\t\tif (count > 1)\r\n\t\t\t{"); action.AppendLine("\t\t\t\titem.Text = \"Temp value\";"); action.AppendLine("\t\t\t\tfor (int i = 1; i < count; i++)\r\n\t\t\t\t{"); action.AppendLine("\t\t\t\t\titem.SubItems.Add(\"Temp Subitem\");\r\n\t\t\t\t}\t\r\n\t\t\t}\r\n\t\t}"); } action.AppendLine("\r\n\t\t\te.Item = item;"); action.AppendLine("\t\t}\r\n"); hook.AppendFormat("\t\t\t{0}RetrieveVirtualItem(e);\r\n", controlName); hook.AppendLine("\t\t}\r\n"); if (flags.UsePartialMethods) { action.AppendFormat( "\t\tpartial void {0}GetItem(ref ListViewItem item, RetrieveVirtualItemEventArgs e);\r\n", controlName ); } }
/// <summary> /// Create generic event hooks /// </summary> private static void AddAction(string viewName, string controlName, string actionName, string eventArgsType, StringBuilder hook, StringBuilder action, CompilerFlags flags) { //DEBUG - Console.WriteLine("{0}Controller :: {1} :: {2} - -a : {3} -p : {4} -e : {5} -v : {6}", viewName, controlName, actionName, flags.IsAbstract, flags.UsePartialMethods, flags.PassControllerToEvents, flags.ProtectListViews); hook.AppendFormat("\t\t[Action(\"{0}\", \"{1}\")]\r\n\t\tpublic void F{0}_{1}(object sender, {2} e)\r\n", controlName, actionName, eventArgsType); hook.AppendLine("\t\t{\r\n\t\t\t//Auto generated call"); action.AppendFormat( "\t\t{2} void {0}{1}({4}{5} e){3}\r\n", controlName, actionName, (flags.UsePartialMethods ? "partial" : "protected virtual"), (flags.UsePartialMethods ? ";" : String.Empty), (flags.PassControllerToEvents ? String.Format("{0}Controller controller,", viewName) : String.Empty), eventArgsType ); //added "protected virtual" so that I can descend and not have to alter this class at all. //20120529 - added partial method option for 3.5+ if (!flags.UsePartialMethods) { action.AppendLine("\t\t{\r\n"); action.AppendLine("\t\t}\r\n"); }//20120529 - added partial method option for 3.5+ hook.AppendFormat("\t\t\t{0}{1}({2}e);\r\n", controlName, actionName, (flags.PassControllerToEvents ? "this, " : String.Empty)); hook.AppendLine("\t\t}\r\n"); }
/// <summary> /// KeyEventHandler stub. /// </summary> private static void AddKeyAction(string viewName, string controlName, string actionName, StringBuilder hook, StringBuilder action, CompilerFlags flags) { AddAction(viewName, controlName, actionName, "KeyEventArgs", hook, action, flags); }
/// <summary> /// This is going to initially be fairly slow /// </summary> private static void AddMappedActions(string viewName, KeyValuePair <string, Type> control, StringBuilder hook, StringBuilder action, CompilerFlags flags, ViewActionMap map) { var added = new List <String>(); //tally, to avoid double adds //we first add the generic stuff foreach (var ev in map.GlobalMap) { if (!added.Contains(ev.EventName)) { //does the event exist? var evi = control.Value.GetEvent(ev.EventName); if (evi == null) { continue; } else { AddAction(viewName, control.Key, ev.EventName, ev.EventArgsName, hook, action, flags); added.Add(ev.EventName); } } } //IEnumerable<ViewControlAction> controlMapItems = map.ControlActionMap.F(ev => ev.ControlType == control.Value.Name); var controlMapItems = from item in map.ControlActionMap where (item.ControlType == control.Value.Name || item.ControlType == control.Value.FullName) //this seems like a good idea, probably a bug since we extended the controlmaps to use the full name for non System.Windows.Forms controls....? select item; if (controlMapItems == null) { return; } else { foreach (var controlMap in controlMapItems) { if (controlMap != null) { foreach (var ev in controlMap.ControlActions) { //this has to be here if (!added.Contains(ev.EventName)) { AddAction(viewName, control.Key, ev.EventName, ev.EventArgsName, hook, action, flags); added.Add(ev.EventName); } } } } } }
/// <summary> /// Start to implement generic event handling /// </summary> private static void AddKnownActions(string viewName, KeyValuePair <string, Type> control, StringBuilder hook, StringBuilder action, CompilerFlags flags) { //test - get a list of all the events for this control EventInfo[] eva = control.Value.GetEvents(); foreach (var ev in eva) { //generally, the event is XXXXEvent and the args are XXXXArgs.. //TODO: look at making htis more generic.. can we get at the param info for the delegate? if (ev.EventHandlerType == typeof(System.EventHandler)) { AddStandardAction(viewName, control.Key, ev.Name, hook, action, flags); } else if (ev.EventHandlerType == typeof(System.Windows.Forms.MouseEventHandler)) { AddMouseAction(viewName, control.Key, ev.Name, hook, action, flags); } else if (ev.EventHandlerType == typeof(System.Windows.Forms.KeyEventHandler)) { AddKeyAction(viewName, control.Key, ev.Name, hook, action, flags); } else if (ev.EventHandlerType == typeof(System.Windows.Forms.DragEventHandler)) { AddDragAction(viewName, control.Key, ev.Name, hook, action, flags); } //could add an else clause to create a theoretical event arg from the handler name here... } }
/// <summary> /// /// </summary> /// <param name="tree"></param> /// <param name="isAbstract"></param> /// <returns></returns> public static string ClassGenerator(ControlTree tree, CompilerFlags flags) { string prefix = (flags.IsAbstract ? ABSTRACT_PREFIX : String.Empty); StringBuilder code = new StringBuilder(); code.AppendLine("/*Auto generated - this code was generated by the MvcFramework compiler, created by RatCow Soft - \r\n See http://code.google.com/p/ratcowsoftopensource/ */ \r\n\r\nusing System; \r\nusing System.Windows.Forms;\r\nusing System.Collections.Generic;\r\nusing System.Linq;\r\nusing System.Text;\r\nusing System.Reflection;\r\n\r\n//3rd Party\r\nusing RatCow.MvcFramework;\r\n"); code.AppendFormat("namespace {0}\r\n", tree.NamespaceName); code.AppendLine("{"); StringBuilder code_s1 = new StringBuilder(); if (flags.CreateEmptyNonDesignedFile) { //if we are creating a stub, we should put the inheritence in the stub, to allow it to be altered (e.g. modal) code_s1.AppendFormat("\tinternal partial class {1}{0}Controller\r\n", tree.ClassName, prefix); } else { code_s1.AppendFormat("\tinternal partial class {1}{0}Controller: BaseController<{0}>\r\n", tree.ClassName, prefix); } code_s1.AppendLine("\t{"); //constructor code_s1.AppendFormat("\t\tpublic {1}{0}Controller() : base()\r\n", tree.ClassName, prefix); code_s1.AppendLine("\t\t{\r\n\t\t}\r\n"); StringBuilder code_s2 = new StringBuilder(); code_s2.AppendLine("\r\n#region GUI glue code\r\n"); code_s2.AppendFormat("\tpartial class {1}{0}Controller\r\n", tree.ClassName, prefix); code_s2.AppendLine("\t{"); if (flags.RestrictActions) { //load the actions file ViewActionMap map = (flags.UseDefaultActionsFile ? GetDefaultViewActionMap() : GetNamedViewActionMap(tree.ClassName, true)); //we now have access to the controls foreach (var control in tree.Controls) { //System.Console.WriteLine(" var {0} : {1} ", control.Name, control.GetType().Name); //add the declaration to code_s2 code_s2.AppendFormat("\t\t[Outlet(\"{1}\")]\r\n\t\tpublic {0} {1} ", control.Value.FullName, control.Key); //add var code_s2.AppendLine("{ get; set; }"); //this should find all known event types AddMappedActions(tree.ClassName, control, code_s2, code_s1, flags, map); //specific listView hooks if (control.Value == typeof(System.Windows.Forms.ListView)) { AddListViewHandler(control.Key, code_s2, code_s1, flags); } } } else { //we now have access to the controls foreach (var control in tree.Controls) { //System.Console.WriteLine(" var {0} : {1} ", control.Name, control.GetType().Name); //add the declaration to code_s2 code_s2.AppendFormat("\t\t[Outlet(\"{1}\")]\r\n\t\tpublic {0} {1} ", control.Value.FullName, control.Key); //add var code_s2.AppendLine("{ get; set; }"); //this should find all known event types AddKnownActions(tree.ClassName, control, code_s2, code_s1, flags); //specific listView hooks if (control.Value == typeof(System.Windows.Forms.ListView)) { AddListViewHandler(control.Key, code_s2, code_s1, flags); } } } //some boiler plate code which helps set the data for a LisViewHelper code_s2.AppendLine("\t\tprotected void SetData<T>(ListViewHelper<T> helper, List<T> data) where T : class"); code_s2.AppendLine("\t\t{\r\n\t\t\t//Auto generated call"); code_s2.AppendLine("\t\t\tType t = helper.GetType();"); code_s2.AppendLine("\t\t\tt.InvokeMember(\"SetData\", BindingFlags.Default | BindingFlags.InvokeMethod, null, helper, new object[] { data });"); code_s2.AppendLine("\t\t}\r\n"); code_s1.AppendLine("\t}"); //end of class declaration code.AppendLine(code_s1.ToString()); code_s2.AppendLine("\t}"); //end of class declaration code_s2.AppendLine("#endregion /*GUI glue code*/"); code.AppendLine(code_s2.ToString()); code.AppendLine("}"); return(code.ToString()); }
/// <summary> /// Hacked mini compiler - it does enough to compile *basic* designer classes /// </summary> /// <param name="className"></param> /// <returns></returns> public static bool Compile(string className, string outputAssemblyName, CompilerFlags flags, List <String> extraAssemblies) { flags.LogDebug("Enter Compile"); //we attempt to compile the file provided and then read info from it CSharpCodeProvider compiler = new CSharpCodeProvider(); CompilerParameters compilerParams = new CompilerParameters(); compilerParams.ReferencedAssemblies.Add("System.dll"); compilerParams.ReferencedAssemblies.Add("System.XML.dll"); compilerParams.ReferencedAssemblies.Add("System.Data.dll"); compilerParams.ReferencedAssemblies.Add("System.Windows.Forms.dll"); compilerParams.ReferencedAssemblies.Add("System.Drawing.dll"); foreach (var extraAssembly in extraAssemblies) { compilerParams.ReferencedAssemblies.Add(extraAssembly); //this takes the physical location } //we can add more in here from command line in future revision compilerParams.GenerateExecutable = false; compilerParams.CompilerOptions = "/t:library"; compilerParams.OutputAssembly = outputAssemblyName; // "./temp.dll"; StringBuilder s = new StringBuilder(); string namespaceName = ""; string fileToCompile = System.IO.Path.Combine(flags.InputPath, String.Format("{0}.Designer.cs", className)); if (!File.Exists(fileToCompile)) { return(false); } TextReader tr = new StreamReader(File.OpenRead(fileToCompile)); try { //read till we find the namespace while (true) { string t = tr.ReadLine(); s.Append(t); if (t.Contains("namespace")) { namespaceName = t.Substring(10).Trim(); break; } } s.Append(tr.ReadToEnd()); } finally { tr.Close(); } //This is a bit of a hack... we need the designer to be a "Form" so we can compile it and //then use the Activator to access the contents later on. We *have* to call "InitializeComponents()" //otherwise, the form is in an uninitialized state and we will not have access to the parts we //actually *want*. string code = "{ public " + className + "(): base() { InitializeComponent();} public System.ComponentModel.IContainer ComponentsAccess {get { return components; } } } /*class*/ } /*namespace*/"; string dummy = String.Format("namespace {2} {3} partial class {0} : System.Windows.Forms.Form {1}", className, code, namespaceName, "{"); //we need to look for a resource file var resx = System.IO.Path.Combine(flags.InputPath, String.Format("{0}.resx", className)); //string rescode = null; var compiledResourceFilename = System.IO.Path.Combine(flags.InputPath, String.Format("{0}.{1}.resources", namespaceName, className)); //we should compile resource files by default!! if (!flags.IgnoreResourceFiles && File.Exists(resx)) { //we must now open the resource file and read the contents try { File.Delete(compiledResourceFilename); //remove older version } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); System.Diagnostics.Debug.WriteLine(ex.StackTrace); } //IDictionary dictionary = null; using (var stream = File.Open(resx, FileMode.Open, FileAccess.Read, FileShare.Read)) { using (var rsxr = new ResXResourceReader(stream)) { using (IResourceWriter writer = new ResourceWriter(compiledResourceFilename)) { // Iterate through the resources and add resources to the resource writer. //dictionary = new Dictionary<string, string>(); foreach (DictionaryEntry d in rsxr) { var k = d.Key.ToString(); var v = d.Value.ToString(); //dictionary.Add( k, v ); writer.AddResource(k, d.Value); //code example I used had this line as (k, v) which embeds a string resource rather than the real resource!!! } writer.Close(); } rsxr.Close(); } stream.Close(); } compilerParams.EmbeddedResources.Add(compiledResourceFilename); #region Old //code example I used had this, but it seems to break the compilation if included //string[] errors; //var provider = new CSharpCodeProvider(); // c#-code compiler //var cu = StronglyTypedResourceBuilder.Create( dictionary, className ?? string.Empty, "", provider, false, out errors ); //var options = new CodeGeneratorOptions //{ // BracingStyle = "C", // BlankLinesBetweenMembers = false, // IndentString = "\t" //}; //var tw = new StringWriter(); //provider.GenerateCodeFromCompileUnit( cu, tw, options ); //rescode = tw.ToString(); //tw.Close(); #endregion } //The files to compile string[] files = { dummy, s.ToString() }; //if ( rescode != null ) // files = new string[] { dummy, s.ToString(), rescode }; //else // files = new string[] { dummy, s.ToString() }; CompilerResults res = null; try { res = compiler.CompileAssemblyFromSource(compilerParams, files); } catch (BadImageFormatException ex) { System.Console.WriteLine(ex.Message); return(false); } catch (Exception ex) { System.Console.WriteLine(ex.Message); return(false); } if (res.Errors.HasErrors) { StringBuilder sb = new StringBuilder(); sb.Append("\nIllegal C# source code generated: "); sb.Append(res.Errors.Count.ToString()); sb.Append(" Errors:\n"); foreach (CompilerError error in res.Errors) { sb.Append("Line: "); sb.Append(error.Line.ToString()); sb.Append(" - "); sb.Append(error.ErrorText); sb.Append('\n'); } System.Console.WriteLine(sb.ToString()); return(false); } //make sure we delete the resourse we created try { if (File.Exists(compiledResourceFilename)) { File.Delete(compiledResourceFilename); } } catch { } //we don't care, we just don't want to throw an exception here if we compiled a successful assembly flags.LogDebug("Leave Compile"); return(true); }
private static void Main(string[] args) { //System.Diagnostics.Debugger.Break(); //Use this for force debugging CompilerFlags flags = new CompilerFlags(); string className = null; //This is new - we try to interpret the compiler params if (args.Length == 0) { Console.WriteLine("USAGE - mvctool [options] classname"); Console.WriteLine("\r\nOPTIONS:"); Console.WriteLine(" --abstract / -a : prefix controllers with \"Abstract\" prefix"); Console.WriteLine(" --partial-methods / -p : use partial methods (.Net 3.5+)"); Console.WriteLine(" -e : send the controller to event handlers"); Console.WriteLine(" -v : add pad code to protect list views"); Console.WriteLine(" -c : create a new action config file called \"default.mvcmap\" (this can't be used with any other params)"); Console.WriteLine(" -C : create a new action config file with view name passed (this can't be used with any other params)"); Console.WriteLine(" -r : use the default mvcmap when creating actions"); Console.WriteLine(" -R : use the mvcmap with the same name as the form passed when creating actions"); Console.WriteLine(" -d : append the .Designer tag to the file name (e.g. Form1.Designer.cs)"); Console.WriteLine(" -D : same as -d, but also creates a stub file if one doesn't exist."); Console.WriteLine(); return; } else if (args.Length > 1) { bool foundFormName = false; if (args[0].Contains("-C")) { CreateNewActionConfig(String.Format("{0}.mvcmap", args[1])); return; } foreach (string arg in args) { Console.WriteLine(arg); if (arg.StartsWith("-")) { //assume it's a param if (arg.Contains("-a")) { flags.IsAbstract = true; //okay, this is a bit of a cheat } if (arg.Contains("-p")) { flags.UsePartialMethods = true; } if (arg.Contains("-e")) { flags.PassControllerToEvents = true; } if (arg.Contains("-v")) { flags.ProtectListViews = true; } if (arg.Contains("-r")) { flags.RestrictActions = true; flags.UseDefaultActionsFile = true; } if (arg.Contains("-d")) { flags.AppendDesignedToFilename = true; } if (arg.Contains("-D")) { flags.AppendDesignedToFilename = true; flags.CreateEmptyNonDesignedFile = true; } if (arg.Contains("-R")) { flags.RestrictActions = true; //flags.UseDefaultActionsFile = false; //this should default to false... } } else { //assume it's the form name if (foundFormName) { Console.WriteLine(String.Format("Did not understand \"{0}\", already found \"{1}\", ignoring.", className, arg)); } else { className = arg; foundFormName = true; } } } Console.WriteLine(flags); if (!foundFormName) { Console.WriteLine("Could not find the form name in the params! Aborted"); return; } } else if (args.Length == 1 && args[0].Contains("-c")) { CreateNewActionConfig("default.mvcmap"); return; } else //assume one param is form name { //this fixes a bug where user was unable to create a non abstract controller flags.IsAbstract = false; flags.UsePartialMethods = false; flags.PassControllerToEvents = false; flags.ProtectListViews = false; className = args[0]; } string outputAssemblyName = String.Format("{0}_{1}.dll", className, DateTime.Now.Ticks); //we currently assume this is one param and that is the name of the class //we also assume the files will be named in a standard C# naming convention. //i.e. MainForm -> MainForm.Designer.cs if (ControllerCreationEngine.Compile(className, outputAssemblyName)) { //if we get here, we created the desired assembly above ControllerCreationEngine.Generate(className, outputAssemblyName, flags); } else { Console.WriteLine("Error! The file could not be generated."); return; } }