Skip to content

Instantly share code, notes, and snippets.

@VincentH-Net
Last active March 21, 2016 18:09
Show Gist options
  • Save VincentH-Net/85e87d364ba196f99b64 to your computer and use it in GitHub Desktop.
Save VincentH-Net/85e87d364ba196f99b64 to your computer and use it in GitHub Desktop.
Xamarin Forms Sketch demonstrating data binding (without strings, to nested objects, to unlimited number of fields) and common app/sketch code. Note: remove the .cs from the file name, it is only there to make GitHub format it as C#
using Xamarin.Forms;
// Additional guidance: see http://vincenth.net/blog/archive/2014/11/27/how-to-share-xamarin-forms-data-binding-code-across-xamarin-sketches-and-apps-without-using-strings.aspx
// NOTE: Once support for creating classes is added to Xamarin Sketches,
// there is no need for this Tuple + enum + BindName + regular expression workaround;
// you can then simply create design data classes in the Sketch and bind to that using
// the same syntax in both projects and sketches, e.g.:
// SetBinding(..., (Person boundPerson) => boundPerson.Name)
// BindName helper function for use with binding to design data in Sketches.
// Usage: SetBinding(..., BindName(SomeEnum.SomeValue))
// Maps an enum property name value to a Tuple ItemX property name.
// Maps 7th and later properties to nested Tuples in Item7.
//
// Use this regular expression to convert SetBinding() code from sketch to project:
// E.g. SetBinding(..., BindName(Person.Name) will become SetBinding(..., (Person boundPerson) => boundPerson.Name
// Search: SetBinding\s*\((?<bindableProperty>[^,]+)\s*,\s*BindName\((?<class>[^\.\)]*)\.(?<property>[^\.\)]*)\)
// Replace: SetBinding(${bindableProperty}, (${class} bound${class}) => bound${class}.${property}
//
// Use this regular expression to convert SetBinding() code from project to sketch:
// E.g. SetBinding(..., (Person boundPerson) => boundPerson.Name will become SetBinding(..., BindName(Person.Name)
// Search: SetBinding\s*\((?<bindableProperty>[^,]+)\s*,\s*\(\s*(?<class>\w*)\s+bound\k<class>\s*\)\s*=>\s*bound\k<class>\.(?<property>\w*)
// Replace: SetBinding(${bindableProperty}, BindName(${class}.${property})
Func<Enum, string> BindName = (Enum propertyName) =>
{
const int MaxTupleItems = 7;
int fieldIndex = int.Parse(propertyName.ToString("D"));
string bindName = "";
while (fieldIndex >= MaxTupleItems)
{
bindName += "Item" + MaxTupleItems.ToString() + ".";
fieldIndex -= (MaxTupleItems - 1);
}
bindName += "Item" + fieldIndex.ToString();
return bindName;
};
// Names of bindable classes with properties as enum names with values for Sketch design data
// Set the first value in each enum to 1 to map to Tuple Item1
// Subsequent items will map to subsequent Tuple fields
// You can overcome the limit of 7 properties in a Tuple by making the 7th property a nested Tuple,
// which can then contain properties 7 through 12. You can keep nesting tuples to add more properties.
enum Name
{
First = 1,
Last
};
enum Person
{
Image = 1,
Name,
Description,
Property4,
Property5,
Property6,
Property7,
Property8,
Property9
};
// Design data for Sketch.
// Each tuple in the list represents a Person class with a nested Name class, which is represented by a nested Tuple.
// Property7..9 are represented by a nested Tuple in Item7, demonstrating how to overcome the limit of 7 properties in a Tuple.
var persons = new List<Tuple<UriImageSource,Tuple<string, string>,string, string, string, string, Tuple<string, string, string>>> {
Tuple.Create(new UriImageSource { Uri = new Uri("http://bit.ly/1s07h2W") }, new Tuple<string, string>("Miguel", "de Icaza"), "CTO and Co-founder", "4", "5", "6", new Tuple<string, string, string>("7", "8", "9th bound property value\nNo strings, just code :-)")),
Tuple.Create(new UriImageSource { Uri = new Uri("http://bit.ly/1rYGvGU") }, new Tuple<string, string>("Nat", "Friedman"), "CEO and Co-founder", "4", "5", "6", new Tuple<string, string, string>("7", "8", "9th bound property value\nUse Class.Property")),
Tuple.Create(new UriImageSource { Uri = new Uri("http://photos1.meetupstatic.com/photos/member/2/4/a/6/member_74169382.jpeg") }, new Tuple<string, string>("Vincent", "Hoogendoorn"), "Developer", "4", "5", "6", new Tuple<string, string, string>("7", "8", "9th bound property value\nCompiler checks name")),
Tuple.Create(new UriImageSource { Uri = new Uri("http://bit.ly/1EhFsao") }, new Tuple<string, string>("Stephanie", "Schatz"), "SVP of Sales and Customer Success", "4", "5", "6", new Tuple<string, string, string>("7", "8", "9th bound property value\nDot notate: Class.Property")),
Tuple.Create(new UriImageSource { Uri = new Uri("http://bit.ly/1oIYpso") }, new Tuple<string, string>("Joanne", ""), "VP of Marketing", "4", "5", "6", new Tuple<string, string, string>("7", "8", "9th bound field value")),
Tuple.Create(new UriImageSource { Uri = new Uri("http://bit.ly/10CbVZE") }, new Tuple<string, string>("Joseph", ""), "Director of Developer Relations and Co-founder", "4", "5", "6", new Tuple<string, string, string>("7", "8", "9th bound field value")),
Tuple.Create(new UriImageSource { Uri = new Uri("http://bit.ly/1vCRbKh ") }, new Tuple<string, string>("Rob", ""), "VP of Business Development", "4", "5", "6", new Tuple<string, string, string>("7", "8", "9th bound property value")),
Tuple.Create(new UriImageSource { Uri = new Uri("http://bit.ly/1rPp1vm") }, new Tuple<string, string>("Bryan", ""), "Vice President of Education Services", "4", "5", "6", new Tuple<string, string, string>("7", "8", "9th bound property value")),
Tuple.Create(new UriImageSource { Uri = new Uri("http://bit.ly/1sXguu1") }, new Tuple<string, string>("Jason", ""), "Team Lead - Xamarin.Forms", "4", "5", "6", new Tuple<string, string, string>("7", "8", "9th bound property value")),
};
var personTemplate = new DataTemplate(() =>
{
// Start of common App/Sketch code fragment #1 *****************************
var image = new Image {
WidthRequest = 100,
HeightRequest = 100
};
image.SetBinding(Image.SourceProperty, BindName(Person.Image));
var firstNameLabel = new Label();
firstNameLabel.SetBinding(Label.BindingContextProperty, BindName(Person.Name));
firstNameLabel.SetBinding(Label.TextProperty, BindName(Name.First));
var lastNameLabel = new Label {
TextColor = Color.Gray
};
lastNameLabel.SetBinding(Label.BindingContextProperty, BindName(Person.Name));
lastNameLabel.SetBinding(Label.TextProperty, BindName(Name.Last));
var titleLabel = new Label();
titleLabel.SetBinding(Label.TextProperty, BindName(Person.Description));
var ninthFieldLabel = new Label {
TextColor = Color.White,
BackgroundColor = Color.Purple
};
ninthFieldLabel.SetBinding(Label.TextProperty, BindName(Person.Property9));
var nameLayout = new StackLayout {
Children = { firstNameLabel, lastNameLabel },
Orientation = StackOrientation.Horizontal
};
var textLayout = new StackLayout {
Children = { nameLayout, titleLabel, ninthFieldLabel }
};
var cellLayout = new StackLayout {
Padding = 10,
Orientation = StackOrientation.Horizontal,
Children = { image, textLayout }
};
// End of common App/Sketch code fragment #1 *******************************
var cell = new ViewCell {
View = cellLayout,
};
return cell;
});
var page = new ContentPage();
// Start of common App/Sketch code fragment #2 *****************************
var searchBar = new SearchBar { Placeholder = "Search ..." };
var listView = new ListView {
ItemTemplate = personTemplate,
ItemsSource = persons,
RowHeight = 110
};
var layout = new StackLayout {
Children = {
searchBar,
listView
}
};
page.Padding = new Thickness(0, 20, 0, 0);
page.Content = layout;
// End of common App/Sketch code fragment #2 *******************************
RootPage.Children.Add(page);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment