Smelly c0de
Saturday, September 9, 2017
Friday, May 5, 2017
Numeric keyboard with "Done" button on iOS Xamarin.Forms
'Done' button on Numeric keyboard on iOS is a very popular clients request, but it does not appear out of the box. Luckily the solution is very easy (as usual), all we have to do is to extend 'Entry' control and to add a custom renderer:
As you can see all the 'magic' is happing in AddDoneButton() method. We create a toolbar and add a 'Done' UIBarButtonItem which will hide the keyboard and send a 'Completed' event back.
Thursday, April 6, 2017
INotifyPropertyChange without boilerplate code in Xamarin.Forms
Implementing INotifyPropertyChange is pretty straightforward. Usually, you create a base ViewModel class which implements it and which usually contains RaisePropertyChanged method:
public abstract class BaseViewModel : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(
[CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
Now you can extend the BaseViewModel and use it this way:
For very small applications it can be a good enough approach, however, in bigger applications it turns into a lot of boring boilerplate code. Here is where NotifyPropertyChanged.Fody comes into play! With this nice package our code will turn into:
public class UserViewModel : BaseViewModel
Easy as it is! I highly recommend to get familiar with the documentation as it contains a lot of useful information about more advanced flows. For example, if you need to RaisePropertyChange for dependent properties or to skip equality comparison.
public abstract class BaseViewModel : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(
[CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
Now you can extend the BaseViewModel and use it this way:
public class UserViewModel : BaseViewModel
{
{
private string login;
public string Login
{
get
{
return login;
}
set
{
if (login == value)
return;
login = value;
RaisePropertyChanged();
}
}
private string password;
public string Password
{
get
{
return password;
}
set
{
if (password == value)
return;
password = value;
RaisePropertyChanged();
}
}
}
[ImplementPropertyChanged]
public abstract class BaseViewModel {}
public class UserViewModel : BaseViewModel
{
public string Login { get; set; }
public string Password { get; set; }
}
Sunday, April 2, 2017
Though about optimisation of work with XAML in Xamarin.Forms
What is great about Xamarin.Forms? XAML of course! Especially if you are familiar with it from WPF / Silverlight times. However, the experience with XAML in Xamarin.Forms is totally different. Unfortunately, you will not have such a great intellisense, by default you will have to discover typos in XAML at runtime, no visual editor (yet) and without preview. I have been using VS 2017 on Windows and VS For Mac on macOS, in both cases problems listed above exists.
There are a lot of threads on stackoverflow about these problems and I am repeating myself, again and again, so I decided to write a post about it. I don't have a magic solution, just a few tricks and a though.
If you are already familiar with XAML and Xamarin.Forms and you don't care that much about intellisence you can turn on XAML compilation to catch the typos at compile time.
You can enable it at the assembly level, by adding the next line of code to your AssemblyInfo.cs:
FYI: If you set the BindingContext inside XAML you may meet this bug.
Remember that all you do in XAML is compiled to code in the end. That means that if the IDE is not working that great with XAML for Xamarin.Forms at this time, you can write everything in plain C#!
Sounds weird, however, all the problems listed above will be solved - except preview. But I find it attractive enough to try. Defining your UI layout in code behind will not violate any of MVVM principles as far as it's not going to include any business logic.
If you know any other tricks please share.
Have a nice week.
There are a lot of threads on stackoverflow about these problems and I am repeating myself, again and again, so I decided to write a post about it. I don't have a magic solution, just a few tricks and a though.
If you are already familiar with XAML and Xamarin.Forms and you don't care that much about intellisence you can turn on XAML compilation to catch the typos at compile time.
You can enable it at the assembly level, by adding the next line of code to your AssemblyInfo.cs:
[assembly: XamlCompilation(XamlCompilationOptions.Compile);
Or turn XAML compilation at the class level, just the next line above class declaration:[XamlCompilation (XamlCompilationOptions.Compile)];
More detailed information can be found here.FYI: If you set the BindingContext inside XAML you may meet this bug.
Remember that all you do in XAML is compiled to code in the end. That means that if the IDE is not working that great with XAML for Xamarin.Forms at this time, you can write everything in plain C#!
Sounds weird, however, all the problems listed above will be solved - except preview. But I find it attractive enough to try. Defining your UI layout in code behind will not violate any of MVVM principles as far as it's not going to include any business logic.
If you know any other tricks please share.
Have a nice week.
Sunday, March 26, 2017
UIDatePicker Countdown mode bug and solution in Xamarin.Forms
Problem
Show hh:mm:ss picker on iOS using Xamarin.Forms.
Goal
Extend Picker view in order to achieve the next result:
Solution
First I tried to keep it simple: to give up on seconds and use UIDatePicker in UIDatePickeCountDownMode. So the end result will look like this:
I achieved it by extending the DatePicker and it's DatePickerRenderer and changing the mode as described above. However, I discovered that 'datePickerValueChanged' is being called only on a second iteration with the values. The issue was successfully reproduced in Swift, so it's not a Xamarin bug. The Swift version can be found here.
After spending some time understanding the issue described above, I found an example on StackOverflow, thanks to Mathieu who shared his solution. His example was based on XLabs, so I removed the dependency and shared it with the community.
The code can be found on GitHub.
Tuesday, March 21, 2017
JSON.net Mastering enums
Problem
Legacy backend API endpoint returns JSON with units in an uncommon manner.Instead of returning the measurement system "imperial" or "metric" it returns "kgs" or "lbs".
Goal
Using JSON.net deserialize & serialize "kgs" to "metric" and "lbs" to "imperial" in our front-end app.Solution
The solution is pretty simple. We have to define an enum, with "EnumMember" attributes on each element and use "StringEnumConverter" as preferred JsonConvertor. Here is the full and working example:using System;
using System.Runtime.Serialization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
namespace JSONnetEnums
{
class Program
{
static void Main(string[] args)
{
var deserializedObj =
JsonConvert.DeserializeObject<Foo>("{\"Unit\":\"kgs\"}");
Console.WriteLine(deserializedObj.Unit);
// Output: Metric
var serializedObj =
JsonConvert.SerializeObject(new Foo { Unit = Unit.Imperial });
Console.WriteLine(serializedObj);
// Output: {"Unit":"lbs"}
}
}
class Foo
{
public Unit Unit { get; set; }
}
[JsonConverter(typeof(StringEnumConverter))]
enum Unit
{
[EnumMember(Value = "kgs")]
Metric,
[EnumMember(Value = "lbs")]
Imperial
}
}
Wednesday, March 15, 2017
Xamarin Forms SQLite-net PCL nuget package failing to install
Following Local Databases Xamarin guide in order to add SQLite database to a Xamarin Forms project I spent quite some time on adding the "SQLite.Net PCL" nuget package. It failed with the next message:
Could not install package 'System.Runtime.InteropServices.RuntimeInformation 4.0.0'. You are trying to install this package into a project that targets '.NETPortable,Version=v4.5,Profile=Profile111', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.
The solution is pretty easy, you just have to install "System.Runtime.InteropServices.RuntimeInformation" before installing "SQLite.Net PCL" nuget package.
More details can be found here.
Could not install package 'System.Runtime.InteropServices.RuntimeInformation 4.0.0'. You are trying to install this package into a project that targets '.NETPortable,Version=v4.5,Profile=Profile111', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.
More details can be found here.
Subscribe to:
Posts (Atom)