The Repository Pattern with Xamarin Forms and SQLite
Wednesday, 20 April 2016
The App
The example app is a simple screen which lists the months of the year. It looks like this......and here's the code...
public class HomePage : ContentPage { public HomePage () { // Set up the repository. var sqlProvider = DependencyService.Get <isqlprovider> (); var repo = new SQLRepository (sqlProvider); repo.Init (); // Set up the controller factory and controller. var controllerFactory = new ControllerFactory (repo); var controller = controllerFactory.GetDemoController (); // Set up the list. var listView = new ListView { RowHeight = 40 }; listView.ItemsSource = controller.GetFirstQuarter (); Content = new StackLayout { VerticalOptions = LayoutOptions.FillAndExpand, Children = { listView } }; } }This is simple. We use the DependencyService to get a reference to the SQLite provider (which supplies the platform specific SQLite connection). We initialise the repository. The repository is passed to the controller factory which supplies a controller. Finally we setup the page.
Platform Specific Code
public class SQLite_Android : ISQLProvider { public SQLite_Android () {} public SQLite.SQLiteConnection GetConnection () { var sqliteFilename = "DemoSQLite.db3"; string documentsPath = System.Environment.GetFolderPath (System.Environment.SpecialFolder.Personal); // Documents folder var path = Path.Combine(documentsPath, sqliteFilename); File.Delete (path); // Create the connection var conn = new SQLite.SQLiteConnection(path); // Return the database connection return conn; }}
The Core Project and Dependency Injection
{ private StandardKernel kernel; public ControllerFactory (IRepository repository) { kernel = new StandardKernel (); kernel.Bind<irepository> ().ToConstant (repository); } public DemoController GetDemoController() { return kernel.Get<democontroller> (); } }
public class SQLRepository : IRepository { SQLiteConnection connection; public SQLRepository (ISQLProvider provider) { this.connection = provider.GetConnection(); } public void Init() { this.connection.CreateTable<month> (); this.connection.Insert(new Month(12, "December")); this.connection.Insert(new Month(11, "November")); this.connection.Insert(new Month(10, "October")); this.connection.Insert(new Month(9, "September")); this.connection.Insert(new Month(8, "August")); this.connection.Insert(new Month(7, "July")); this.connection.Insert(new Month(6, "June")); this.connection.Insert(new Month(5, "May")); this.connection.Insert(new Month(4, "April")); this.connection.Insert(new Month(3, "March")); this.connection.Insert(new Month(2, "February")); this.connection.Insert(new Month(1, "January")); } public List<month> GetMonths () { return this.connection.Table<month> ().ToList (); } }...the SQLRepository - This is a simple demo so all the repository does is provide a list of months. Months are set up when the repository initialises.
public class DemoController { private IRepository repo; public DemoController (IRepository repo) { this.repo = repo; } public List<month> GetFirstQuarter() { return this.repo.GetMonths ().Where (x => x.Number <= 3).ToList (); } }
The Unit Test Project
public class DemoController [TestFixture ()] public class Test { [Test ()] public void TestCase () { var repository = new TestRepository (); repository.Months.Add (new Month (12, "December")); repository.Months.Add (new Month (11, "November")); repository.Months.Add (new Month (10, "October")); repository.Months.Add (new Month (9, "September")); repository.Months.Add (new Month (8, "August")); repository.Months.Add (new Month (7, "July")); repository.Months.Add (new Month (6, "June")); repository.Months.Add (new Month (5, "May")); repository.Months.Add (new Month (4, "April")); repository.Months.Add (new Month (3, "March")); repository.Months.Add (new Month (2, "February")); repository.Months.Add (new Month (1, "January")); var controllerFactory = new ControllerFactory (repository); var controller = controllerFactory.GetDemoController (); var months = controller.GetFirstQuarter (); Assert.AreEqual ("February", months [1].Name); } }
Project Setup & Package References
To clarify the project structure and required references we have...The Xamarin Forms project - This provides the UI. It has to reference the sqlite.net pcl so it can pass the connection from the platform specific project to the core project.
The platform specific projects - these need to reference Ninject and sqlite.net. The platform specific versions are provided by the package dependency.
The core project - again this needs to reference Ninject and sqlite.net but this time it will use the cross compatible versions.
The unit test project - This one just needs the Ninject reference as it doesn't use sqlite.net.
The key thing to remember with all these package references is that the platform specific version will be provided; A reference to sqlite-net-pcl in an IOS project will provide the IOS version, in Android it will provide the Android version.
If you are missing the reference to Ninject in the platform specific project you will get a 'System.NotImplemented' exception.
If you are missing the SQLite reference in the platform specific project you will get the error 'Something went wrong in the build configuration. This is the bait assembly, which is for referencing by portable libraries, and should never end up part of the app. Reference the appropriate platform assembly instead.'
If you are getting either error with the packages in place try cleaning the solution or uninstalling the app from your device.
Intrepid South Morocco Discovery - December 2015
Sunday, 3 January 2016
Highlights - The High Atlas
On the first full day of the trip we drove from Marrakech into the High Atlas mountains. We travelled past the golf courses and olive groves on the edge of the city and then turned from the main highway into a valley on the way to the mountain town of Imlil. The drive was fairly short and we had a few photo and coffee stops on the way (Pro Tip - the best views are on the left hand side). Imlil is a proper mountain town and it’s where most climbers start the ascent of Mount Toubkal, the highest peak in North Africa. We left the van and started walking uphill. The mountains around us were dry and barren like I expected but the valley itself was surprisingly green, there was even grass! In fact in places it was like a warm autumn day at home. The path climbed quickly but the walking wasn’t hard. There were a few villagers about on the way but they didn’t want to be in photos, apparently not for any deep reason but because if they end up on a postcard their friends will laugh at them! At then end of the walk we arrived at our gite in the tiny village of Aroumd. We were welcomed on the roof terrace with a great lunch.Above Imlil |
Morning in the High Atlas |
Highlights - Tizi n Tichka & Ait Benhaddou
We needed to cross the Atlas mountains for the next part of out trip, which meant a lot of driving. Fortunately there was plenty to do and see on the way. After leaving Imlil we drove back towards Marrakech, then skirted the foot of the mountain range. We stopped at a town on market day where you could buy pretty much anything, and even visit the dentist or chiropractor! This was an eye opener for me and I guess it’s how a market day in Britain would have been two hundred years ago - everyone from the vicinity was out doing their shopping and it was really busy.After that stop we headed back into the mountains and the Tizi N’Tichka pass - this is the main route between the Marrakech plains and the edge of the sahara desert and it’s a busy road. The scenery was incredible throughout the drive - the landscapes throughout Morocco were vast, much bigger and more varied than I expected. The views changed constantly on the drive. Also as we drove through the towns and villages we got a fascinating, albeit brief, glimpse of the local lifestyle.
Tizi N'Tichka |
Rooftops at Ait Benhaddou |
Highlights - The Sahara
The Sahara Desert was the absolute highlight of the trip and a day and night that I’ll remember forever. We did so much in the day! First we stopped at a local town to pick up a picnic lunch, then visited an Islamic library with hundreds of books dating back to 1066 and some beautiful tiling. We also visited a pottery and had the chance to pick up some souvenirs. All this was early in the day, in the afternoon we were headed to the Sahara.Tiles at Tamegroute library |
Offroading! |
In the morning I got up early to watch the sunrise, there were tracks in the dunes so there must have been some animals around in the night, although we hadn’t seen any. After breakfast we got back into the 4x4s for some more driving. Again this was so good. Abd our guide had told us we would have a chance to look for fossils on the way out of the desert and we stopped in a place surrounded by rocks - there were fossils everywhere! This was a complete surprise and a great finish to our time in the desert.
Dunes at sunset |
Highlights - Essaouira
Essaouria is a fishing port on the Atlantic close. We a couple of nights there at the end of the trip and it made for a great ending. It was much more touristy than the places we had been before and it was a nice time to unwind after a lot of travelling. We stayed in a beautiful riad - my favourite accommodation of the trip. We had an interesting tour of the town, ate barbecued fish that we brought straight of the dock, had too much gelato and generally enjoyed ourselves. It was a good chance to do some shopping, there were loads of things to buy - leather goods, woodwork, we found a herbal shop down a backstreet which had herbs spilling from the walls, hundreds of jars of products, and a floor lined with the husks of argan nuts. On the first evening a few of us had beers on a rooftop terrace, then listened to a great local band with some Moroccan film stars. Basically it felt like being on holiday and was a nice way to finish. Essaouira is so photogenic, and I came home with some great pictures.Essaouira streets |
Weather
Travelling to Morocco in December means that you need to be prepared for a variety of weather; it’s warm in the daytime but can be very cold at night. That said, it was never uncomfortable cold, and although I’d brought my own sleeping bag I didn’t need it. Unless you really feel the cold you won’t either. Our guide told us a saying about Morocco - “The cold country with the hot sun” - and this is very true, even in December the sun was very warm but when it got dark it got cold very quickly. It didn’t rain at all and it was never really cloudy either. One thing I would say is that it was often cold in the hotels at night - in warmer weather it would be nice to sit outside or go for a swim in the evenings. In December it wasn’t warm enough to do either which was a shame.Accommodation
The accommodation throughout the trip was good. The hotel in Marrakech (El Caspien) had the best facilities but it was also the most expensive. The desert camp in the Sahara was obviously pretty basic but the beds were comfortable and their were plenty of sheets. The riad in Imlil was also basic and the showers weren’t exactly warm, but again it was perfectly comfortable. Apart from those two nights we stayed in hotels, my favourite of which was the riad in Essaouira which had a peaceful roof terrace. I also have to mention Riad Hida in Oulad Berhil which used to be a palace. It had beautiful grounds with peacocks in the gardens, and the restaurant was stunning. We had wifi every night except in the desert which was a nice surprise.Food
For most of the trip the food was quite similar. For breakfast we had bread, preserves, and maybe some pancakes or pastries. Simple, but tasty and filling. For lunch and dinner most places had a choice of tagine, cous cous, or chicken skewers and fries. The tagines and cous cous were more delicately spiced than I was expecting they were nice but not massively exciting. Also I’m not a big fan of red meat, or chicken on the bone, which didn’t help. There was normally a vegetarian option of vegetable (legume in French) tagine but all the tagine dishes also had plenty of veggies. The other dish that would appear regularly was berber omelette (an omelette with tomatoes and spices). I mostly chose chicken skewers and fries - I don’t eat chips at home but I was on holiday so I had an excuse! There was always plenty of tasty bread and olives alongside the meals so I never went hungry.Essaouira is a fishing port so obviously there’s some great seafood available. On the first night in town I had delicious dish of monkfish cooked in a ginger sauce and the next day we brought fish straight from the harbour and had it cooked on the dock. It was so cheap - I had sardines which cost pennies but even monkfish or tuna only cost a few dirhams. After buying the fish you had to pay someone to gut it, then take it to the barbecue and pay again to have it cooked (again both a really cheap). It’s cooked very simply but is absolutely delicious. We had our guide to help us with this - if I was travelling alone I would have gone to one of the stands in a square near the harbour which have the fish ready to cook for a set price. There’s also a great gelato shop in the same square which is a chance to work on your flavour combinations. The same shop also sells special hot chocolate.
In terms of drinks we got though a lot of coffee; mostly I had nos nos which is half espresso and half milk, the other choice being cafe noir. We also had a lot of mint tea - green tea with fresh mint leaves served in a teapot. There’s a technique to pouring it and you have to lift the pot as far above the cup as you can. I really enjoyed the mint tea - I much prefer it to straight green tea I’m going to start having it at home once I’ve grown some mint. Being a Muslim country alcohol isn’t widely available, a couple of the hotels served alcohol and there was the odd shop but you would need to be organised if you wanted to drink every day. Personally I found it was a nice change to not drink while on holiday. Until the last night that is, when I turned into a wine monster, but hey, it was our last night and I was in the mood.
Transport
For most of the trip we were in our own minibus and as there were only seven of us there was plenty of space. It was nice to have our own vehicle and meant we weren’t constantly worrying about out luggage. As I’ve said the 4x4s in the desert were great fun. I hadn’t realised that we would take a ‘chicken bus’ from Essaouira back to Marrakech - this actually turned out to be a nice coach with air conditioning. There were a couple of times where we left our main bags behind and took an overnight bag to our accommodation. This was a bit of an annoyance but I think that says more about my packing skills than anything else. There were a couple of long travel days which wasn’t ideal but the things we got to see and do made them worth it.Fast Restores with Sql Server Snapshots
Friday, 18 December 2015
Using Backup/Restore to reset you data is ok but it can take a while. Snapshots are a much faster alternative. On my system a 20Gb snapshot restores in less than 10 seconds.
What are snapshots
A database snapshot is a readonly view of a database at the time the snapshot was created. The exist as a database on the server – you can find them in ‘Database Snapshots’ in the Sql Managment Studio object explorer. You can use them for reporting but here we are creating them, then restoring them over the main database.
Creating snapshots
Here’s the script to create a snapshot. It doesn’t need much explanation…
If db_id('DemoSnapshot') is Not Null Begin Drop Database DemoSnapshot End CREATE DATABASE DemoSnapshot ON ( NAME = DemoDatabase, FILENAME = 'E:\TempBackups\Demo.ss') As Snapshot of DemoDatabase
If your database filename doesn’t match the database name you might get an error that says all files must be specified. In that case you need to pass the file name to the Name parameter.
Restoring snapshots
The script to restore the snapshot is simple as well. It closes existing connections by putting the database into single user mode, restores the snapshot, then puts the database back into multi user mode.
ALTER DATABASE DemoData SET SINGLE_USER WITH ROLLBACK IMMEDIATE GO RESTORE DATABASE DemoData From Database_Snapshot = 'DemoSnapshot' GO ALTER DATABASE DemoData SET MULTI_USER GO
That’s it, run the restore script whenever you want to put the database back to the saved state.
Quick Fix: Android Emulator is offscreen
Thursday, 16 April 2015
I’ve been having an annoying problem when the title bar for my Android emulator is off the top of the screen in Windows so I can’t move it around. I’ve found a couple of fixes…
1 – Hove over the icon on the TaskBar until a preview appears. Right click on the preview and select move. Then you can move the emulator with the cursor keys.
2 – Try using a different skin. I’ve found switching to no skin will bring the emulator back on screen and then I can switch it back to my normal skin with no problems.
An Autohotkey Timer Function
Sunday, 25 January 2015
#NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. SendMode Input ; Recommended for new scripts due to its superior speed and reliability. SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. TimerSleep(Time) { Countdown := Time Loop, %Time% { SplashTextOn, , 30,Sleeping, %Countdown% Sleep, 1000 Countdown := Countdown - 1 } SplashTextOff return 0 }
Xamarin Android - ViewPager & PageTranformers
Monday, 27 October 2014
ViewPager Basics
To set up a basic view pager we need:- A Layout with a ViewPager widget.
- Some fragments to use as pages.
- A PagerAdapter which managers the fragments.
- An Activity to tie everything together.
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" />In this example the page fragments are simple as well, the layout is contains a TextView and the fragment class just picks up the layout:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" android:minWidth="25px" android:minHeight="25px" android:background="@drawable/Fragment"> <TextView android:text="textView1" android:textAppearance="?android:attr/textAppearanceMedium" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textView1" android:textColor="#ff000000" /> </LinearLayout>
public class PagerFragment : Fragment { public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.Inflate(Resource.Layout.DemoFragment, container, false); return view; } }We need a PagerAdapter to manage the fragments, this is simple in the demo but would be more complicated in real life.
internal class DemoPagerAdapter : Android.Support.V13.App.FragmentStatePagerAdapter { private const int PageCount = 5; public DemoPagerAdapter(FragmentManager fm) : base(fm) { } public override Fragment GetItem(int position) { return new PagerFragment(); } public override int Count { get { return PageCount; } } }Finally we need an activity to tie it all together. The activity uses the view pager layout and ties it up to the pager adapter.
[Activity(Label = "PagerDemo", Icon = "@drawable/icon")] public class PagerActivity : Activity { private ViewPager viewPager; private PagerAdapter pagerAdapter; protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); this.SetContentView(Resource.Layout.PagerActivity); pagerAdapter = new DemoPagerAdapter(this.FragmentManager); viewPager = this.FindViewByIdAfter putting it all together you get an activity which looks like this. This is great but now we'll look at making the transitions between the pagers much cooler.(Resource.Id.pager); viewPager.Adapter = pagerAdapter; } }
Animations with Page Transformers
To spice up the animation between the fragments we need a class that implements ViewPager.IPageTransformer. This will let us customise the animation as the pages change in pretty much any way we like. We’ll also need to set the page transformer against the view pager using SetPageTransformer. The interface has a single method called TransformPage which accepts the view from the pages fragment and a float called position. The position variable will change from -1 to 1 as the page changes. -1 is off screen to the right, 1 is off screen to the left, and 0 means that the page is fully in the centre of the screen.First of all we’ll fade the fragments out as they go off screen, this is what the FadeTransformer class looks like when it’s running:
Here’s the code for the transformer. You can see it calculates the alpha value and then apply it to the view. We also need to set the alpha value to 0 when the view is fully of screen (positions 1 and -1).
/// <summary> /// This FadeTransformer fades fragments in and out as they are swiped. /// </summary> public class FadeTransformer : Java.Lang.Object, ViewPager.IPageTransformer { private float MinAlpha = 0.3f; // Minimum alpha value. public void TransformPage(View view, float position) { if (position < -1 || position > 1) { view.Alpha = 0; // The view is offscreen. } else { float scale = 1 - Math.Abs (position); // The scale should be 1 at position 0, and 0 at positions 1 and -1 float alpha = MinAlpha + (1 - MinAlpha) * scale; // Calculate the alpha value view.Alpha = alpha; // Apply the value to the view view.FindViewById<TextView> (Resource.Id.textView1).Text = string.Format ("Position: {0}\r\nAlpha: {1}", position, alpha); } } }Here’s another page transformer - this time we’ll shrink the views as they go offscreen:
And here’s the code. Calculating the scale is fairly simple. We also need to set the views TranslateX property, this keeps the edges of the old and new pages nice and close together:
/// <summary> /// This ScaleTransformer zooms fragments in and out as they are swiped. /// </summary> public class ScaleTransformer : Java.Lang.Object, ViewPager.IPageTransformer { private float MinScale = 0.5f; // Minimum scale value. public void TransformPage(View view, float position) { if (position < -1 || position > 1) { view.Alpha = 0; // The view is offscreen. } else { view.Alpha = 1; // Scale the view. float scale = 1 - Math.Abs (position) * (1 - MinScale); view.ScaleX = scale; view.ScaleY = scale; // Set the X Translation to keep the views close together. float xMargin = view.Width * (1 - scale) / 2; if (position < 0) { view.TranslationX = xMargin / 2; } else { view.TranslationX = -xMargin / 2; } view.FindViewById<TextView> (Resource.Id.textView1).Text = string.Format ("Position: {0}\r\nScale: {1}", position, scale); } } }In Android you can apply 3d effects to views easily. Here’s a page transformer that has a 3d ‘wheel’ effect.
Here’s the code, we need to set the pivots for the rotation - the y pivot is half way down the view and the x pivot can be on either edge. The x pivots should be on adjacent edges of the old and new views. The rotation values is calculated by multiplying the position by the maximum rotation value.
internal class WheelPageTransformer : Java.Lang.Object, ViewPager.IPageTransformer { private const float MaxAngle = 30F; public void TransformPage(View view, float position) { if (position < -1 || position > 1) { view.Alpha = 0; // The view is offscreen. } else { view.Alpha = 1; view.PivotY = view.Height / 2; // The Y Pivot is halfway down the view. // The X pivots need to be on adjacent sides. if (position < 0) { view.PivotX = view.Width; } else { view.PivotX = 0; } view.RotationY = MaxAngle * position; // Rotate the view. view.FindViewById<TextView> (Resource.Id.textView1).Text = string.Format ("Position: {0}\r\nPivotX: {1}\r\nRotationY {2}", position, view.PivotX, view.RotationY); } } }Here’s the final transformer, in this one pages from the right of the screen are treated normally but pages on the left sink into the background.
This transformer is slightly different to the other as the pages are drawn in the opposite order so that the z-indexs are correct. We control this in the call to SetPageTransformer. The other difference is that the transformer only really does anything when the pages are to the left of the screen.
internal class SinkAndSlideTransformer : Java.Lang.Object, ViewPager.IPageTransformer { public void TransformPage(View view, float position) { if (position < -1 || position > 1) { view.Alpha = 0; // The view is offscreen. } else { view.Alpha = 1; if (position < 0) { // 'Sink' the view if it's to the left. // Scale the view. view.ScaleX = 1 - Math.Abs (position); view.ScaleY = 1 - Math.Abs (position); // Set the translationX to keep the view in the middle. view.TranslationX = view.Width * Math.Abs (position); } } } }