Using a Sterling-database in Windows Phone as alternative to SQL CE

I you remember my blogpost from a very long time ago, I wrote about using SQL CE with Windows Phone (you can find it here). SQL CE can be queried with LINQ to SQL, making it interesting for storing relational data. Recently I came in contact with the Sterling-database (check it here), an Object-database which can be used in .NET, Silverlight and Windows Phone ! You can add “SterlingPhone” to your project by using NuGet. Just like SQL CE I can use Sterling for storing data in Isolated Storage. I’ll show you how to use it with a “fake” Northwind-database, but it can also be used for persisting full Viewmodels when using MVVM. In my fake Northwind-database I will use Products and Categories, so I simply start by creating classes for these two entities : 1: public class Product 2: { 3: public int ProductId { get; set; } 4:   5: public string ProductName { get; set; } 6:   7: public double? UnitPrice { get; set; } 8:   9: public Category Category { get; set; } 10: } 11:   12: public class Category 13: { 14: public int CategoryId { get; set; } 15:   16: public string CategoryName { get; set; } 17:   18: public List<Product> Products { get; set; } 19: } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }   These classes are pure and simple POCO-classes, no specific classes to inherit from or a bunch of attributes to use. Second step is to create our “database-class”, which inherits from BaseDatabaseInstance : public class FakeNorthWindDatabase : BaseDatabaseInstance .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } In here I will register my tables by overriding RegisterTables : protected override System.Collections.Generic.List<ITableDefinition> RegisterTables() { return new List<ITableDefinition>() { this.CreateTableDefinition<Product,int>(p=>p.ProductId) .WithIndex<Product,Category,int>("IX_ProductCategory",p=>p.Category), this.CreateTableDefinition<Category,int>(c=>c.CategoryId) }; } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } In here I create the table Category and Products, which are respectively using the CategoryId and ProductId-properties as identifiers. The WithIndex-option creates a relationship between these two entities. This database also needs to be registered. I do that in the Application_Launching: 1: private SterlingEngine engine; 2: private SterlingDefaultLogger logger; 3:   4: public static ISterlingDatabaseInstance DB { get; set; } 5:   6: private void Application_Launching(object sender, LaunchingEventArgs e) 7: { 8: InitDB(); 9: } 10:   11: private void InitDB() 12: { 13: engine = new SterlingEngine(); 14: engine.SterlingDatabase.RegisterSerializer<DefaultSerializer>(); 15: engine.Activate(); 16:   17: DB = engine.SterlingDatabase.RegisterDatabase<FakeNorthWindDatabase>(); 18: FakeNorthWindDatabase.Init(DB); 19: } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }   One of the things we need to do is to specify which serializer will be used for writing and reading data. At this moment we only have the DefaultSerializer and AggregateSerializer, but you could create your own classes here, as long as they inherit from BaseSerializer. At the end I call the init-method of the FakeNorthWindDatabase, which I implemented as follows : 1: internal static void Init(Wintellect.Sterling.ISterlingDatabaseInstance DB) 2: { 3: if (!DB.Query<Category,int>().Any()) 4: { 5: Category c1 = new Category() { CategoryId=1, CategoryName = "Beverages"}; 6: Category c2 = new Category() { CategoryId = 2, CategoryName = "Cheese" }; 7: Category c3 = new Category() { CategoryId = 3, CategoryName = "Seafood" }; 8:   9: Product p11 = new Product() { ProductId = 1, ProductName = "WestVleteren 12", 10: UnitPrice = 3, Category = c1 }; 11: Product p12 = new Product() { ProductId = 2, ProductName = "Rochefort 10", 12: UnitPrice = 3, Category = c1 }; 13: Product p13 = new Product() { ProductId = 3, ProductName = "Maredsous 8", 14: UnitPrice = 2.5, Category = c1 }; 15:   16: Product p21 = new Product() { ProductId = 4, ProductName = "Maredsous", 17: UnitPrice = 3, Category = c2 }; 18: Product p22 = new Product() { ProductId = 5, ProductName = "Gouda", 19: UnitPrice = 3, Category = c2 }; 20: Product p23 = new Product() { ProductId = 6, ProductName = "Cambozola", 21: UnitPrice = 2.5, Category = c2 }; 22:   23: Product p31 = new Product() { ProductId = 7, ProductName = "Shrimps", 24: UnitPrice = 3, Category = c3 }; 25: Product p32 = new Product() { ProductId = 8, ProductName = "Tuna Fish", 26: UnitPrice = 3, Category = c3 }; 27: Product p33 = new Product() { ProductId = 9, ProductName = "Calamares", 28: UnitPrice = 2.5, Category = c3 }; 29:   30: DB.Save(c1); 31: DB.Save(c2); 32: DB.Save(c3); 33:   34: DB.Save(p11); 35: DB.Save(p12); 36: DB.Save(p13); 37: DB.Save(p21); 38: DB.Save(p22); 39: DB.Save(p23); 40: DB.Save(p31); 41: DB.Save(p32); 42: DB.Save(p33); 43: } 44: } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } This code first checks if there is already categories present, and if not starts filling the database with some sample-data. We can now use our data: let’s simply show the name of a Category. The Sterling-database has a load-function that can be passed the key-value of the entity to find : 1: private void button1_Click(object sender, RoutedEventArgs e) 2: { 3: Category c= App.DB.Load<Category>(1); 4: MessageBox.Show(c.CategoryName); 5: } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Simple. Retrieving a list is also simple : listBox1.ItemsSource = App.DB.Query<Category, int>().Select(c => c.LazyValue.Value); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }   The select-method uses a delegate that takes a TableKey<Category,int> and returns an object, in this case the Category-entity. By using LINQ I can get the products for a specific category : int catId = Convert.ToInt32(NavigationContext.QueryString["cat"]); listBox1.ItemsSource = (from p in App.DB.Query<Product, int>() where p.LazyValue.Value.Category.CategoryId == catId select p.LazyValue.Value).ToList(); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }   Let’s add a new Category and product : 1: Category c = new Category() 2: { 3: CategoryId = 4, 4: CategoryName = "Condiments" 5: }; 6:   7: Product p = new Product() 8: { 9: ProductId = 10, 10: ProductName = "Aniseed Syrup", 11: UnitPrice = 12.2, 12: Category = c 13: }; 14:   15: App.DB.Save<Product>(p); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Saving the product also saves the category. Save checks the Id-field to know if it should do an update or an insert. Unfortunately there’s no autonumber-functionality, but Sterling also allows me to create triggers, with which I could create autonumber-functionality myself. This blogpost just scratches the surface of Sterling, there’s lots more fun stuff you can do with it, so check it out if you need to store persistant data. Follow @PiekenPuil !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs"); Tweet

Using Reactive extensions for feeding test sensor-readings in Windows Phone

An interesting technology you might have heard of is Reactive Extension (MSDN Rx Site). It’s available for different types of applications, although  you may need to add the necessary assemblies through NuGet. But in WP7.5 it’s included in the SDK. The only thing you need are references to Microsoft.Phone.Reactive and System.Observable.  Let’s start with a very simple scenario : simulating the PositionChanged-event of the GeoCoordinateWatcher. I know that the Mango-emulator allows me to simulate Geographical position, but it’s a nice starting point. My application consists out of a very simple Page which shows a Bing mapcontrol. I set the Zoomlevel to 10, and we’re set to go. The code is fairly simple : 1: private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e) 2: { 3: GeoCoordinateWatcher watcher = new GeoCoordinateWatcher(); 4: watcher.MovementThreshold = 1; 5: watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged); 6: 7: watcher.Start(); 8: } 9:   10: void watcher_PositionChanged(object sender, GeoPositionChangedEventArgs<GeoCoordinate> e) 11: { 12: map1.Dispatcher.BeginInvoke(()=> map1.Center = e.Position.Location); 13: } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }   Now let’s try to simulate some changes in our position: Let’s travel from South England to France, passing Dover and Calais. Let’s start by creating a simple function that gives me back an GeoPositionEventArgs every 50 ms : 1: #if DEBUG 2: static double l = 0; 3:   4: private static IEnumerable<GeoPositionChangedEventArgs<GeoCoordinate>> GetLocations() 5: { 6: while (true) 7: { 8: System.Threading.Thread.Sleep(50); 9: l += .001; 10:   11: yield return new GeoPositionChangedEventArgs<GeoCoordinate> 12: (new GeoPosition<GeoCoordinate>(DateTimeOffset.Now, new GeoCoordinate(51, l))); 13: } 14: } 15: #endif .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Now let’s create a Thread that calls this functions, and uses Rx for feeding the eventargs to the eventhandler : 1: private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e) 2: { 3: GeoCoordinateWatcher watcher = new GeoCoordinateWatcher(); 4: watcher.MovementThreshold = 1; 5: watcher.PositionChanged += new EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>>(watcher_PositionChanged); 6:   7: #if DEBUG 8: System.Threading.Thread thr = new System.Threading.Thread(() => 9: { 10: var test = GetLocations().ToObservable(); 11: test.Subscribe(ea => watcher_PositionChanged(null, ea)); 12: }); 13:   14: thr.Start(); 15: #endif 16: 17: watcher.Start(); 18: } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }   The ToObservable-function turns my IEnumerable<T> into an IObservable<T>. The Subscribe-function binds it with the eventhandler. Run the app (in debug-mode, of course), and you’ll see the map slowly moving East passing from England to France. Now let’s try to use the same concept with the Accelerometer. I create a simple page with three TextBlock-controls for displaying the X,Y and Z-components of my accelaration. In here we’ll have to do similar stuff with SensorReadingEventArgs<AccelerometerReading>. In AccelerometerReading I need to set the Acceleration-property which is of type Vector3 (with X,Y,Z). The problem that arrises here is that the setter of Accelartion is declared as internal, so I cannot use this from my code. The solution can be found at Microsoft Patterns and Practices site, which has some recipes for creating alternatives for the sensor-classes (here). Instead of the AccelerometerReading-class I can use AccelerometerSensorReading-class and the SettableAccelerometerSensorReading-class. The name of the latter already describes it : it will allow me to set the Acceleration-property. Let’s have a look at the result : 1: private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e) 2: { 3: AccelerometerAdapter acc = new AccelerometerAdapter(); 4: acc.TimeBetweenUpdates = TimeSpan.FromSeconds(1); 5:   6: acc.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<AccelerometerSensorReading>>(acc_CurrentValueChanged) 7: acc.Start(); 8:   9: #if DEBUG 10: System.Threading.Thread thr = new System.Threading.Thread(() => 11: { 12: var test = GetReadings().ToObservable(); 13: test.Subscribe(ea => acc_CurrentValueChanged(null, ea)); 14: }); 15:   16: thr.Start(); 17: #endif 18: } 19:   20: void acc_CurrentValueChanged(object sender, SensorReadingEventArgs<AccelerometerSensorReading> e) 21: { 22: ContentPanel.Dispatcher.BeginInvoke(() => 23: { 24: textBlock1.Text = e.SensorReading.Acceleration.X.ToString(); 25: textBlock2.Text = e.SensorReading.Acceleration.Y.ToString(); 26: textBlock3.Text = e.SensorReading.Acceleration.Z.ToString(); 27: }); 28: } 29:   30: #if DEBUG 31:   32: static float f = 0f; 33: public static IEnumerable<SensorReadingEventArgs<AccelerometerSensorReading>> GetReadings() 34: { 35: while (true) 36: { 37: System.Threading.Thread.Sleep(500); 38: var acc = new SettableAccelerometerSensorReading(); 39: acc.SetAcceleration(new Vector3(f, 0f, 0f)); 40: f += .1f; 41: if (f > Math.PI) 42: { 43: f = (float)-Math.PI; 44: } 45: var reading = new SensorReadingEventArgs<AccelerometerSensorReading>(); 46:   47: yield return new SensorReadingEventArgs<AccelerometerSensorReading>() { SensorReading = acc }; 48: } 49: } 50: #endif .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }   And there you go. Also tried it with the virtual Motion-sensor, unfortunately I got stuck there. I’m missing a SettableAttitudeReading-class, and I’ve been trying to create it since a few days, but I’m close to giving up. I guess there’s a reason for not having it in the patterns-library. Follow @PiekenPuil !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs"); Tweet

Creating WP7 prototypes with Sketchflow

With the upcoming release of Windows Phone Mango, you can create prototypes for Phone apps with Sketchflow. For people not knowing Sketchflow : it allows you to create prototypes that look like they have been drawn. When you present a “normal” prototype to a customer you get conversations like this : Nice protoype, how long before you can deliver us the final product ? I estimate we can deliver within 4 months. What ? You created this prototype in just 3 days, it looks like it’s almost finished. How can it possibly take 4 months for completing ? A sketchflow prototype looks more “unfinished”. It’s not new, it has been around for WPF and silverlight, but you can now also get the projecttemplate for WP7 for using in Blend. Just go to http://wp7sketchflow.codeplex.com/, download and install. Beware : you can only use this thing if you have the full paid version of Blend. The one you get for free with the phone developers tool will not do. OK. Let’s open up Blend and create a Windows Phone SketchFlow application : This project directly creates some an empty screen for my app  and a fake start-up screen: I also get an overview how I can move (“Flow”) between the different screens: I created a little prototype for an application I sometimes create during WP7-courses : a complaints-application for my city (the well-know megacity Serskamp in Belgium). This application allows me to signal stuff like defective traffic lights a.o. I also need to be able to add a location (GPS) and a picture, and to track my filed complaints. I’m not going to create the app itself now, but just the screens. I start by adding a Panorama on my start screen. This thing automatically gets 2 Panorama-items. The design of my item looks like this : For the data I created a demo-datasource in the data-tab:   got some trouble for designing the second Panorama-item. Unlike Visual Studio, in which you simply have to select a Panorama-item for making it the active one, there’s no such thing in Blend. Or at least I didn’t find it. The only thing I could do was temporary setting the visibility of the other items to collapsed. Inside the Flow-panel I can select to add a new Connected screen. This way I create a screen for the follow-up of my complaints, and one for setting the location. I also create connections for returning to Screen 1, and remove the connection from my new screens to Search and AppList. The Follow-up screen looks like this : For finishing I also change the start-screen, and I’m done. Now I’ve finished my SketchFlow-prototype, there’s 2 thing I can do : print it, or run it. In the File-menu you have an option for exporting to Word. This will export all your designs and add a table of contents : WindowsPhonePrototype2.doc (1,28 mb)  Creating a SketchFlow-prototype is essentially creating a Silverlight-application. This gives you a way of “running” the app, so you can demonstrate it to your customer (see video) :     Is that cool, or what ?     Follow @PiekenPuil !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs"); Tweet

Visual State Manager or rather Behavior ? (part 3)

So far, so good. I created a little application indicating the distance to my geographically closest friend. I used Visual State Manager for making my indicator change, depending on the distance I get from the Distance-service. It takes some practice to get used to it. Now, I have two little problems with VSM: It's a lot to write, even for having a simple control like our distance-indicator. Changes (e.g. adding another state) always have to be done in two locations : code and XAML. Now, when using Blend, you might have seen Behaviors, which you can drag and drop on top of your controls. They add some, ehm 'Behavior' to these controls. It also adds a specific assembly needed for creating these Behaviors, i.e. Microsoft.Phone.Interop. Next to a few out-of-the-box behaviors that Blend provides, you can start creating your own Behaviors. And the way of doing that, is just child's play. Simply create your own class, inheriting from Behavior<T> with T being the control for which you create a behavior. Of course, nothing stops you from using FrameworkElement here. I keep it simple, and I create a Behavior for the Ellipse. I also create 3 properties for specifying the colors for my distance-indicator: 1: public class DistanceBehavior : Behavior<Ellipse> 2: { 3: protected override void OnAttached() 4: { 5: base.OnAttached(); 6:   7: Ellipse ao = AssociatedObject as Ellipse; 8: DistanceReader.DistanceChanged += (s, ea) => 9: { 10: if (ea.Distance>5) 11: { 12: ao.Fill = this.FarColor; 13: } 14: else if (ea.Distance>2) 15: { 16: ao.Fill = this.AverageColor; 17: } 18: else 19: { 20: ao.Fill = this.CloseColor; 21: } 22: }; 23: } 24:   25: public Brush FarColor { get; set; } 26:   27: public Brush AverageColor { get; set; } 28:   29: public Brush CloseColor { get; set; } 30: } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }   Let's now use this behavior on an ellipse we add to our MainPage. We first need to add the necessary namespaces to our xaml: xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" xmlns:my="clr-namespace:WindowsPhoneApplication1" .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } (!! I'm only showing the my-namespace here for completeness. Since we already added it to App.xaml in Part 1, we don't need to add it here). Let's now add our ellipse, and give it our Behavior : <Ellipse> <i:Interaction.Behaviors> <my:DistanceBehavior FarColor="Red" AverageColor="Orange" CloseColor="Green"/> </i:Interaction.Behaviors> </Ellipse> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Test your application again, and you'll see your ellipse change in the same way as your VSM-control, but this time with less coding and (in my opinion) easier to maintain. Tweet

Visual State Manager or rather Behavior ? (part 2)

In part 1 I set up the service and the WP7-application. The WP7-application will poll the service regularly for asking the distance to the closest friend. Let's now finish the WP7-app so we can show the distance by a little indicator. When closer than 2 (km? miles ? light-years ? You choose) the indicator will show green, less then 5 will be orange, and all the rest is red. Let's first create an indicator using Visual State Manager. In VSM we will define different states. In code we define the state our control is in, and in XAML we define how a state should look like. Let's create our control: 1: [TemplatePart(Name="Core",Type=typeof(FrameworkElement))] 2: [TemplateVisualState(Name="Far",GroupName="DistanceStates")] 3: [TemplateVisualState(Name = "Close", GroupName = "DistanceStates")] 4: [TemplateVisualState(Name = "VeryClose", GroupName = "DistanceStates")] 5: public class DistanceIndicator: Button 6: { 7: Ellipse corePart; 8: 9: private Ellipse CorePart 10: { 11: get { return corePart; } 12: set { corePart = value; } 13: } 14: 15: public override void OnApplyTemplate() 16: { 17: base.OnApplyTemplate(); 18: 19: CorePart = (Ellipse) GetTemplateChild("Core"); 20: VisualStateManager.GoToState(this, "Far", true); 21: DistanceReader.DistanceChanged += 22: new EventHandler<DistanceEventArgs>(DistanceReader_DistanceChanged); 23: } 24: 25: void DistanceReader_DistanceChanged(object sender, DistanceEventArgs e) 26: { 27: if (e.Distance>5) 28: { 29: VisualStateManager.GoToState(this,"Far",true); 30: } 31: else if (e.Distance > 2) 32: { 33: VisualStateManager.GoToState(this,"Close",true); 34: } 35: else 36: { 37: VisualStateManager.GoToState(this, "VeryClose", true); 38: } 39: } 40: } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } The code-attributes already shows you the different states my Indicator can have : Far, Close and VeryClose (OutOfInspirationException occurred). I add the controltemplate to App.xaml, describing how my three states should look like : 1: <ControlTemplate x:Key="u2uCtrl" TargetType="my:DistanceIndicator"> 2: <Ellipse x:Name="ellipse" Height="{TemplateBinding Height}" Fill="Yellow"> 3: <VisualStateManager.VisualStateGroups> 4: <VisualStateGroup x:Name="DistanceStates"> 5: <VisualState x:Name="Close"> 6: <Storyboard> 7: <ColorAnimation Duration="0" To="Orange" 8: Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" 9: Storyboard.TargetName="ellipse" d:IsOptimized="True"/> 10: </Storyboard> 11: </VisualState> 12: <VisualState x:Name="VeryClose"> 13: <Storyboard> 14: <ColorAnimation Duration="0" To="Green" 15: Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" 16: Storyboard.TargetName="ellipse" d:IsOptimized="True"/> 17: </Storyboard> 18: </VisualState> 19: <VisualState x:Name="Far"> 20: <Storyboard> 21: <ColorAnimation Duration="0" To="Red" 22: Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" 23: Storyboard.TargetName="ellipse" d:IsOptimized="True"/> 24: </Storyboard> 25: </VisualState> 26: </VisualStateGroup> 27: </VisualStateManager.VisualStateGroups> 28: </Ellipse> 29: </ControlTemplate> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }I cheated, of course: I used blend for creating this template. Nevertheless, I add my control to my MainPage: <my:DistanceIndicator Content="" x:Name="distanceIndicator1" Template="{StaticResource u2uCtrl}" /> .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }That's it. Open the WPF-application, change the slider. Run the WP7-application and there you go. Play with the slider, and the WP7-app responds visually (after some time). Nice stuff, but it get's nicer with Behavior. That's for part 3. Tweet

Visual State Manager or rather Behavior(part 1)

During an interesting event last week, discussing the virtues of Silverlight apps out of the browser, I was confronted with Behavior. I should probably be ashamed because I never heard of them before. Because they have a high coolness- and awesomeness-level I checked if they were also available for Windows Phone, and hooray,  they are! Now what are they about ? In WPF you can use Triggers, to react on certain "events", like this one : <Button.Triggers> <EventTrigger RoutedEvent="Click"> <BeginStoryboard Storyboard="{StaticResource mySB}"/> </EventTrigger> </Button.Triggers> Specially useful when you're creating your own Controltemplates. Unfortunately they're not available in Silverlight (except for the Loaded-event).  When creating your own controls, and you need them to have some kind of visual feedback, we'll have to use the Visual State Manager. In my little example I have a WP7-app that regularly calls a "Distance-service" that gives the shortest distance between you and your geographically closest friend (could be something Foursquare provides). The closest distance will be shown by some small colored ellipse. Whenever the distance changes, the color changes. Let's start by the service: I have a little WCF library that I'm hosting in a WPF-app. Service looks like this: public class DistanceService : IDistanceService { public double GetDistance() { return DistanceHelper.Distance; } } Can't make them smaller than this. What about this DistanceHelper ? public static class DistanceHelper { private static double distance=10;   public static double Distance { get { return distance; } set { distance = value; } } } My MainWindow only has a slider going from 0 to 10, with an eventhandler for the ValueChanged. In this eventhandler I simply set the DIstance-property from DIstanceHelper: 1: private void distanceSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) 2: { 3: DistanceHelper.Distance = distanceSlider.Value; 4: } 5:   6: private void Window_Loaded(object sender, RoutedEventArgs e) 7: { 8: host = new ServiceHost(typeof(DistanceServiceLib.DistanceService)); 9: host.Open(); 10: } 11:   12: private void Window_Unloaded(object sender, RoutedEventArgs e) 13: { 14: host.Close(); 15: } I also configured my WCF-service to use simple basicHttpBinding. In my WP7-app I start by creating a service reference towards my service. This will be used by a helper-class DistanceReader: 1: public static class DistanceReader 2: { 3: static DistanceReader() 4: { 5: DispatcherTimer timer = new DispatcherTimer(); 6: timer.Interval = new TimeSpan(0, 0, 10); 7: timer.Tick += (s, ea) => 8: { 9: var proxy = new DistanceServiceRef.DistanceServiceClient(); 10: proxy.GetDistanceCompleted+=(s2,ea2)=> 11: { 12: DistanceReader.LastDistance = ea2.Result; 13: }; 14: proxy.GetDistanceAsync(); 15: }; 16: timer.Start(); 17: } 18: 19: public static event EventHandler<DistanceEventArgs> DistanceChanged; 20:   21: public static void OnDistanceChanged(DistanceEventArgs e) 22: { 23: if (DistanceChanged!=null) 24: { 25: DistanceChanged(typeof(DistanceReader), e); 26: } 27: } 28:   29: private static double lastDistance; 30: public static double LastDistance 31: { 32: get { return lastDistance;} 33: set 34: { 35: if (lastDistance!=value) 36: { 37: lastDistance = value; 38: OnDistanceChanged(new DistanceEventArgs() { Distance=value}); 39: } 40: } 41: } 42: } This class calls the service (every 10 seconds) and raises an event whenever the distance changes. Now, how to show this ? Let's start by the VSM-approach.  But that is something I'll leave for part 2. Tweet