Using t4 templates to create c# layout accessor

Hi folks, I'm trying out an idea to simplify access to android layout elements and I just thought I'd share and ask for general feedback on the approach.

I use https://github.com/MartinF/Dynamo.AutoTT with the attached t4 template to create a simple way to create and access android layouts. The code at the bottom of the message may need some de-mangling :-)

Have fun, any feedback is welcome.

Thanks,
Mat.

<# // Copyright Matware 2013 #>

<#@ output extension=".cs" #>

<#@ template language="C#" hostSpecific="true" #>

<#@ assembly name="System.Core" #>

<#@ assembly name="System.Xml" #>

<#@ assembly name="System.Xml.Linq" #>

<#@ import namespace="System.IO" #>

<#@ import namespace="System.Collections.Generic" #>

<#@ import namespace="System.Linq" #>

<#@ import namespace="System.Text" #>

<#@ import namespace="System.Text.RegularExpressions" #>

<#@ import namespace="System.Xml" #>

<#@ import namespace="System.Xml.Linq" #>

<#@ import namespace="System.Xml.XPath" #>

using Android.Widget;
using Android.Views;
using Android.Content;
using Android.Util;
/*********************************************************

  • Auto generated by LayoutToView.TT
  • layout access for mono for android <#WriteLine(DateTime.Now.ToString());#>
    *********************************************************/
    //
    <#
    var projectName = Host.ResolveAssemblyReference("$(ProjectName)");
    WriteLine("namespace "+projectName+".Layout {");

>

<#
var files = Directory.GetFiles(Host.ResolvePath(@..\Resources\Layout\),"*.axml");
foreach(var file in files){
Process(file);
}

>

public static class LayoutFactory {

<#

foreach(var file in files){
    BuildViewFactory(file);
}

>

}

}

<#+

public void BuildViewFactory(string layoutRelativePathPath)
{
    var className = System.IO.Path.GetFileNameWithoutExtension(layoutRelativePathPath);
    WriteLine("\t\tpublic static "+className+ " Inflate"+ className+"(this Context c)");
    WriteLine("\t\t{");
    WriteLine("\t\t\tvar inflater = c.GetSystemService(Context.LayoutInflaterService) as LayoutInflater;");
    WriteLine("\t\t\tvar theView = inflater.Inflate(Resource.Layout."+className+", null);");
    WriteLine("\t\t\tvar result = new "+className+"(theView);");

    WriteLine("\t\t\treturn result;");
    WriteLine("\t\t}");
}

public void Process(string layoutRelativePathPath)
{
    XNamespace nsm = "http://schemas.android.com/apk/res/android";
    XNamespace app = "http://schemas.android.com/apk/res-auto";
    var className = System.IO.Path.GetFileNameWithoutExtension(layoutRelativePathPath);
    WriteLine("\tpublic partial class " + className+"{");
    WriteLine("\t\tpublic Context Context{get;private set;}");
    WriteLine("\t\tprivate readonly View view;");
    WriteLine("\t\tpublic View View{get {return view;}}");
    WriteLine("\t\tpublic " + className+"(View v){view=v;Context = view.Context;}");
    WriteLine("\t\tpublic " + className+"(Context c){");
    WriteLine("\t\t\tContext = c;");
    WriteLine("\t\t\tvar inflater = Context.GetSystemService(Context.LayoutInflaterService) as LayoutInflater;");
    WriteLine("\t\t\tif (inflater != null) view = inflater.Inflate(Resource.Layout."+className+", null);");
    WriteLine("\t\t}");
    XDocument document;

    try
    {
        document = XDocument.Load(layoutRelativePathPath);
    }
    catch (FileNotFoundException)
    {
        WriteLine(" //File not found: " + layoutRelativePathPath);
        return;
    }

    var widgets = new string []{"AnalogClock","AutoCompleteTextView","Button","Checkbox","Chronometer","DatePicker","DigitalClock","EditText","ExpandableListView",
                                "Gallery","GridView","ImageButton","ImageView","ListView","MediaController","ProgressBar","RadioGroup","RadioButton","RatingBar","ScrollView",
                                "SeekBar","Spinner","TabWidget","TextView", "TimePicker","ToggleButton","VideoView","WebView"};

    var layouts = new string []{"AbsoluteLayout","FrameLayout","ImageSwitcher","LinearLayout","RelativeLayout","TableLayout","TableRow","TextSwitcher","ViewAnimator","ViewFlipper","ViewSwitcher"};

    // Find the layout root if it is a basic layout type
    foreach(var root in layouts)
        ProcessRoot(root,document);

    // Find the id'd layouts within the layout
    foreach(var w in layouts)
        ProcessElement(w, document);

    // Find all the basic widgets
    foreach(var w in widgets)
        ProcessElement(w, document);

    WriteLine("\t}");
    WriteLine("");

}

// Find the root layout element for the resource
public void ProcessRoot(string commonRoot, XDocument doc)
{
    if(doc == null || commonRoot== null)
        return;

    IEnumerable<XElement> dataElements = doc.XPathSelectElements("/"+commonRoot);

    // We need to have a way to find the class which maps to the xml namespace of the view... hmmm
    foreach (XElement element in dataElements)
    {
        WriteLine("\t\tpublic "+element.Name+" Root{get {return view as "+element.Name+";}}");
    }
}

Regex r = new Regex(@"\+id/(\w+)", RegexOptions.Compiled);

public void ProcessElement(string elementName, XDocument doc)
{
    if(doc == null || elementName== null)
        return;

    XNamespace nsm = "http://schemas.android.com/apk/res/android";
    XNamespace app = "http://schemas.android.com/apk/res-auto";

    IEnumerable<XElement> dataElements = doc.XPathSelectElements("//"+elementName);
    if(dataElements == null)
        return;

    foreach (XElement element in dataElements)
    {
        var idAttribute = element.Attribute(nsm + "id");

        if(idAttribute == null)
            continue;

        string id = idAttribute.Value;

        var m = r.Match(id);

        if (m.Success)
        {

            var propertyName = m.Groups[1].Value;
            var fieldName = "_" + propertyName;

            WriteLine("\t\tprivate "+elementName +" " + fieldName + " = null;");
            WriteLine("\t\tpublic "+elementName +" "+propertyName +" {");
            WriteLine("\t\t\tget{");
            WriteLine("\t\t\t\treturn "+fieldName+"??("+fieldName + "=view.FindViewById(Resource.Id." + propertyName + ") as " + elementName+");");
            WriteLine("\t\t\t}");
            WriteLine("\t\t}");

        }
    }
}

>

Posts

Sign In or Register to comment.