User avatar
CyberFox
Topic Author
Posts: 6
Joined: 06 May 2019, 10:41

Unity3D autogenerate .g.cs

06 May 2019, 12:08

https://www.noesisengine.com/docs/2.2/G ... ifferences
I'm too lazy and too stupid to manage that. Here's piece for generating the .g.cs code.

You can find the latest version of the script at https://github.com/CyberFoxHax/NoesisGU ... sGenerator

Installation:
In NoesisPostprocessor.cs find a method called ScanDependencies() in the bottom of the method body paste this code: "NoesisCsBindingsGenerator.GenerateCsFile(filename);" and you're good to go.


it will pump out code that looks like this:
using Noesis;

namespace Assets.UI.Views.DesignerUI {
	public partial class DesignerMain : UserControl {
		public Grid JustNormalGrid;
		public UniformGrid MyUniformGrid;
		public Assets.UI.Views.DesignerUI.CircleButton Skinkeskinke;
		private void InitializeComponent() {
			GUI.LoadComponent(this, "Assets/UI/Views/DesignerUI/DesignerMain.xaml");
			this.JustNormalGrid = (Grid)FindName("JustNormalGrid");
			this.MyUniformGrid = (UniformGrid)FindName("MyUniformGrid");
			this.Skinkeskinke = (Assets.UI.Views.DesignerUI.CircleButton)FindName("Skinkeskinke");
		}
	}
}
Last edited by CyberFox on 25 Jun 2019, 08:47, edited 1 time in total.
 
User avatar
sfernandez
Site Admin
Posts: 2991
Joined: 22 Dec 2011, 19:20

Re: Unity3D autogenerate .g.cs

07 May 2019, 11:03

Wow! This will be very helpfull for a lot of people, including us, thanks a lot for sharing it. We had in mind to implement something like this, but didn't get the chance yet.

One thing that could probably be improved in your code would be to use the x:Class name to get the namespace of the class, instead of relying on the folder structure, this way it would work for more scenarios. And it can also be used to determine if the generation of this g.cs file is required or not, because if x:Class is not present it means the xaml has no code-behind class.

And the other thing we wanted to include is the automatic connection of event handlers, that is, the generation of the ConnectEvent() override.
 
User avatar
CyberFox
Topic Author
Posts: 6
Joined: 06 May 2019, 10:41

Re: Unity3D autogenerate .g.cs

07 May 2019, 12:28

Yes, the x:Class is definitely the way to go. I've already had issues already because i needed (and forgot) to change the namespace structure manually

Looking at your example projects i also noticed these "event connectors". I believe them to be a tad more difficult to identify using a regex.
"x:Name" is fairly unique but event handlers have a myriad of names (Click, MouseUp, Focused to name a few). I fetch them via reflection but we might run into a race condition with new custom events not yet being available in the assemblies.

Since i'll probably keep working with Noesis i'll also keep patching this thing. Today i added the function to not reimport the script if there are no changes. Speeds up process a lot. Didn't have time for much today others, i struggled with getting OpacityMask working. (I didn't get it working. Damn thing is upside down inside Unity3D)
 
User avatar
sfernandez
Site Admin
Posts: 2991
Joined: 22 Dec 2011, 19:20

Re: Unity3D autogenerate .g.cs

07 May 2019, 12:57

i struggled with getting OpacityMask working. (I didn't get it working. Damn thing is upside down inside Unity3D)
Are you using latest NoesisGUI 2.2.2? We fixed a bunch of bugs pretty similar to that, see changelog 'Fixed Several bugs related to opacity and projection'.
 
User avatar
CyberFox
Topic Author
Posts: 6
Joined: 06 May 2019, 10:41

Re: Unity3D autogenerate .g.cs

08 May 2019, 07:40

I tried the update. There were a bunch of differences in the code so i updated mine accordingly.

NoesisCsBindingsGenerator.cs
using System.IO;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Text.RegularExpressions;
using System.Linq;

public class NoesisCsBindingsGenerator {
    public static void GenerateCsFile(string filename) {
        var generator = new NoesisCsBindingsGenerator();
        generator.XamlAsset = AssetDatabase.LoadAssetAtPath<NoesisXaml>(filename.Replace(".xaml", ".asset"));
        generator.XamlText = File.ReadAllText(filename);
        generator.SaveFile();
    }

    public NoesisXaml XamlAsset { get; set; }
    public string XamlText { get; set; }

    private static readonly Regex NameRegex = new Regex("x:Name=\"(.+)\""); // x:Name="MyElementNameHere"
    private static readonly Regex XmlnsRegex = new Regex("xmlns:(\\w+)=\"clr-namespace:(.+)\""); // xmlns:designerui="clr-namespace:Assets.UI.Views.DesignerUI"
    private static readonly Regex XamlCodeBehindRegex = new Regex("x:Class=\"(.+)\""); // x:Class="Assets.UI.Views.DesignerUI.CircleButton"

    private void SaveFile() {
        var file = GetCsFileName();
        var csText = GetCsText();

        if (csText == null) {
            if (File.Exists(file))
                File.Delete(file);
            return;
        }

        if (AssetDatabase.LoadAssetAtPath<TextAsset>(file) != null) {
            var oldFile = File.ReadAllText(file);
            if (oldFile == csText)
                return;
        }

        File.WriteAllText(file, csText);
        AssetDatabase.ImportAsset(file);
    }

    private string GetCsText() {
        var namespaceString = GetNamespaceString();
        var className = GetClassNameString();
        var inheritsClassName = GetInheritsClassName();
        var includedNamespaces = GetXamlIncludedNamespaces().ToArray();
        var elements = GetNamedElements()
            .Select(p=>new XamlElement {
                Name = p.Name,
                Type = ReplaceXamlNamespace(p.Type, includedNamespaces)
            })
            .ToArray();

        if (namespaceString == null || className == null)
            return null;

        var hasNamedElements = elements.Any();

        var stringBuilder = new System.Text.StringBuilder();
        stringBuilder.AppendLine("using Noesis;");
        stringBuilder.AppendLine();
        stringBuilder.Append("namespace ").Append(namespaceString).AppendLine(" {");
        stringBuilder.Append("\tpublic partial class ").Append(className).Append(" : ").Append(inheritsClassName).AppendLine(" {");

        if(hasNamedElements)
            stringBuilder.AppendLine();
        foreach (var item in elements)
            stringBuilder
                .Append("\t\tpublic ")
                .Append(item.Type)
                .Append(" ")
                .Append(item.Name)
                .AppendLine(";");

        stringBuilder.AppendLine();
        stringBuilder.AppendLine("\t\tprivate void InitializeComponent() {");
        stringBuilder.Append("\t\t\tGUI.LoadComponent(this, \"").Append(XamlAsset.source).AppendLine("\");");

        if(hasNamedElements)
            stringBuilder.AppendLine();
        foreach (var item in elements) {
            stringBuilder
                .Append("\t\t\tthis.")
                .Append(item.Name)
                .Append(" = (")
                .Append(item.Type)
                .Append(")FindName(\"")
                .Append(item.Name)
                .AppendLine("\");");
        }

        stringBuilder.AppendLine("\t\t}");
        stringBuilder.AppendLine();
        stringBuilder.AppendLine("\t}");
        stringBuilder.AppendLine("}");

        return stringBuilder.ToString();
    }

    private string GetNamespaceString() {
        var codeBehindClassMatch = XamlCodeBehindRegex.Match(XamlText);
        if (codeBehindClassMatch == null)
            return null;
        var namespaceString = codeBehindClassMatch.Groups[1].Value;
        var lastIndex = namespaceString.LastIndexOf('.');
        namespaceString = namespaceString.Substring(0, lastIndex);
        return namespaceString;
    }

    private string GetClassNameString() {
        var codeBehindClassMatch = XamlCodeBehindRegex.Match(XamlText);
        if (codeBehindClassMatch == null)
            return null;
        var namespaceString = codeBehindClassMatch.Groups[1].Value;
        var lastIndex = namespaceString.LastIndexOf('.');
        var className = namespaceString.Substring(lastIndex + 1);
        namespaceString = namespaceString.Substring(0, lastIndex);
        return className;
    }

    private string GetInheritsClassName() {
        var inheritsClassName = "";
        var startIndex = 0;
        while (XamlText[startIndex] != '<')
            startIndex++;
        startIndex += 1;
        for (var i = startIndex; XamlText[i] != ' ' && XamlText[i] != '\r' && XamlText[i] != '\n'; i++)
            inheritsClassName += XamlText[i];

        return inheritsClassName;
    }

    private struct XamlElement {
        public string Type { get; set; }
        public string Name { get; set; }
    }

    private IEnumerable<XamlElement> GetNamedElements() {
        var elements = new List<XamlElement>();
        var matches = NameRegex.Matches(XamlText);
        foreach (Match match in matches) {
            // backwards search for owner element start
            var elementStartIndex = -1;
            for (var i = match.Index; XamlText[i] != '<'; i--)
                elementStartIndex = i;

            // forward search for owner element start
            var xamlTypeName = "";
            for (var i = elementStartIndex; XamlText[i] != ' '; i++)
                xamlTypeName += XamlText[i];

            var name = match.Groups[1].Value;
            yield return new XamlElement {
                Type = xamlTypeName,
                Name = name
            };
        }
    }

    private struct XamlNamespaceInclusion {
        public string XamlName { get; set; }
        public string ClrNamespace { get; set; }
    }

    private IEnumerable<XamlNamespaceInclusion> GetXamlIncludedNamespaces() {
        var matches = XmlnsRegex.Matches(XamlText);
        foreach (Match match in matches)
            yield return new XamlNamespaceInclusion {
                XamlName = match.Groups[1].Value,
                ClrNamespace = match.Groups[2].Value
            };
    }

    private string ReplaceXamlNamespace(string xamlElementType, IEnumerable<XamlNamespaceInclusion> includedNamespaces) {
        foreach (var ns in includedNamespaces) {
            var before = xamlElementType;
            xamlElementType = xamlElementType.Replace(ns.XamlName + ":", ns.ClrNamespace + ".");
            if (xamlElementType != before)
                break;
        }
        return xamlElementType;
    }

    private string GetCsFileName() {
        return XamlAsset.source.Replace(".xaml", ".g.cs");
    }
}
About the OpacityMask, update didn't fix it. But i did my due diligence https://www.noesisengine.com/bugs/view.php?id=1462
 
User avatar
sfernandez
Site Admin
Posts: 2991
Joined: 22 Dec 2011, 19:20

Re: Unity3D autogenerate .g.cs

08 May 2019, 19:58

Thanks for the report, we were able to reproduce the problem and fix it for the next release.
 
User avatar
CyberFox
Topic Author
Posts: 6
Joined: 06 May 2019, 10:41

Re: Unity3D autogenerate .g.cs

19 Jun 2019, 11:43

Hello I'm back again with an update to the generator. This may be the final version as i don't see any more functions needed.

Here's a demo:
/* This file has been generated automatically. All user changes will be overwritten if the XAML is changed. */
using Noesis;

namespace UserControls {
	[UnityEngine.HideInInspector]
	public partial class MainWindow : UserControl {

		public SolidColorBrush BgColor;
		public UserControls.NumericUpDown BgR;
		public UserControls.NumericUpDown BgG;
		public UserControls.NumericUpDown BgB;
		public SolidColorBrush FgColor;
		public UserControls.NumericUpDown FgR;
		public UserControls.NumericUpDown FgG;
		public UserControls.NumericUpDown FgB;

		private void InitializeComponent() {
			GUI.LoadComponent(this, "Assets/UI/Test/NoesisNumericUpDown/MainWindow.xaml");

			this.BgColor = (SolidColorBrush)FindName("BgColor");
			this.BgR = (UserControls.NumericUpDown)FindName("BgR");
			this.BgG = (UserControls.NumericUpDown)FindName("BgG");
			this.BgB = (UserControls.NumericUpDown)FindName("BgB");
			this.FgColor = (SolidColorBrush)FindName("FgColor");
			this.FgR = (UserControls.NumericUpDown)FindName("FgR");
			this.FgG = (UserControls.NumericUpDown)FindName("FgG");
			this.FgB = (UserControls.NumericUpDown)FindName("FgB");
		}

		protected override bool ConnectEvent(object s, string e, string h) {
			if(s is UserControls.NumericUpDown && e=="ValueChanged" && h=="BgR_ValueChanged") {
				((UserControls.NumericUpDown)s).ValueChanged+=BgR_ValueChanged;
				return true;
			}
			if(s is UserControls.NumericUpDown && e=="ValueChanged" && h=="BgG_ValueChanged") {
				((UserControls.NumericUpDown)s).ValueChanged+=BgG_ValueChanged;
				return true;
			}
			if(s is UserControls.NumericUpDown && e=="ValueChanged" && h=="BgB_ValueChanged") {
				((UserControls.NumericUpDown)s).ValueChanged+=BgB_ValueChanged;
				return true;
			}
			if(s is UserControls.NumericUpDown && e=="ValueChanged" && h=="FgR_ValueChanged") {
				((UserControls.NumericUpDown)s).ValueChanged+=FgR_ValueChanged;
				return true;
			}
			if(s is UserControls.NumericUpDown && e=="ValueChanged" && h=="FgG_ValueChanged") {
				((UserControls.NumericUpDown)s).ValueChanged+=FgG_ValueChanged;
				return true;
			}
			if(s is UserControls.NumericUpDown && e=="ValueChanged" && h=="FgB_ValueChanged") {
				((UserControls.NumericUpDown)s).ValueChanged+=FgB_ValueChanged;
				return true;
			}
			return false;
		}
	}
}
I had it parse one of the sample projects you can compare with the original code here:
https://github.com/Noesis/Tutorials/blo ... ow.xaml.cs

Changes
  • Bugfixes obviously
  • Event connectors, via reflection.
  • If there already is an existing implementation of "InitializeComponent" in the class defined in the XAML the generation is skipped entirely. This is also via reflection.
You may notice the strange attribute in the beginning. "[UnityEngine.HideInInspector]". This is a dummy attribute, it has no function in the program i only use it to differentiate the generated implementations vs the user implementations. It would be better to use a custom attribute, but i didn't wanna add more files. And it also doesn't have any function when put on classes anyway.

Here is the final code:
using System.IO;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Text.RegularExpressions;
using System.Linq;
using System;
using System.Xml;

public class NoesisCsBindingsGenerator {
    public class NoesisGeneratedAttribute :Attribute { }
    public static void GenerateCsFile(string filename) {
        var generator = new NoesisCsBindingsGenerator();
        generator.XamlAsset = AssetDatabase.LoadAssetAtPath<NoesisXaml>(filename.Replace(".xaml", ".asset"));
        generator.XamlText = File.ReadAllText(filename);
        generator.SaveFile();
    }

    public NoesisXaml XamlAsset { get; set; }
    public string XamlText { get; set; }

    private static readonly Regex NameRegex = new Regex("x:Name=\"([\\w\\d_]+)\""); // x:Name="MyElementNameHere"
    private static readonly Regex XmlnsRegex = new Regex("xmlns:([\\w\\d_]+)=\"clr-namespace:([^;\"]+)(?:;.*)?\""); // xmlns:designerui="clr-namespace:Assets.UI.Views.DesignerUI"
    private static readonly Regex XamlCodeBehindRegex = new Regex("x:Class=\"(.+)\""); // x:Class="Assets.UI.Views.DesignerUI.CircleButton"
    private const string DummyAttribute = "[UnityEngine.HideInInspector]";

    private void SaveFile() {
        if (HasExistingUserImplemention())
            return;
        var file = GetCsFileName();
        var csText = GetCsText();

        if (csText == null) {
            if (File.Exists(file))
                File.Delete(file);
            return;
        }

        if (AssetDatabase.LoadAssetAtPath<TextAsset>(file) != null) {
            var oldFile = File.ReadAllText(file);
            if (oldFile == csText)
                return;
        }

        File.WriteAllText(file, csText);
        AssetDatabase.ImportAsset(file);
    }

    private string GetCsText() {
        var namespaceString = GetNamespaceString();
        var className = GetClassNameString();
        var inheritsClassName = GetBaseClassName();
        var includedNamespaces = GetXamlIncludedNamespaces().ToArray();
        var events = GetEvents().ToArray();
        var elements = GetNamedElements()
            .Select(p=>new XamlElement {
                Name = p.Name,
                Type = ReplaceXamlNamespace(p.Type, includedNamespaces)
            })
            .ToArray();

        var hasNamedElements = elements.Any();
        var hasEvents = events.Any();
        var hasCodeBehind = className != null && namespaceString != null;

        if (hasNamedElements == false && hasEvents == false && hasCodeBehind == false)
            return null;

        var stringBuilder = new System.Text.StringBuilder();
        stringBuilder.AppendLine("/* This file has been generated automatically. All user changes will be overwritten if the XAML is changed. */");
        stringBuilder.AppendLine("using Noesis;");
        stringBuilder.AppendLine();
        stringBuilder.Append("namespace ").Append(namespaceString).AppendLine(" {");
        stringBuilder.AppendLine("\t" + DummyAttribute);
        stringBuilder.Append("\tpublic partial class ").Append(className).Append(" : ").Append(inheritsClassName).AppendLine(" {");

        {
            if (hasNamedElements)
                stringBuilder.AppendLine();
            foreach (var item in elements)
                stringBuilder
                    .Append("\t\tpublic ")
                    .Append(item.Type)
                    .Append(" ")
                    .Append(item.Name)
                    .AppendLine(";");

            stringBuilder.AppendLine();
            stringBuilder.AppendLine("\t\tprivate void InitializeComponent() {");
            stringBuilder.Append("\t\t\tGUI.LoadComponent(this, \"").Append(XamlAsset.source).AppendLine("\");");

            if(hasNamedElements)
                stringBuilder.AppendLine();
            foreach (var item in elements) {
                stringBuilder
                    .Append("\t\t\tthis.")
                    .Append(item.Name)
                    .Append(" = (")
                    .Append(item.Type)
                    .Append(")FindName(\"")
                    .Append(item.Name)
                    .AppendLine("\");");
            }

            stringBuilder.AppendLine("\t\t}");
        }

        if (hasEvents) {
            stringBuilder.AppendLine();
            stringBuilder.AppendLine("\t\tprotected override bool ConnectEvent(object s, string e, string h) {");
            foreach (var evt in GetEvents()) {
                stringBuilder
                    .Append("\t\t\tif(s is ")
                    .Append(evt.Type)
                    .Append(" && e==\"")
                    .Append(evt.EventName)
                    .Append("\" && h==\"")
                    .Append(evt.HandlerName)
                    .AppendLine("\") {");

                stringBuilder
                    .Append("\t\t\t\t((")
                    .Append(evt.Type)
                    .Append(")s).")
                    .Append(evt.EventName)
                    .Append("+=")
                    .Append(evt.HandlerName)
                    .AppendLine(";");

                stringBuilder.AppendLine("\t\t\t\treturn true;");
                stringBuilder.AppendLine("\t\t\t}");
            }
            stringBuilder.AppendLine("\t\t\treturn false;");
            stringBuilder.AppendLine("\t\t}");
        }

        stringBuilder.AppendLine("\t}");
        stringBuilder.AppendLine("}");

        return stringBuilder.ToString();
    }

    // check if the class already exists and implements the InitializeComponent() and is not a generated class
    private bool HasExistingUserImplemention() {
        var type = GetType(GetNamespaceString() + "." + GetClassNameString());
        var initializeComponentMethod = type.GetMethod("InitializeComponent", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        var dummyAttributes = type.GetCustomAttributes(typeof(HideInInspector), true);
        return initializeComponentMethod != null && dummyAttributes.Any() == false;
    }

    // gets string for the namespace without the class name
    private string GetNamespaceString() {
        var codeBehindClassMatch = XamlCodeBehindRegex.Match(XamlText);
        if (codeBehindClassMatch.Success == false)
            return null;
        var namespaceString = codeBehindClassMatch.Groups[1].Value;
        var lastIndex = namespaceString.LastIndexOf('.');
        namespaceString = namespaceString.Substring(0, lastIndex);
        return namespaceString;
    }

    // get string for class name without the namespace
    private string GetClassNameString() {
        var codeBehindClassMatch = XamlCodeBehindRegex.Match(XamlText);
        if (codeBehindClassMatch.Success == false)
            return null;
        var namespaceString = codeBehindClassMatch.Groups[1].Value;
        var lastIndex = namespaceString.LastIndexOf('.');
        var className = namespaceString.Substring(lastIndex + 1);
        namespaceString = namespaceString.Substring(0, lastIndex);
        return className;
    }

    private string GetBaseClassName() {
        var inheritsClassName = "";
        var startIndex = 0;
        while (XamlText[startIndex] != '<')
            startIndex++;
        startIndex += 1;
        for (var i = startIndex; XamlText[i] != ' ' && XamlText[i] != '\r' && XamlText[i] != '\n'; i++)
            inheritsClassName += XamlText[i];

        return inheritsClassName;
    }

    private struct XamlElement {
        public string Type { get; set; }
        public string Name { get; set; }
    }

    // enumerate x:Name="" definitions
    private IEnumerable<XamlElement> GetNamedElements() {
        var elements = new List<XamlElement>();
        var matches = NameRegex.Matches(XamlText);
        foreach (Match match in matches) {
            // backwards search for owner element start
            var elementStartIndex = -1;
            for (var i = match.Index; XamlText[i] != '<'; i--)
                elementStartIndex = i;

            // forward search for owner element start
            var xamlTypeName = "";
            for (var i = elementStartIndex; XamlText[i] != ' ' && XamlText[i] != '\r' && XamlText[i] != '\n'; i++)
                xamlTypeName += XamlText[i];

            var name = match.Groups[1].Value;
            yield return new XamlElement {
                Type = xamlTypeName,
                Name = name
            };
        }
    }

    private struct XamlNamespaceInclusion {
        public string XamlName { get; set; }
        public string ClrNamespace { get; set; }
    }

    // enumerate xmlns:local="" definitions
    private IEnumerable<XamlNamespaceInclusion> GetXamlIncludedNamespaces() {
        var matches = XmlnsRegex.Matches(XamlText);
        foreach (Match match in matches)
            yield return new XamlNamespaceInclusion {
                XamlName = match.Groups[1].Value,
                ClrNamespace = match.Groups[2].Value
            };
    }

    // replace strings "local:MyCircle" with "MyApp.CustomControls.MyCircle"
    private string ReplaceXamlNamespace(string xamlElementType, IEnumerable<XamlNamespaceInclusion> includedNamespaces) {
        foreach (var ns in includedNamespaces) {
            var before = xamlElementType;
            xamlElementType = xamlElementType.Replace(ns.XamlName + ":", ns.ClrNamespace + ".");
            if (xamlElementType != before)
                break;
        }
        return xamlElementType;
    }

    private string GetCsFileName() {
        return XamlAsset.source.Replace(".xaml", ".g.cs");
    }

    private struct EventConnection {
        public string EventName { get; set; }
        public string HandlerName { get; set; }
        public string Type { get; set; }
    }

    private IEnumerable<EventConnection> GetEvents() {
        var xmlDoc = new XmlDocument();
        xmlDoc.LoadXml(XamlText);

        var includedNamespaces = GetXamlIncludedNamespaces().ToArray();

        foreach (var node in XmlRecursion(xmlDoc).Skip(1)) { // first element is always #document, skip it
            // prevent handling of nested property tags <Grid><Grid.Resources /></Grid>
            if (node.Name.StartsWith(node.ParentNode.Name) && node.Name != node.ParentNode.Name)
                continue;

            if (node.Name.StartsWith("x:"))
                continue;

            var typename = ReplaceXamlNamespace(node.Name, includedNamespaces);
            Type type;
            if(typename == node.Name)
                type = GetType("Noesis."+typename);
            else
                type = GetType(typename);

            if (node.Attributes == null)
                continue;

            foreach (XmlAttribute attribute in node.Attributes) {
                var evt = type.GetEvent(attribute.Name);
                if (evt == null)
                    continue;
                yield return new EventConnection {
                    EventName = attribute.Name,
                    HandlerName = attribute.Value,
                    Type = typename
                };
            }
        }

        yield break;
    }

    private IEnumerable<XmlNode> XmlRecursion(XmlNode node) {
        yield return node;
        var children = node.ChildNodes;
        foreach (XmlNode child in node.ChildNodes) {
            foreach (var child2 in XmlRecursion(child)){
                yield return child2;
            }
        }
    }

    // https://stackoverflow.com/a/11811046
    public static Type GetType(string typeName) {
        var type = Type.GetType(typeName);
        if (type != null) return type;
        foreach (var a in AppDomain.CurrentDomain.GetAssemblies()) {
            type = a.GetType(typeName);
            if (type != null)
                return type;
        }
        return null;
    }

}
Installation:
In NoesisPostprocessor.cs find a method called ScanDependencies() in the bottom of the method body paste this code: "NoesisCsBindingsGenerator.GenerateCsFile(filename);" and you're good to go.


And again. There is no license on the code. Take it, use it, claim it as your own. I don't care. It's yours now.
 
User avatar
sfernandez
Site Admin
Posts: 2991
Joined: 22 Dec 2011, 19:20

Re: Unity3D autogenerate .g.cs

19 Jun 2019, 19:42

Thanks again for sharing this!
 
User avatar
jsantos
Site Admin
Posts: 3917
Joined: 20 Jan 2012, 17:18
Contact:

Re: Unity3D autogenerate .g.cs

20 Jun 2019, 11:22

This is awesome! Thanks for sharing. We are going to support this soon or later. Problem is we need to find a way to support C#, C++ and Unity at the same time so we will probably follow the route of creating a Visual Studio plugin.
 
User avatar
horeaper
Posts: 34
Joined: 22 Sep 2014, 12:50

Re: Unity3D autogenerate .g.cs

24 Jun 2019, 08:37

A small problem:
In method "HasExistingUserImplemention()", the "type" returned by GetType() can be null, I made a small modification:
bool HasExistingUserImplemention()
{
	var type = GetType(GetNamespaceString() + "." + GetClassNameString());
	var initializeComponentMethod = type?.GetMethod("InitializeComponent", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
	var dummyAttributes = type?.GetCustomAttributes(typeof(HideInInspector), true);
	return initializeComponentMethod != null && dummyAttributes.Any() == false;
}
And it works like a charm!

Who is online

Users browsing this forum: Ahrefs [Bot], DHSven, Semrush [Bot] and 2 guests