File IO in Windows 8

Let’s leave Windows Phone for a moment, and let’s have a look at Windows 8. Recently the U2U-team was present at the Microsoft Build-convention in Anaheim, California, where Microsoft unveiled Windows 8. Now, what we saw is still just a preview, but it clearly shows the direction in which Windows is evolving. Have a look at this video, to see Windows 8 in action :

 

The “new style” applications Windows 8 offers are “Metro”-applications (yes, like in Windows Phone Metro style), and these can be made using Xaml and managed code, or even using HTML5 + Javascript. Metro-apps will have to be installed through a marketplace, and are kind of sandboxed (Comparable to Silverlight, but different ;-)  ). One of the effects of this sandboxing is that your options for working with files are limited. You cannot just access any folder on your machine ! Unfortunately you’re also unable to use Isolated Storage. So what can you use ? Let’s start by writing info into the “Local Folder”.

Windows.Storage.ApplicationData appData = Windows.Storage.ApplicationData.Current;
 
StorageFile file = await appData.LocalFolder.CreateFileAsync("EmployeeList.u2u");
Windows.Storage.Streams.IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite);

 

No ordinary File here, but a StorageFile which I have to open to write in. The IRandomAccessStream I get back gives me the possibility to create an input- (for reading) or output-stream (for writing).

IOutputStream output = stream.GetOutputStreamAt(0);

 

And then I got stuck. The IOutputStream gives me a WriteAsync-function, but it ask me for an IBuffer-object. How to write data ? Luckily there’s already some MSDN-documentation available. That tells me to use a DataWriter which takes the IOutputStream as a constructor-argument.

DataWriter writer = new DataWriter(output);
writer.WriteString("HERE GOES DATA");
output.FlushAsync();

 

Not there yet ! The code I wrote starts fro; the assumption that File IO is much like the “ordinary” file IO: flush the stream and done. In Metro we have to ”commit” the data in the writer, and I have to start the flushing, so this is the working code :

   1:  DataWriter writer = new DataWriter(output);
   2:  writer.WriteString("HERE GOES DATA");
   3:   
   4:  await writer.StoreAsync();
   5:  output.FlushAsync().Start();    
   6:  statusTxt.Text = "File Saved";

 

They could have made it simpler Smile.
By localfolder I assumed the bin/debug-folder. Nothing there. It seems my file is located in C:\Users\michael\AppData\Local\Packages\d64899f1-9800-470a-9cb3-fa89210f4941_qs0a8q7rnpy8j\LocalState.

How about reading the file ? Well, simply reverse your writing-logic (writer becomes reader, output becomes input, store becomes load, …)

   1:  Windows.Storage.ApplicationData appData = Windows.Storage.ApplicationData.Current;
   2:   
   3:  var file = await appData.LocalFolder.GetFileAsync("EmployeeList.u2u");
   4:  Windows.Storage.Streams.IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read);
   5:   
   6:  IInputStream input = stream.GetInputStreamAt(0);
   7:   
   8:  DataReader reader = new DataReader(input);
   9:   
  10:  var size = stream.Size;
  11:  await reader.LoadAsync((uint)size);
  12:  var data = reader.ReadString((uint)size);

 

There you go!

What about other folders than the “local” ? The KnownFolders=clqss gives me access to following locations :

  • Documents Library
  • Home Group
  • Media Server Devices (DLNA – Digital Living Network Alliance Devices, sounds interesting)
  • MusicLibrary
  • Pictures Library
  • Removable Devices
  • Videos Library

Let’s change the first 2 lines of my writing-code for using the documents library :

StorageFolder doclib = Windows.Storage.KnownFolders.DocumentsLibrary;
 
StorageFile file = await doclib.CreateFileAsync("EmployeeList.u2u");

 

As soon as you start running your code, it will fail on the first line (no exception though, simply stops). That’s because you explicitly have to give the app the capability to access the Document library. Double-clicking on Package.appxmanifest allows you to do that :

image

Still: this time your app will stop on the second line. You also need to associate your app with the u2u-fileextension. This is also done in the appxmanifest-file in the declarations-tab where we add a filetype association declaration :

image

There you go: the app works and saves my u2u-file in the doclibrary.


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 :

image

This project directly creates some an empty screen for my app  and a fake start-up screen:

image

I also get an overview how I can move (“Flow”) between the different screens:

image

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 :

image image

For the data I created a demo-datasource in the data-tab:

image 

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.

image

The Follow-up screen looks like this :

image

For finishing I also change the start-screen, and I’m done.

image

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 ?

 

 



The return of SQL CE !

After playing a few weeks with the Mango-beta, I’m even more convinced that the Windows Phone 7 simply is the best smartphone available. Driving in your car, receiving a text-message, and suddenly a voice over Bluetooth  asks me if the message should be read! And after the message has been read, it asks if I would like to dictate an answer (or call). How cool is that ? (unfortunately only in English for the moment, so when trying to dictate in Dutch, you get funny results ).

One of the things that Mango brings is SQL Server CE. I remember using this on Windows Mobile, when you had to use stuff like SqlCeConnection, SqlCeCommand, etc… It seems that these classes are not existing on Mango, but of course we have Linq to SQL we can use. Using IsolatedStorageFile’s for storing data is nice, but having a “real” database for storing relational data is nicer. Still, during my experiment I saw that there are a few things missing to make life easier. It’s still in beta of course, so hopefully it will get added in the near future.

I wanted to do a little trial showing the products and Categories out of the NorthWind-database. I decided to use SQL Integration Services for creating a SQL CE database for me, copying the needed data. Unfortunately this is not possible for CE. I needed to create the database and the tables myself. In the beta-version of Mango developer-tools it is yet impossible to select a SQLCE-file for item to add. I simply created it in a dummy console-app, and then copied it into my WP7-application. Double clicking on the sdf-file opens up the designer.

image

Adding a table is easy: Right-click the Tables-folder, select “Create Table” and you can start designing. This is what I created :

image

Specifying the Primary Key and the relationship between Products and Categories can be created by calling the table properties:

image

So far for the database structure. Copying the data from the “normal” Northwind to my CE-tables can be done through SQL Integration services. Now what about the LINQ to SQL classes ? No way of adding such an item in my project. The way to go, is like in the beginning of LINQ: use SQLMetal (You’ll find it here : C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin). The following command generates the necessary code:

Sqlmetal /code:NorthWindCE.cs Northwind.sdf

 

The generated code look nice, but if your looking for any navigation-properties: nowhere to find…

Next roadblock: I can only access databases stored in isolatedstorage. Makes sense, although it would be nice to be able to share data over multiple apps. Since there is no direct way of adding files for IsolatedStorage in VisualStudio, I wrote a bit of code for copying my sdf-file (which has been added as a resource) to IsolatedStorage:

   1:  private void CheckIsolatedStorageDb()
   2:  {
   3:      var storage = IsolatedStorageFile.GetUserStoreForApplication();
   4:      if (!storage.FileExists("NorthWind.sdf"))
   5:      {
   6:          Uri uri = new Uri("SQLTest;component/NorthWind.sdf",UriKind.Relative);
   7:          StreamResourceInfo info = App.GetResourceStream(uri);
   8:   
   9:          if (info!=null)
  10:          {
  11:              Stream stream = info.Stream;
  12:              BinaryReader reader = new BinaryReader(stream);
  13:              byte[] buffer = new byte[stream.Length];
  14:              reader.Read(buffer, 0, Convert.ToInt32(stream.Length));
  15:              reader.Dispose();
  16:   
  17:              IsolatedStorageFileStream iStream= storage.CreateFile("NorthWind.sdf");
  18:              iStream.Write(buffer, 0, buffer.Length);
  19:              iStream.Flush();
  20:              iStream.Dispose();
  21:              stream.Dispose();
  22:          }
  23:      }
  24:  }

 

I call this function on Application_launch, and my sdf-file gets copied.  From now on I can start using my db, using LINQ. Let’s start by adding a listbox to our MainPage like this:

<ListBox DisplayMemberPath="ProductName" ItemsSource="{Binding}" />

 

Code looks like this :

private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
    db = new NorthWind("Data Source=isostore:/NorthWind.sdf");
 
    this.DataContext = from p in db.Products
                       where p.UnitPrice < 20
                       select p;    
}

As you can see, I provide a connectionstring pointing to Isolated storage, binding the datacontext to some LINQ-statement, and voila.

Now what about navigating between categories and products ? First I extend my SQLmetal-generated code with these (copied these by generating code for the “big” Northwind) :

In Products:

   1:  private EntityRef<Categories> _Category;
   2:   
   3:  [global::System.Data.Linq.Mapping.AssociationAttribute(Name = "Category_Product", Storage = "_Category",
   4:      ThisKey = "CategoryID", OtherKey = "CategoryID", IsForeignKey = true)]
   5:  public Categories Category
   6:  {
   7:      get
   8:      {
   9:          return this._Category.Entity;
  10:      }
  11:      set
  12:      {
  13:          Categories previousValue = this._Category.Entity;
  14:          if (((previousValue != value)
  15:                      || (this._Category.HasLoadedOrAssignedValue == false)))
  16:          {
  17:              this.SendPropertyChanging();
  18:              if ((previousValue != null))
  19:              {
  20:                  this._Category.Entity = null;
  21:                  previousValue.Products.Remove(this);
  22:              }
  23:              this._Category.Entity = value;
  24:              if ((value != null))
  25:              {
  26:                  value.Products.Add(this);
  27:                  this._CategoryID = value.CategoryID;
  28:              }
  29:              else
  30:              {
  31:                  this._CategoryID = default(Nullable<int>);
  32:              }
  33:              this.SendPropertyChanged("Category");
  34:          }
  35:      }
  36:  }

And in Categories:

   1:  private EntitySet<Products> _Products;
   2:   
   3:  [global::System.Data.Linq.Mapping.Association(Name="Category_Product", Storage="_Products",
   4:      ThisKey="CategoryID", OtherKey="CategoryID")]
   5:  public EntitySet<Products> Products 
   6:  {
   7:      get { return this._Products; }
   8:      set { this._Products.Assign(value); }
   9:  }

 

  • Let’s now change our MainPage a little: I’ll have two Listboxes this time:
<ListBox DisplayMemberPath="CategoryName" Name="listBox2" ItemsSource="{Binding}" />
<ListBox Grid.Row="1" Name="listBox1" DataContext="{Binding ElementName=listBox2, Path=SelectedItem}"
         DisplayMemberPath="ProductName" ItemsSource="{Binding Products}" />

 

Also set the datacontext to categories this time :

private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
    db = new NorthWind("Data Source=isostore:/NorthWind.sdf");
 
    this.DataContext = db.Categories;            
}

And thanks to the powers of databinding, I get all products from the category I select.

image

Now I’m already happy to have this in the beta, but I’d like to have some extras in the final version:

  • - Give me an easy way of copying existing structures to my CE database
  • - Get me a way of creating my LINQ to SQL classes from within Visual Studio
  • - Make sure that my Navigation properties are being generated
  • - and give me something, so I can specify files to be directly saved in Isolated Storage. (Some Build Action ? Next to Resource, Content,… also an option IsolatedStorage ?)


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:  }

 

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"

(!! 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>

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.



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:  }

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>

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}" />
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.

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.



Updating WP7 live tiles without push notifications

While experimenting with push notifications for updating your live tiles, I found the ShellTileSchedule-class. It sounded interesting enough to play around with it.

On MSDN I found following description for this class : Creates an object which allows an application to schedule updates of its tile's background image.  The ShellTileSchedule has some properties like the recurrence and the interval. The interval is an enumeration which goes from hourly to monthly :

1

Another Property is the RemoteImageUri. Because of the word "Remote" I assume that the image has to be remote (that was a hard one Smile). So for testing this thing I first set up a website, with simply a png-image (62*62 – I copied Background.png and changed it a bit with Paint). Let's set up our schedule. This has to be done in the Application_Launching:

private void Application_Launching(object sender, LaunchingEventArgs e)
{
    sts = new ShellTileSchedule();
    sts.Interval = UpdateInterval.
 
    sts.Recurrence = UpdateRecurrence.Interval;
    sts.RemoteImageUri = new Uri(String.Format("http://localhost:51177/Site/Tiles/1.png", TileNr.ToString()));
    sts.Start();
}

After starting the application I had to wait for an hour before my tile changed. Changing the clock settings didn't do the job either, but after an hour, finally the tile changed.

This could be useful for pulling tiles, instead of pushing. Get a tile every hour for showing the weather conditions in your area.

Now about this "Remote"-thing. Can I use a local png-file for changing the tile this way ? My first try was to add a png-file, and than refer to it this way:

sts.RemoteImageUri = new Uri("/LocalTile/5.png",UriKind.Relative);

 

That was not good.

2

Also tried it with "/TilesTest;component/LocalTile/5.png", but also no success. I needed to get the absolute path. In Silverlight I can use App.Current.Host.Source and Windows Phone is Silverlight, right. But I cannot use the Source-property here, although I can see it in my Locals-window:

3 

OK, another try : let's use this code:

Uri uri = new Uri(new Uri(
    "file:///Applications//Install//27F6C4CB-1192-44AD-A970-635F12689A08//Install"),
    "//LocalTile//5.png");
sts.RemoteImageUri = uri;

OK, I know it's not very useful, because every user that has this application, will also have another GUID. Still : I do it for serving science Winking smile. Result :

 4

What happened to my GUID and stuff jQuery152010964315148992043_1315308924440 Last try, Let's simplify by using this :

Uri uri = new Uri(
    "file:///Applications//Install//27F6C4CB-1192-44AD-A970-635F12689A08//Install//LocalTile//5.png");

 

And now I get this :

5

OK, I quit. Remote indeed means Remote.



Saving an Image to the Pictures Hub

Something that will also be discussed during the upcoming Windows Phone course, here at U2U, is the cooperation between Silverlight for Windows Phone and XNA.

At the end of my previous blog post, I was left with one more challenge: saving my modified picture to the Pictures Hub. Until shortly I thought that the only way of using the Pictures Hub was through the PhotoChooserTask or the CameraCaptureTask. Luckily I came across the MediaLibrary-class from the XNA-framework, who gives much more possibilities for accessing your pictures.

To start I needed to add a reference to Microsoft.Xna.Framework. This results in an alarming message :

image

At first I tried to do some experimenting with the MediaLibrary. Let’s start by simply getting the number of pictures I have on the emulator :

ml = new MediaLibrary();
nrOfPics = ml.Pictures.Count;
MessageBox.Show(nrOfPics.ToString());

 

That works nice. The Medialibrary has several collection I can use, like Pictures, Songs, Genres,…

Next step : lets create a little slideshow-app for iterating through my pictures. I start out with a simple page :

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <Grid.RowDefinitions>
        <RowDefinition Height="523*" />
        <RowDefinition Height="84*" />
    </Grid.RowDefinitions>
    <Image Name="image1" Stretch="Fill" />
    <Grid Grid.Row="1" Name="grid1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Button Content="&gt;&gt;" Grid.Column="1" Name="btnGoForward" 
                Click="btnGoForward_Click" />
        <Button Content="&lt;&lt;" Name="btnGoBack" Click="btnGoBack_Click" />
    </Grid>
</Grid>

 

The code looks like this :

 1: public partial class MainPage : PhoneApplicationPage
 2: {
 3:     int nrOfPics;
 4:     int picNr = 0;
 5:     MediaLibrary ml;
 6:     BitmapImage img = new BitmapImage();
 7:  
 8:     // Constructor
 9:     public MainPage()
 10:     {
 11:         InitializeComponent();
 12:     }
 13:  
 14:     private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
 15:     {
 16:         ml = new MediaLibrary();
 17:         nrOfPics = ml.Pictures.Count;
 18:         MessageBox.Show(nrOfPics.ToString());
 19:         
 20:         ShowImage();
 21:     }
 22:  
 23:     private void ShowImage()
 24:     {
 25:         img.SetSource(ml.Pictures[picNr].GetImage());
 26:         image1.Source = img;
 27:     }
 28:  
 29:     private void btnGoBack_Click(object sender, RoutedEventArgs e)
 30:     {
 31:         if (--picNr<0)
 32:         {
 33:             picNr = nrOfPics - 1;
 34:         }
 35:         ShowImage();
 36:     }
 37:  
 38:     private void btnGoForward_Click(object sender, RoutedEventArgs e)
 39:     {
 40:         if (++picNr>=nrOfPics)
 41:         {
 42:             picNr = 0;
 43:         }
 44:         ShowImage();
 45:     }
 46: }

 

image

Let's now return to the application created during my previous blog post. In the "Save Img" code we opened another page that simply showed the image with copyright-message. Let's now change the loaded-event of the WrittenImage-page so we can save the image :

WriteableBitmap bmp = PhoneApplicationService.Current.State["bmp"] as WriteableBitmap;
writtenImage.Source = bmp;
 
MediaLibrary ml = new MediaLibrary();
Stream stream = new MemoryStream();
bmp.SaveJpeg(stream, bmp.PixelWidth, bmp.PixelHeight, 0, 100);
 
ml.SavePicture("u2uPic.jpg", stream);
 
MessageBox.Show("Picture Saved...");

 

The SaveJpeg-method from WritableBitmap gives me a Stream containing the image in jpg-format. SavePicture saves the image in the MediaLibrary. However: it doesn't work ! It took me some time to find out why: It seems that the position of the stream remains at the end-position. Insert this line of code just before the SavePicture-call to make it work:

stream.Position=0;
 

It's working !! Cool.

Next step: let's deploy these two apps to my device and test. Not working ! How the hell is that possible ? Retesting in the emulator : works fine. Retesting on device: not working. Aaaaargh !! Disconnecting my device, going over to a colleague to ventilate my frustration and see that all of a sudden it is working !! Seems that for this thing to work, it needs to be disconnected from the PC.

 

 


Adding a text to an image in WP7

Some time ago, somebody asked me if it was possible to add some text to an image, and then use the combination image-text as a new image. It seems that it’s rather easy to do, and it’s very similar to the way you could achieve this in regular Silverlight.

I started out by adding this piece of XAML to my MainPage :

<Grid x:Name=”ContentPanel” Grid.Row=”1″ Margin=”12,0,12,0″>
<Grid.RowDefinitions>

<RowDefinition Height=”532*” />

<RowDefinition Height=”75*” />

</Grid.RowDefinitions>

<Grid Name=”TheImage”>

<Image Name=”sourceImg” Stretch=”Uniform”

Source=”/WritableBitMap;component/Images/BasilicaNotreDame_ROW459961203.jpg” />

<TextBlock VerticalAlignment=”Center” Text=”(c) U2U” HorizontalAlignment=”Center”/>

</Grid>
<Grid Grid.Row=”1″ Name=”grid1″>
<Grid.ColumnDefinitions>

<ColumnDefinition Width=”*” />

<ColumnDefinition Width=”*” />

</Grid.ColumnDefinitions>

<Button Content=”Get Picture” Name=”button1″ Click=”button1_Click” />

<Button Content=”Save Img” Grid.Column=”1″ Name=”addMsgButton”

Click=”addMsgButton_Click” />

</Grid>

</Grid>

This creates something like this :

What I need to do now, is to use the grid, combining the Image and the TextBlock, as a new Image. To make it a bit more complete I also added a Button for fetching a picture from the PictureHub:

private void button1_Click(object sender, RoutedEventArgs e)

{
PhotoChooserTask task = new PhotoChooserTask();

task.Completed += (s, ea) =>

{

img = new BitmapImage();

img.SetSource(ea.ChosenPhoto);

sourceImg.Source = img;

};

task.Show();

}
For creating an new Image, out of the original one plus the added TextBlock, I use the WriteableBitmap-class, which has a constructor that takes a UIElement as input. This one I save in the service-state, and I open another page (WrittenImage.xaml).

WriteableBitmap wbm = new WriteableBitmap(TheImage, null);

PhoneApplicationService.Current.State["bmp"] = wbm;

NavigationService.Navigate(new Uri(“/WrittenImage.xaml”, UriKind.Relative));

WrittenImage.xaml is a simple Page that only has one Image-control (called writtenImage, to make a little bit confusing – I like confusion, sometimes). In the loaded-event I have following code :

if (PhoneApplicationService.Current.State.ContainsKey(“bmp”))

{

writtenImage.Source = PhoneApplicationService.Current.State["bmp"] as WriteableBitmap;

}

Nice. The next question is then if it’s possible to save this image in the Picture-hub. That’s for a next time…

If you know of a more elegant way of adding text to an image, let it know !