Monday, October 16, 2017

Jump start your next project with Xamarin.Forms Caliburn.Micro Starter Kit

Hey all! I’ve bundled my walkthrough of setting up a Xamarin.Forms to use Caliburn.Micro for Android, iOS and UWP into a Visual Studio Project Template and made it available in the Visual Studio Extensions Gallery.

You can download it directly here, or from within Visual Studio: Tools –> Extensions and Updates –> Online.

image

As a multi-project, it’s very straight forward to use, simply choose File –> New and select “Xamarin.Forms with Caliburn.Micro”

image

Will create a project with the following structure:

image

Which, when run (on your platform of choosing) looks like this screenshot below. This is right where we left off from my walk-through earlier this year and is a great starting point for prototyping or building your next app.

image

Known Issues

  • Windows does not automatically create a signing key and identity for your app. Be sure to edit the UWP manifest and associate with your signing identity.

The source code for the starter kit can be found here. Let me know what you think!

submit to reddit

Tuesday, October 10, 2017

Bundle your Visual Studio Solution as a Multi-Project Template

Earlier this year I provided a walkthrough of setting up a Xamarin.Forms project that leveraged Caliburn.Micro for Android, iOS and UWP. I had big plans for extracting the contents of that walkthrough and providing it as a NuGet package. Plans changed however, and I’ve decided to package the entire solution as a Multi-Project Template and provide it as an add-on to Visual Studio (VSIX). This post introduces provides a walk-through on how to create multi-project templates.

Wait, why not NuGet?

First off, as an aside, let’s go back and look what I wanted to do. I wanted to provide a starter-kit of files that would jump start your efforts and allow you to modify my provided files as you see fit. As a NuGet package, I can deliver these files to any project simply by adding these loose code files in the content folder of the NuGet package. Two things that are really awesome about this: the code files can be treated as source code transforms by changing their extension to *.pp, and through platform targeting I could deliver different content files per platform (Xamarin.iOS10, Xamarin.Android10, uap10.0, etc). With this approach, you would simply create a new Xamarin.Forms project then add the NuGet package to all projects. Bam. Easy.

But there are a few problems with this approach:

  • Existing files. My NuGet package would certainly be replacing existing files in your solution. I’d want to overwrite key parts of the initial template (App.xaml, AppDelegate, Activity, etc) and in some cases delete files (MainPage.xaml). Technically, I can overcome these side-effects by modifying the project through a NuGet install script (install.ps1). However, you would be prompted during the install about the replacements and if you clicked ‘No’ when prompted to replace these files… my template wouldn’t work.
  • Delivering Updates. This is the funny thing about this approach -- it is really intended as a one time deal. You would add the starter files to your project and then begin to modify and extend to your hearts’ content. However, as the package author, no doubt I would find an issue or improvement for the package and publish it. If you were to update the package, it would repeat its initialization process and nuke your customizations. I would prefer not to see you when you’re angry.
  • Not guaranteed. Lastly, you could try and add the NuGet package to only one of your projects, or to a library that isn’t intended as a Xamarin.Forms project.

Above all else, the NuGet documentation clearly states that these files should be treated immutable and not intended to be modified by the consuming project. And since the best place to add the package is immediately after you create the project using a Visual Studio Template, why not just make a Template?

Creating a Multi-Project Template

While Multi-Project Templates have been around for a while, their tooling has improved considerably over the last few releases of Visual Studio. Although there isn’t a feature to export an entire solution as a multi-project, they conceptually work the same way as creating a single project template and then tweaking it slightly.

There are two ways to create a Project Template. The first and easiest is simply to select Project –> Export Template. The wizard that appears will prompt you for a Project and places your template in the My Exported Templates folder.

The second approach requires you to install the Visual Studio SDK, which can be found as an option in the initial installer. When you have the SDK installed, you can create a Project Template as an item in your solution. This project includes the necessary vstemplate files and produces the packaged template every time you build.

image

Effectively, a Project Template is just a zip file with a .vstemplate file in it. A Multi-Project Template has a single .vstemplate that points to templates in subfolders. Here’s how I created mine:

1. Create a Project Template project

Using the Visual Studio SDK, I created a Project Template project to my solution and modified the VSTemplate file with the appropriate details:

<VSTemplate Version="2.0.0" Type="ProjectGroup"
    xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
  <TemplateData>
    <Name>Xamarin.Forms with Caliburn.Micro</Name>
    <Description>Xamarin.Forms project with PCL library.</Description>
    <ProjectType>CSharp</ProjectType>
    <Icon>_icon.ico</Icon>
    <DefaultName>App</DefaultName>
    <ProvideDefaultName>true</ProvideDefaultName>
    <CreateNewFolder>true</CreateNewFolder>
    <RequiredFrameworkVersion>2.0</RequiredFrameworkVersion>
    <SortOrder>1000</SortOrder>
    <TemplateID>Your ID HERE</TemplateID>
  </TemplateData>
  <TemplateContent/>
</VSTemplate>


2. Export Projects and Add to the Project Template project

Next, simply export all the projects in your solution that you want to include in your template. The Project –> Export Template dialog looks like this:

image

Once you’ve exported the projects as templates take each of the zip files and extract them into a subfolder of your Template Project. Then, in Visual Studio, include these extracted subfolders as part of the project. Note that Visual Studio will assign a default Action for each file, so code files will be set to Compile, images will be set as EmbeddedResource, etc. You’ll have to go through each of these files and change the default action to Content, copy if newer. It’s a pain, and I found it easier to unload the project and manually edit the csproj file directly.

3. Configure the Template to include the embedded Projects

Now that we have the embedded projects included in the output, we need to modify the template to point to these embedded templates. Visual Studio has a set of reserved keywords that can be used in the vstemplate and code transforms; $safeprojectname$ is a reserved keyword that represents the name of the current project. My vstemplate names the referenced templates after the name that was provided by the user:

<VSTemplate Version="2.0.0" Type="ProjectGroup"
    xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
  <TemplateData>
    ...
  </TemplateData>
  <TemplateContent>
    <ProjectCollection>
      <ProjectTemplateLink ProjectName="$safeprojectname$" CopyParameters="true">XF\MyTemplate.vstemplate</ProjectTemplateLink>
      <ProjectTemplateLink ProjectName="$safeprojectname$.Android" CopyParameters="true">XF.Android\MyTemplate.vstemplate</ProjectTemplateLink>
      <ProjectTemplateLink ProjectName="$safeprojectname$.UWP" CopyParameters="true">XF.UWP\MyTemplate.vstemplate</ProjectTemplateLink>
      <ProjectTemplateLink ProjectName="$safeprojectname$.iOS" CopyParameters="true">XF.iOS\MyTemplate.vstemplate</ProjectTemplateLink>
    </ProjectCollection>
  </TemplateContent>  
</VSTemplate>

If the ProjectName is omitted, it will use the name within the embedded template.

4. Fix Project References

To ensure the project compiles, we must fix the project references to the PCL library in the iOS, Android and UWP projects. Here we leverage an interesting feature of Multi-Project templates – Visual Studio provides special reserved keywords for accessing properties of the root template project. In this case, we can reference the safeprojectname of the root project using the $ext_safeprojectname$ reserved keyword. And because project references use a GUID to refer to the referenced project, we can provide the PCL project with a GUID that will be known to all the child projects – in this case, we can use $ext_guid1$.

The <ProjectGuid> element in the PCL Project must be configured to use the shared GUID:

<PropertyGroup>
  <MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
  <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
  <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
  <ProjectGuid>{$ext_guid1$}</ProjectGuid>
  <OutputType>Library</OutputType>
  <AppDesignerFolder>Properties</AppDesignerFolder>
  <RootNamespace>$safeprojectname$</RootNamespace>
  <AssemblyName>$safeprojectname$</AssemblyName>
  <FileAlignment>512</FileAlignment>
  <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
  <TargetFrameworkProfile>Profile259</TargetFrameworkProfile>
  <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
  <NuGetPackageImportStamp>
  </NuGetPackageImportStamp>
</PropertyGroup>

In the projects that reference the PCL, the path to the project, project GUID and Name must be also be modified:

<ItemGroup>
  <ProjectReference Include="..\$ext_safeprojectname$\$ext_safeprojectname$.csproj">
    <Project>{$ext_guid1$}</Project>
    <Name>$ext_projectname$</Name>
  </ProjectReference>
</ItemGroup>

5. Fix-ups

Lastly, there will be some other fix-ups you will need to apply. These are things like original project names that appear in manifest files, etc. The templating engine can make changes to any type of file, but you may need to verify that these files have the ReplaceParameters attribute set to True in the .vstemplate file.

Build and Deploy!

With this in place, you can simply compile the Project Template and copy the zip to ProjectTemplates folder. Optionally, you can add a VSIX project to the solution that you can use to bundle our Project Template as an installer that you can distribute to users via the Visual Studio Extensions Gallery.

Happy coding!

submit to reddit

Thursday, September 28, 2017

Unit testing Xamarin.Forms Behaviors

So in my last post, I outlined how I’m unit testing my Xamarin.Forms projects. Today, I want to highlight a practical example of unit testing a Behavior.

Let’s take a simple behavior that prevents item selection in a ListView:

public class DisableListViewSelection : Behavior<ListView>
{
    private ListView _attached;

    protected override void OnAttachedTo(ListView bindable)
    {
        _attached = bindable;

        if (_attached != null)
        {
            _attached.ItemSelected += Bindable_ItemSelected;
        }
    }


    protected override void OnDetachingFrom(ListView bindable)
    {
        if (_attached != null)
        {
            _attached.ItemSelected -= Bindable_ItemSelected;
        }
    }

    private void Bindable_ItemSelected(object sender, SelectedItemChangedEventArgs e)
    {
        _attached.SelectedItem = null;
    }
}

Unit testing the behavior should be straight forward but there are a few gotchas.

The first concern is that we're testing a visual that requires Xamarin.Forms to be initialized using Xamarin.Forms.Forms.Init();. This is easily addressed using the Xamarin.Forms.Mocks nuget package I mentioned in my last post.

The second concern is that the Behavior<T> implementation explicitly implements the IAttachedObject interface which is marked as internal. We can address this with some Reflection hackery.

I’ve addressed both concerns with the following base test fixture:

public abstract class BaseBehaviorTests<TSubjectBehavior, TTargetElement> : INotifyPropertyChanged
    where TSubjectBehavior : Behavior<TTargetElement>, new() 
    where TTargetElement : BindableObject, new()
{
    private BindingFlags _bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance;

    public TTargetElement ContainingElement { get; set; }
    public TSubjectBehavior Subject { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;

    public virtual void Setup()
    {
        Xamarin.Forms.Mocks.MockForms.Init();

        Subject = new TSubjectBehavior();
        ContainingElement = new TTargetElement();
    }

    protected virtual void Attach()
    {
        Subject.GetType().GetMethod("Xamarin.Forms.IAttachedObject.AttachTo", _bindingFlags).Invoke(Subject, new object[] { ContainingElement });
    }

    protected virtual void Detach()
    {
        Subject.GetType().GetMethod("Xamarin.Forms.IAttachedObject.DetachFrom", _bindingFlags).Invoke(Subject, new object[] { ContainingElement });
    }

    protected void NotifyPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

Take a quick peek at the Attach/Detach methods. The IAttachedObject.AttachTo method is explicitly implemented on the class so we have to use the full namespace of the method to resolve it. If it was implicitly implemented, we could simply use "AttachTo".

Now that we have this test fixture capability, writing a test for our DisableListViewSelectionBehavior is dead simple:

[TestClass]
public class DisableListViewSelectionBehaviorTests : BaseBehaviorTests<DisableListViewSelection, ListView>
{
    List<object> _list = new List<object>();

    [TestInitialize]
    public override void Setup()
    {
        _list.Add(new object());

        base.Setup();
    }

    [TestMethod]
    public void WhenSelectingItem_AndAttachedToBehavior_ShouldUnselectedItem()
    {
	// arrange
	Attach();
        ContainingElement.ItemsSource = _list;

	// act
        ContainingElement.SelectedItem = _list.First();

	// assert
        ContainingElement.SelectedItem.ShouldBeNull();
    }

    [TestMethod]
    public void WhenSelectingItem_AndDetachedFromBehavior_ShouldKeepSelectedItem()
    {
	// arrange
        Detach();
        ContainingElement.ItemsSource = _list;

	// act
        ContainingElement.SelectedItem = _list.First();

	// assert
        ContainingElement.SelectedItem.ShouldNotBeNull();
    }
}


Well, that's all for now. My next post will look at behaviors with data binding.

Happy coding!

submit to reddit

Wednesday, September 27, 2017

Unit testing Xamarin.Forms

As a TDD Evangelist, I’m well aware of the dichotomy between desired and actual testing practices. It can be hard to write tests when we’re rapid prototyping, and we can convince ourselves that we’re writing testable code, but at some point, you need to establish some testing practices before things scale beyond your reach. This week I’ve been looking at some code where I supported the engineering team but unit testing wasn’t our top priority. I’m glad that I helped shape the code with testability in mind, but now that I’m writing unit tests for the code I’m discovering fallacies in our thinking and areas that are proving difficult to test.

Still, I’ve managed to go from 0% to 50% code coverage in about 10 days which is promising. I’m also hopeful that there’ll be lots more code in testable areas so this number should only trend upward. These last few days I’ve been looking at squeezing out a few extra tests for some of the custom behaviors and I quickly discovered that testing code for visual elements is challenging. Here’s a breakdown of how I’m approaching testing for Xamarin.Forms.

Project Setup

First off, since 90% of my logic resides within the shared PCL layer my focus is on writing unit tests for ViewModels, Services and Behaviors. Some services are platform specific and for those I will likely need to test using Xamarin.iOS or Xamarin.Android, but for the PCL layer I’m using MSTest and .NET 4.6. The choice for using a .NET library instead of Xamarin.iOS or Xamarin.Android is largely for convience and speed of running the tests as they don’t require an emulator or device, and I’m also targetting UWP so I have to compile on a windows machine regardless. I also want to leverage a mocking framework like Moq which won’t work correctly on Mono.

Mocking

For unit testing my ViewModels, I wrote a simple extension to Caliburn.Micro’s dependency container that can automatically fill my viewmodels with fake dependencies.

public class TestContainer : SimpleContainer
{
    public T CreateSubject<T>()
    {
        Type targetType = typeof(T);

        var greedyConstructor = targetType
            .GetConstructors()
            .OrderByDescending(i => i.GetParameters().Length)
            .FirstOrDefault();

        foreach(var arg in greedyConstructor.GetParameters())
        {
            // handle IEnumerable<T> in constructor
            if (typeof(IEnumerable).IsAssignableFrom(arg.ParameterType))
            {
                var genericType = arg.ParameterType.GenericTypeArguments[0];

                // ensure we have at least one item in the array
                if (!HasHandler(genericType, null))
                {
                    CreateAndInsertMock(genericType);
                }
            }
            else
            {
                if (!HasHandler(arg.ParameterType, null))
                {
                    CreateAndInsertMock(arg.ParameterType);
                }
            }
        }

        this.PerRequest<T>();

        return this.GetInstance<T>();
    }
    
    public Mock<T> GetMock<T>() where T : class
    {
        var obj = this.GetInstance<T>();
        if (obj == null)
        {
            throw new InvalidOperationException("Mock is not directly used by the subject.");
        }

        return Mock.Get(obj);
    }

    public Mock<T> GetMock<T>(int index) where T : class
    {
        var instances = this.GetAllInstances<T>();

        return Mock.Get(instances.ToArray()[index]);
    }

    public Mock<T> AddMock<T>(params Type[] interfaces) where T : class
    {
        var mock = new Mock<T>();
        mock.SetupAllProperties();

        if (interfaces.Length > 0)
        {
            var asMethodInfo = mock.GetType().GetMethod("As");
            foreach(var def in interfaces)
            {
                var method = asMethodInfo.MakeGenericMethod(def);
                method.Invoke(mock, null);
            }
        }

        var instance = mock.Object;

        RegisterInstance(typeof(T), null, instance);
        foreach (var def in interfaces)
        {
            RegisterHandler(def, null, container => instance);
        }            

        return mock;
    }        

    private Mock CreateAndInsertMock(Type targetType)
    {
        var method = this.GetType().GetMethod("AddMock").MakeGenericMethod(targetType);
        return (Mock)method.Invoke(this, new object[] { new Type[] { } } );
    }
}

This coupled with a base test fixture really helped to get my viewmodels under the test microscope quickly.

public abstract class BaseViewModelTest<T> where T : BaseScreen
{
    private TestContainer _container;    

    protected T Subject { get; set; }

    public virtual void Setup()
    {
        _container = new TestContainer();
        Subject = _container.CreateSubject<T>();
    }

    protected Mock<TDependency> Get<TDependency>() where TDependency : class
    {
        reutnr _container.GetMock<TDependency>();
    }

    protected Mock<TDependency> Set<TDependency>() where TDependency : class
    {
        return _container.AddMock<TDependency>();
    }

    protected void Activate()
    {
        var activatable = Subject as Caliburn.Micro.IActivate;
        if (activatable != null)
        {
            activatable.Activate();
        }
    }
}

[TestClass]
public class HomeScreenTests : BaseViewModelTest<HomeScreenViewModel>
{
    [TestInitialize]
    public override void Setup()
    {
        base.Setup();

        // additional setup
    }

    // Tests...
}

Testing UI Elements

As I started writing unit tests for controls and behaviors, I realized that any Xamarin.Forms UI element was going to require the Xamarin.Forms.Forms.Init() method to be invoked, which would not work for my test project. Further investigation revealed that most of the plumbing within Xamarin is marked as internal or with the [EditorBrowsable(EditorBrowsableState.Never)] which makes it impossible for us to initialize with mocks …externally. The only way to get at these internals is through the InternalsVisibleTo attribute.

Fortunately, Xamarin MVP Jon Peppers has discovered the same issue and realized a small security flaw in Xamarin’s usage of [InternalsVisibleTo]. Since their usage doesn’t require the use of a public key, anyone can access these internals if they name their assembly a certain way. Jon has published a nuget package that contains Xamarin.Forms.Core.UnitTests.dll assembly. His dummy versions act as a great stand-in for bypassing the platform dependencies allowing us to write tests for simple functionality instead of platform behavior.

My next few posts will cover a few practical examples.

submit to reddit

Monday, September 18, 2017

Extension methods for Caliburn.Micro SimpleContainer

Caliburn.Micro ships with an aptly named basic inversion of control container called SimpleContainer. The container satisfies most scenarios, but I’ve discovered a few minor concerns when registering classes that support more than one interface.

Suppose I have a class that implements two interfaces: IApplicationService and IMetricsProvider:

public class MetricsService : IApplicationService, IMetricsProvider
{
    #region IApplicationService
    public void Initialize()
    {
        // initialize metrics...
    }
    #endregion

    #region IMetricsProvider
    public void IncrementMetric(string metricName)
    {
        // do something with metrics...
    }
    #endregion
}

The IApplicationService is a pattern I usually implement where I want to configure a bunch of background services during application startup, and the IMetricsProvider is a class that will be consumed elsewhere in the system. It's not a perfect example, but it'll do for our conversation...

The SimpleContainer implementation doesn't have a good way of registering this class twice without registering them as separate instances. I really want the same instance to be used for both of these interfaces. Typically, to work around this issue, I might do something like this:

var container = new SimpleContainer();

container.Singleton<IMetricsProvider,MetricsService>();

var metrics = container.GetInstance<IMetricsProvider>();
container.Instance<IApplicationService>(metrics);

This isn't ideal though it will work in trivial examples. Unfortunately, this approach can fail if the class has additional constructor dependencies. In that scenario, the order in which I register and resolve dependencies becomes critical. If you resolve in the wrong order, the container injects null instances.

To work around this issue, here's a simple extension method:

public static class SimpleContainerExtensions
{
    public static SimpleContainerRegistration RegisterSingleton<TImplementation>(this SimpleContainer container, string key = null)
    {
        container.Singleton<TImplementation>(key);
        return new SimpleContainerRegistration(container, typeof(TImplementation), key);
    }
    
    class SimpleContainerRegistration
    {
        private readonly SimpleContainer _container;
        private readonly Type _implementationType;
        private readonly string _key;
    
        public SimpleContainerRegistration(SimpleContainer container, Type type, string key)
        {
            _container = container;
            _implementationType = type;
            _key = key;
        }
    
        public SimpleContainerRegistration AlsoAs<TInterface>()
        {
            container.RegisterHandler(typeof(TInterface), key, container => container.GetInstance(_implementationType, _key));
            return this;
        }
    }
}

This registers the class as a singleton and allows me to chain additional handlers for each required interface. Like so:

var container = new SimpleContainer();

container.RegisterSingleton<MetricsService>()
    .AlsoAs<IApplicationService>()
    .AlsoAs<IMetricsProvider>();

Happy coding!

submit to reddit

Tuesday, September 05, 2017

Dynamically hiding Cells in a TableView

Suppose you have a fixed list of items that you want to display in a Xamarin.Forms TableView, but you want some rows and sections of that table to be hidden. Unfortunately, there isn’t a convenient IsVisible property on the TableSection or Cell elements that we can bind to, and the only way to manipulate them is through code. Here’s a quick look on how to collapse our Cells and Sections using an Attached Property.

Take this example layout:

<ContentPage>

    <Grid>
        <TableView Intent="Settings">
            <TableRoot>
                <TableSection Title="Group 1">
                    <SwitchCell Title="Setting 1" />
                    <SwitchCell Title="Setting 2" />
                </TableSection>
                <TableSection Title="Group 2">
                    <SwitchCell Title="Setting 3" />
                    <SwitchCell Title="Setting 4" />
                </TableSection>
            </TableRoot>
        </TableView>
    </Grid>

</ContentPage>

In the above, I have two TableSection elements that contain two very simple SwitchCell elements. A lot of the detail has been omitted for clarity, but let's assume that I want the ability to only show certain settings to the user. Perhaps each setting is controlled by a special backend entitlement logic, and I want to bind that visibility for each cell through my ViewModel.

We'll create an attached property that can hide our cells:

public class CellEx
{

    public static BindableProperty CollapsedProperty =
        BindableProperty.CreateAttached(
            "Collapsed",
            typeof(bool?),
            typeof(CellEx),
            default(bool?),
            defaultBindingMode: BindingMode.OneWay,
            propertyChanged: OnCollapsedChanged);

    public static bool GetCollapsed(BindableObject target)
    {
        return (bool)target.GetValue(CollapsedProperty);
    }

    public static void SetCollapsed(BindableObject target, bool value)
    {
        target.SetValue(CollapsedProperty, value);
    }

    private static void OnCollapsedChanged(BindableObject sender, object oldValue, object newValue)
    {
        // do work with cell
    }
}

The OnCollapsedChanged event handler is called when the bound value of the BindableProperty is first set and we’ll use it to obtain a reference to the Cell. As the binding is potentially invoked before the UI is fully initialized we’ll need to defer our changes until it’s ready:

private static void OnCollapsedChanged(BindableObject sender, object oldValue, object newValue)
{
    var view = sender as Cell;
    bool isVisible = (bool)newValue;
    if (view != null)
    {
        // the parent isn't available until the page has loaded.
        if (view.Parent == null)
        {
            view.Appearing += (o,e) => 
            {
                ToggleViewCellCollapsedState(view, isVisible);
            };
        }
        else
        {
            ToggleViewCellCollapsedState(view, isVisible);
        }
    }
}

Once we have an initialized Cell, we need to obtain a reference to the containing TableSection. As a twist, the Parent of the Cell is the root TableView, so we must traverse the entire table downward to find the correct TableSection. Since a TableView only contains a fixed list of cells, scanning the entire table shouldn't be too troublesome at all:

private static void ToggleViewCellCollapsedState(Cell cell, bool isVisible)
{
    var table = (TableView)cell.Parent;
    TableSection container = FindContainingTableSection(table, cell);
    if (container != null)
    {
        if (!isVisible)
        {
            // do work to hide cell
        }
    }
}

private static TableSection FindContainingTableSection(TableView table, Cell cell)
{
    foreach(var section in table.Root)
    {
        foreach(var child in section)
        {
            if (child == cell)
            {
                return section;
            }
        }
    }

    return null;
}

Lastly, once we've obtained the necessary references, we can simply manipulate the TableSection contents. To ensure this works on all platforms, this code must execute on the UI thread:

if (!isVisible)
{

    Device.BeginInvokeOnMainThread(() => 
    {
        // remove the cell from the section
        container.Remove(cell);

        // remove the section from the table if it's empty
        if (container.Count == 0)
        {
            table.Root.Remove(container);
        }
    });
}

We can then bind the visibility of our cells to the attached property:

<ContentPage
    xmlns:ex="clr-namespace:MyNamespace.Behaviors"
    >

    <Grid>
        <TableView>
            <TableRoot>
                <TableSection Title="Group 1">
                    <SwitchCell Title="Setting 1" ex:CellEx.Collapsed={Binding IsSetting1Visible}" />
                    <SwitchCell Title="Setting 2" ex:CellEx.Collapsed={Binding IsSetting2Visible}" />
                </TableSection>
                <TableSection Title="Group 2">
                    <SwitchCell Title="Setting 3" ex:CellEx.Collapsed={Binding IsSetting3Visible}" />
                    <SwitchCell Title="Setting 4" ex:CellEx.Collapsed={Binding IsSetting4Visible}" />
                </TableSection>
            </TableRoot>
        </TableView>
    </Grid>

</ContentPage>

This works great and can dynamically hide individual cells or an entire section if needed. The largest caveat to this approach is that it only hides cells and won’t re-introduce them into the view when the binding changes. This is entirely plausible as you could cache the cells in a local variable and re-insert them programmatically, but you’d need to remember the containing section and appropriate indexes. I’d leave that to you dear reader, or I may rise to the challenge if I determine I really want to re-activate these cells in my app.

Happy coding!

submit to reddit

Monday, July 03, 2017

Troubleshooting Xamarin iPhoneSimulator errors from Visual Studio

I’m using the Xamarin Mac BuildAgent to compile my Xamarin.Forms app from Visual Studio and test it using the device simulator on my Mac. This solution was working really well for me until one day, it wasn’t. I could compile and deploy to the Simulator fine, but I was seeing errors at runtime that simply weren’t there on Android or UWP. To make matters worse, my colleagues weren’t seeing this problem when compiling and deploying to an actual device.

The problem started when we added Azure Mobile Services to our project. The errors we were seeing weren’t very helpful at all, either a TypeLoadException or NullReferenceException and they appear when trying to invoke calls that were part of the Mobile Services client. These errors are frustrating because the error detail in Visual Studio provides little guidance as to why these calls aren’t working, especially when the same calls were working before adding the reference.

The forums and usage for Azure Mobile Services recommends that you must invoke CurrentPlatform.Init() to ensure that some of the extended assemblies that are dynamically loaded at runtime are linked into the output during compilation. I’ve seen similar problems before in WPF where the compilation process would optimize away assemblies that contain only DataTemplates and Styles – effectively, if they don’t contain byte-code then the compiler will not list the reference as a dependency.

Unfortunately our team was already using CurrentPlatform.Init() in our code, and since the error was only specific to the iPhoneSimulator it suggested an issue with the Linking used for the Debug_iPhoneSimulator configuration. Although the Linker Behavior is set to Don’t link – which effectively takes all assemblies without attempting to optimize – we added the –linkskip arguments to both the main Azure Mobile Service assembly and its platform equivalent (Microsoft.WindowsAzure.Mobile.Ext).

image

This strangely seemed to resolve the issue, at least partially. We could get further along in our app initialization before the app would hang.

Inspecting the Logs

Often, the errors from Xamarin will recommend checking the logs. There are two logs to check:

  • Xamarin Logs. These logs are found through Visual Studio: Help –> Xamarin –> Open Logs. They show diagnostics for Xamarin within Visual Studio and are especially useful for understanding deployment errors such as connectivity with the Mac BuildAgent.
  • Device Logs. These logs can be found on the Mac. Simulator: Debug –> Open System Log. These logs contain the paydirt of what’s happening with the logs and provides insights into the inner exceptions that don’t bubble up into Visual Studio.

In my case, looking at the Simulator’s Device Log showed the critical missing piece of information. I was missing a reference to a reference. I was missing a reference to System.Net.Http!

Jul 2 13:35:15 Bryans-MacBook-Pro MyAppiOS[24157]: Could not find `System.Net.Http` referenced by assembly `Xamarin.Forms.Platform.iOS, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null`. 
Jul 2 13:35:15 Bryans-MacBook-Pro MyAppiOS[24157]: Could not find `System.Net.Http` referenced by assembly `Microsoft.WindowsAzure.Mobile, Version=1.3.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35`. 
Jul 2 13:35:15 Bryans-MacBook-Pro MyAppiOS[24157]: Could not find `System.Net.Http` referenced by assembly `Xamarin.Auth, Version=1.3.0.0, Culture=neutral, PublicKeyToken=null`. 
Jul 2 13:35:15 Bryans-MacBook-Pro MyAppiOS[24157]: Could not find `System.Net.Http` referenced by assembly `Microsoft.WindowsAzure.Storage, Version=7.1.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35`.

The logs contain .NET StackTraces and Exception details, which provide excellent supporting information for errors that occur in the IDE. And now that the simulator actually works it’ll be used a great deal more often.