Dienstag, 25. Juni 2013

Enable Debugging on my Nexus 7 (Android 4.2.2)

Tried to run one of my apps on my Nexus 7. Actually I found out that I never before used my Nexus 7 to test/debug any of my apps.. After searching about 10 minutes for the "Allow USB-Debugging"-Option I started asking google for it..

Found the solution quite fast, here we go:
1. Go to Apps > Settings 
2. Go to About Tablet (or About Phone)
3. Tap "Build number" 7 times
4. Profit (you will now have a menu in Settings called Developer options).

Thanks to the guy from here:
http://www.monkeycoder.co.nz/Community/posts.php?topic=4009

Seriously.. couldn't that be done a little bit more intuitive? XD

Mittwoch, 1. Mai 2013

Using resx-files for localization in MvvmCross

With the release of Xamarin.Android 4.6.3 there was a small not in the release notes saying:
5037: Support satellite assemblies. 
This is actually awesome. (At least I think so XD). Up to now we had to use the json-localization-plugin included in MvvmCross. As I do not like to edit json and I guess any translator does not like it as well, I prefer the resx-stuff. 

In this blog-post I do want to describe how to use resx-Files all around your Xamarin.Android/Xamarin.iOS and Windows Phone 8 Solution (do not target WinRT and WPF, but they should actually be a nobrainer as they use resx by default :-)).

First of all, the fix mentioned before did not really fix the satellite assemblies-problem. You have to fix an additonal file by yourself. So start with this:
Filename: Xamarin.Android.Common.targets

At this point, thanks to Jonathan Pryor  for the awesome support on this!

This fixed, we can start by creating all the resx-stuff we need :-)

Additional Note:  I'm working in a solution already containing an android/touch/WP8 project. All of them ar up and running using the latest NuGet-Stuff provided by Stuart :-)

Step 1: Create PCL-Project for the resources
First I called this projects Test.Resources. Never do that unless you do not want to support Windows Phone.. ! Read why here:

This is why I renamed this project to Test.Localization :-)

Add a reference from each project where you need the localization to this new pcl-project.

Step 2: Create Resources Files
Add a single resources-file. I called it "Strings.resx". Add a second Resource-File called "Strings.de-DE.resx"

Make sure your first resources-file has the visibility-modifier set to public. Otherwise we will not be able to see the resources from any other assembly. All the additional translations do not need to generate the code. This means you can set them to "No code generation"




Step 3: Add a new class "ResxTextProvider" to your Core-Project.

using System.Diagnostics;
using System.Globalization;
using System.Resources;
using System.Threading;
using Cirrious.MvvmCross.Localization;
 
namespace Test.Core
{
    public class ResxTextProvider : IMvxTextProvider
    {
        private readonly ResourceManager _resourceManager;
 
        public ResxTextProvider(ResourceManager resourceManager)
        {
            _resourceManager = resourceManager;
            CurrentLanguage = Thread.CurrentThread.CurrentUICulture;
        }
 
        public CultureInfo CurrentLanguage { get; set; }
 
        public string GetText(string namespaceKey, string typeKey, string name)
        {
            string resolvedKey = name;
 
            if (!string.IsNullOrEmpty(typeKey))
            {
                resolvedKey = string.Format("{0}.{1}", typeKey, resolvedKey);
            }
 
            if (!string.IsNullOrEmpty(namespaceKey))
            {
                resolvedKey = string.Format("{0}.{1}", namespaceKey, resolvedKey);
            }
 
            return _resourceManager.GetString(resolvedKey, CurrentLanguage);
        }
 
        public string GetText(string namespaceKey, string typeKey, string name, params object[] formatArgs)
        {
            string baseText = GetText(namespaceKey, typeKey, name);
 
            if (string.IsNullOrEmpty(baseText))
            {
                return baseText;
            }
 
            return string.Format(baseText, formatArgs);
        }
    }
}

Step 4: Initialize your ResxTextProvider in your App-Class:

public class App : MvxApplication
{
    public override void Initialize()
    {
        CreatableTypes()
            .EndingWith("Service")
            .AsInterfaces()
            .RegisterAsLazySingleton();
 
        Mvx.RegisterSingleton(new ResxTextProvider(Strings.ResourceManager));
 
        RegisterAppStart();
    }
}

Here is the point where we pass the ResourceManager from our generated String-class to the ResxTextProvider.

Step 5: Extend your ViewModel with a TextSource:

public IMvxLanguageBinder TextSource
{
    get { return new MvxLanguageBinder("", GetType().Name); }
}

In this example I do not pass a Namespace to the MvxLanguageBinder. This means that the GetText-Method of our ResxTextProvider is always called with an empty first parameter. The second parameter will be the current Type. As we are in the MainViewModel, this well be "MainViewModel". 

Step 6: Register Language Converter
protected override void FillValueConverters(IMvxValueConverterRegistry registry)
{
    base.FillValueConverters(registry);
    registry.AddOrOverwrite("Language", new MvxLanguageConverter());
}
Add this line in your Setup.cs in your android app. Not sure whether this could be improved by the MvvmCross-Framework. I think it should *hint* *hint* :-)

Step 7: Start using MvxBind in your android XML-Code.
<TextView
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      android:textSize="40dp"
      local:MvxLang="Text test1" />
Android should now work fine, let's move to iOS:
Her is not that much to do. Simply use the MvxLanguageConverter to bind the TextSource to the Label (or whatever) and set the resx-key as CommandParameter.
You know an easier way? Leave a comment :-)
var bindingSet = this.CreateBindingSet();
    bindingSet.Bind(Label1).To(ViewModel => ViewModel.TextSource)
           .WithConversion(new MvxLanguageConverter(),"test1")
     .Apply();
 
   bindingSet.Bind(Label2).To(ViewModel => ViewModel.TextSource)
    .WithConversion(new MvxLanguageConverter(),"test2")
     .Apply();

What has to be said, when building the generated resx-stuff on Mac it fails as it can not find any of this annotation. Simply delete all of them, we do not really need them :-)

All that done, move ahead to Windows Phone. 
As resx-files is the common idea of doing the localization in WindowsPhone, I do not want to explain much on this. Just give a short compressed version of this great tutorial:

Steps on Windows Phone:


  1.  Add ressources to App.xaml (you could also add this to any other xaml file.. but when adding here we do have access to the localized stuff from every screen...)
  2. Make sure your app does support all the cultures you have translations for (right click project -> properties)
  3. Use the resoruces with a binding and StaticResource:
<TextBlock Text="{Binding Path=Strings.MainViewModel_test1, Source={StaticResource Strings}}" />



All my code is available on GitHub:

Hope I did not miss anything, in case of a not working or any improvement, please leave a comment :-)






Freitag, 19. April 2013

Binding a ViewModel to a simple UITableView using MvvmCross


In this blog entry I will describe how to show a simply UITableView which is bound to a list of custom objects.

I've started a while ago writing my first TableView. I used the CustomerManagement-Sample as kind of a template. This can be found here:

As I had not that much of an idea how it really works, I just implemented the same classes as which they are available in the sample:
  • A custom TableSource-class
  • A custom Cell-class
This actually did not really work, I've ended up writing a question on Stackoverflow:

With the answer from Stuart and some additional hints he gave me in the chat I knew, that I may have to read  and watch some additional stuff. 
So for everyone starting with cells in MvvmCross, take an hour and watch the following video:

This should give you a greate overview on how to create/bind and use custom cells.

But what is the easy way to go?
As I just want to bind a single text to the list there must be a simpler solution for this.Stuart already mentioned this solution in his stackoverflow post. It is implemented in the following sample:

It is really easy:
Here the implementation of my controller which is all I had to do: (no custom TableSource/cell/xibs.. whatever :-))
[MvxViewFor(typeof(MainViewModel))]
  public partial class TestViewController : MvxViewController
 {
  public TestViewController () : base ("TestViewController", null)
  {
  }
  
  public override void ViewDidLoad ()
  {
   base.ViewDidLoad ();
 
         var source = new MvxStandardTableViewSource(UiTableViewOutlet, "TitleText Name;");
 
   this.AddBindings(new Dictionary()
                    {
    {source, "ItemsSource MyList;"}
   });
   
   UiTableViewOutlet.Source = source;
   UiTableViewOutlet.ReloadData();
  }
 }

As you can see, you can use the MvxStandardTableViewSource. This class we have to support with a reference to our UITableView-Outlet and the binding-description. This binding-description is executed on every item in the list we bound to ItemSource in the lines 14 to 16.

Make sure you set the source to the UiTableView and call ReloadData. And that's it!
Thanks to Stuart for the help and write a comment should you have any additional problems with UiTableViews :-)

Montag, 1. April 2013

Bindings in MvvmCross V3 Touch

Stuart has done some significant improvements in V3.
This also means, that the syntax for adding the binding-description in a Touch-Project has changed to a fluent syntax:

Here we go:

this.CreateBinding(TextFieldOutlet)                
.For(textField =>   textField.Text)                
.To((MainViewModel vm) => vm.SearchText)                
.Apply();


This is the code we need in the controller to bind our TextField-Outlet to a property called "SearchText" on our ViewModel.

The "For"-part is not needed for every binding as there are several default-bindings included in the MvvmCross-Binding-Framework. For example when you bind to a TextField it uses the "Text"-property by default. Which means we could write the upper code without the "For".

Here are some more default bindings:      

registry.AddOrOverwrite(typeof (UIButton), "TouchUpInside");
registry.AddOrOverwrite(typeof (UIBarButtonItem), "Clicked");
registry.AddOrOverwrite(typeof (UITextField), "Text");
registry.AddOrOverwrite(typeof (UITextView), "Text");
registry.AddOrOverwrite(typeof (UILabel), "Text");
registry.AddOrOverwrite(typeof (MvxCollectionViewSource), "ItemsSource");
registry.AddOrOverwrite(typeof (MvxTableViewSource), "ItemsSource");
registry.AddOrOverwrite(typeof (MvxImageView), "ImageUrl");
registry.AddOrOverwrite(typeof (UIImageView), "Image");
registry.AddOrOverwrite(typeof (UIDatePicker), "Date");
registry.AddOrOverwrite(typeof (UISlider), "Value");
registry.AddOrOverwrite(typeof (UISwitch), "On");
registry.AddOrOverwrite(typeof (IMvxImageHelper), "ImageUrl");
registry.AddOrOverwrite(typeof (MvxImageViewLoader), "ImageUrl");





This for example means, that when you bind anything to a UIButton (normally you will bind an ICommand-instance). It is bound to TouchUpInside as long as you do not specify anything different using the For-Method.
This Defaults are specified in the following code (as long it is not moved XD)

Samstag, 16. Februar 2013

MvvmCross - how to include external library (like RESTSharp)

There are multiple possibilities to include an external library in your MvvmCross-Project (using vNext build on top of PCLs).

  1. Having a PCL-version of the library you want to include
  2. Inject from a UI Project
  3. Inject from a Plugin
For sure the easiest way to go is the first one. As you do not have to create any additional stuff. Simply add the library to your Core-PCL-Project.

More infos about possibility 2 or 3 can be found here: