Archive Page 2

25
Mar
12

metro c# webapi client

Peter Daukintis

For my own purposes I wanted to create a test application which I can use as a test-bed to experiment with user interface aspects of Metro. I decided to create a simple REST web service and make create/read/update/delete type calls to it from a c# metro application. Pretty much the next step up from ‘Hello World’ for a web connected application.

First, to create the Web API choose ASP.NET MVC 4 Application from the New Project Dialog and in the ensuing dialog select WebApi. We are using the ASP.NET MVC 4 Beta which now includes the WebApi (http://www.asp.net/web-api); which was formerly known as WCF WebApi.

The template creates a ValuesController to expose the sample CRUD methods (GetCollection/Get/Post/Put/Delete). It uses a string as the payload so I’m going to change that to use a Person class.

public class Person
{
    static int idGen = 123456;
    public Person()
    {
        Id = ++idGen;
    }
    public Person(Person other)
    {
        Id = other.Id;
        Name = other.Name;
        Occupation = other.Occupation;
    }

    public string Occupation { get; set; }
    public string Name { get; set; }
    public int Id { get; private set; }
}

Next, I renamed the ValuesController to PeopleController and modified the template code to query a list of Person objects:

public class PeopleController : ApiController
{
    private List<Person> _list = new List<Person>
        {
            new Person{ Name = "fred", Occupation = "plumber" },
            new Person{ Name = "bob", Occupation = "lawyer" },
            new Person{ Name = "flo", Occupation = "pilot" },
        };

    // GET /api/people
    public IEnumerable<Person> Get()
    {
        return _list;
    }

    // GET /api/people/5
    public Person Get(int id)
    {
        return _list.SingleOrDefault(p => p.Id == id);
    }

    // POST /api/people
    public void Post(Person value)
    {
        _list.Add(value);
    }

    // PUT /api/people/5
    public void Put(int id, Person value)
    {
        var item = _list.SingleOrDefault(p => p.Id == id);
        if (item != null)
        {
            item.Name = value.Name;
            item.Occupation = value.Occupation;
        }
    }

    // DELETE /api/people/5
    public void Delete(int id)
    {
        var item = _list.SingleOrDefault(p => p.Id == id);
        if (item != null)
        {
            _list.Remove(item);
        }
    }

I’m not worried about the correctness or completeness of the http responses and behavior here as this post is about the client side of the code. Making the above code changes is enough to expose my RESTful api. For this example I an running the server on IISExpress on localhost – this enables me to test the GET calls using the browser by typing in http://localhost:60442/api/people to IE10 on the Desktop. (since web api returns JSON by default I made the modification to the registry described here http://stackoverflow.com/questions/2483771/how-can-i-convince-ie-to-simply-display-application-json-rather-than-offer-to-do to easily view the data coming back).

 

WebApiResponse

(I tested the other HTTP verbs using Fiddler by constructing requests by hand).

With that done it’s over to the Metro client.

I started with a blank c# Metro Style application and added a GridView to which I would bind my ViewModel (I tend to use the MVVM pattern). To support my MVVM architecture I rolled up a few helper classes; a DelegateCommand and a ViewModelBase class to provide INotifyPropertyChanged and an IsDesignMode property. The Expression Blend designer doesn’t work with network calls so the IsDesignMode property is used to facilitate design time data.

Next, I created some design-time data to enable me to design the ui in Blend

if (IsDesignMode)
{
    People = new ObservableCollection<Person>
    {
        new Person { Name = "design fred", Occupation = "Nurse" },
        new Person { Name = "design bob", Occupation = "Artist" },
        new Person { Name = "design flo", Occupation = "Teacher" },
        new Person { Name = "design zak", Occupation = "Fireman" },
        new Person { Name = "design rita", Occupation = "Nurse" },
    };
}

Here’s how it looked in Blend:

DesignData

With this out of the way I could get to the heart of the problem – making the client-side calls:

Starting with retrieving the initial list

var http = new HttpClient();
var resp = await http.GetAsync(new Uri(apiRoot));
var stream = await resp.Content.ReadAsStreamAsync();
var djs = new DataContractJsonSerializer(typeof(List<Person>));
People = new ObservableCollection<Person>((IEnumerable<Person>)djs.ReadObject(stream));
stream.Dispose();

Then, Deleting a Person from the list

var http = new HttpClient();
var resp = await http.DeleteAsync(new Uri(apiRoot + "/" + Selected.Id));
resp.EnsureSuccessStatusCode();

Then, editing and adding, which I implemented in the same function:

var http = new HttpClient();
var djs = new DataContractJsonSerializer(typeof(Person));
var ms = new MemoryStream();
djs.WriteObject(ms, person);
ms.Position = 0;
var sc = new StreamContent(ms);
sc.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");

var resp = original == null ?
        await http.PostAsync(new Uri(apiRoot), sc) :
        await http.PutAsync(new Uri(apiRoot + "/" + original.Id), sc);

ms.Dispose();
resp.EnsureSuccessStatusCode();

In order to invoke the CRUD commands I added an application bar and populated it with app bar command buttons which I data bound to ICommands exposed by the View Model.

 

appbar

 

One thing worth mentioning is that in order to edit the Person objects I needed some form of editor page. I wasn’t sure of the best Metro-Style way to implement it, but in the end I went for a modal dialog which looked similar to the built in message box.

 

PersonEditor

 

I created this as a full screen UserControl.

 

The solution containing the web api project and the metro c# client is here https://skydrive.live.com/redir.aspx?cid=4f1b7368284539e5&resid=4F1B7368284539E5!442&parid=4F1B7368284539E5!123.

UPDATE: An update for the Release Preview is here http://sdrv.ms/N4kfZT

17
Mar
12

skydrive upload c# metro

Peter Daukintis

A preview of the latest Live SDK for Metro apps can be downloaded here https://connect.microsoft.com/site1226. This is for usage with the Windows 8 Consumer Preview (Note that the SDK is a preview version with no go-live license).

After installing you can add a reference via ‘add Reference’ > and select Windows > Extensions in the Reference Manager dialog.

livesdkRef

In order to configure sign in on Windows Phone a client ID was required; this is different for Metro-style Apps as you now need to register your app package name and publisher identity here http://go.microsoft.com/fwlink/?LinkId=227628.

Once registered you will be provided with a new Package Name – copy this back into your app manifest.

Once this is complete, using the following code you will be able to sign in:

XAML:

add this namespace declaration

xmlns:live="using:Microsoft.Live.Controls"

and a sign in button

AccessRequest

 

The Live id session status is reported by the SessionChanged event so I handle it like this, storing the session object for later use:

private void SignInButtonSessionChanged(object sender, LiveConnectSessionChangedEventArgs e)
{
    if (e.Status == LiveConnectSessionStatus.Connected)
    {
        _liveConnectSession = e.Session;
        UpdateEnabled();
    }
}

Next we need a way to get hold of an image so I just used the File Picker to retrieve one (I added a way to capture an image using the camera but I couldn’t test it so it probably won’t work Sad smile)

Here’s the code for the file picker:

async private void ChooseFile(object sender, RoutedEventArgs e)
{
    FileOpenPicker openPicker = new FileOpenPicker();
    openPicker.ViewMode = PickerViewMode.Thumbnail;
    openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
    openPicker.FileTypeFilter.Add(".jpg");
    openPicker.FileTypeFilter.Add(".jpeg");
    openPicker.FileTypeFilter.Add(".png");
    StorageFile file = await openPicker.PickSingleFileAsync();

    if (file != null)
    {
        _filename = file.Name;
        BitmapImage bitmapImage = new BitmapImage();
        _stream = (FileRandomAccessStream)await file.OpenAsync(FileAccessMode.Read);
        bitmapImage.SetSource(_stream);
        myImage.Source = bitmapImage;
        UpdateEnabled();
    }
}

and finally, what it was all about, uploading to skydrive:

private void Upload(Stream data, string filename)
{
    var liveConnectClient = new LiveConnectClient(_liveConnectSession);

    liveConnectClient.UploadCompleted += LiveConnectClientUploadCompleted;
    VisualStateManager.GoToState(this, "Busy", true);
    liveConnectClient.UploadAsync("me/skydrive", filename, true, data, data);
}

Here’s the ui whilst uploading an image:

uploadspam

 

and when completed – displaying the json result returned by the upload.

 

uploadresults

 

and finally, the image on skydrive.

 

spamonskydrive

The project can be found here https://skydrive.live.com/redir.aspx?cid=4f1b7368284539e5&resid=4F1B7368284539E5!441&parid=4F1B7368284539E5!123

17
Mar
12

metro background audio c# (consumer preview)

Peter Daukintis

Some changes occurred in the consumer preview release of Windows 8 regarding background audio; the steps required to get it working are outlined in this forum post

http://social.msdn.microsoft.com/Forums/en-AU/winappswithcsharp/thread/2d3496df-a145-4d87-be08-aadd5a8098e2

The steps are

  • Create a MediaElement and set it’s AudioCategory property to ‘BackgroundCapableMedia’
    <MediaElement x:Name="myMedia"
                  Source="/Assets/Sleep Away.mp3"
                  AudioCategory="BackgroundCapableMedia"/>

  • Update the app manifest to declare Background Tasks of types ‘Audio’ and ‘Control Channel’
  • Implement event handlers for
    • MediaControl.PlayPressed
    • MediaControl.PausePressed
    • MediaControl.PlayPauseTogglePressed
    • MediaControl.StopPressed

 

public BlankPage()
{
    this.InitializeComponent();
    MediaControl.PlayPressed += MediaControl_PlayPressed;
    MediaControl.PausePressed += MediaControl_PausePressed;
    MediaControl.PlayPauseTogglePressed += MediaControl_PlayPauseTogglePressed;
    MediaControl.StopPressed += MediaControl_StopPressed;
}

private void MediaControl_StopPressed(object sender, object e)
{
    myMedia.Stop();
}

private void MediaControl_PlayPauseTogglePressed(object sender, object e)
{
}

private void MediaControl_PausePressed(object sender, object e)
{
    myMedia.Pause();
}

private void MediaControl_PlayPressed(object sender, object e)
{
    myMedia.Play();
}

The media transport event handlers which need to be implemented are detailed here http://msdn.microsoft.com/en-us/library/windows/hardware/hh833781.aspx

 

Here’s a working sample project.

https://skydrive.live.com/redir.aspx?cid=4f1b7368284539e5&resid=4F1B7368284539E5!440&parid=4F1B7368284539E5!123‏

UPDATE: I have updated this for the Release Preview (see http://babaandthepigman.wordpress.com/2012/08/12/metro-background-audio-c-release-preview/)

02
Mar
12

skydrive photo upload wp7

Peter Daukintis

I just modified my file upload sample (http://babaandthepigman.wordpress.com/2012/01/18/wp7-skydrive-upload/) to use the PhotoChooserTask to enable photo upload.

 

upload

 

Here are the files:

https://skydrive.live.com/redir.aspx?cid=4f1b7368284539e5&resid=4F1B7368284539E5!439&parid=4F1B7368284539E5!123

08
Feb
12

datatemplateselector winrt

by Peter Daukintis

Having used DataTemplateSelectors previously with WPF and similar on Silverlight/Windows Phone I decided to check out whether they work the same in a xaml Metro application. It turns out to be pretty much the same (barring a few things being a bit buggy in the Win8 Developer Preview). Anyway, for reference, here’s a description:

First I created a custom data template selector. This enables you to intercept the decision of which template to use.

Custom Template Selector
  1.     public class MyDataTemplateSelector : DataTemplateSelector
  2.     {
  3.         public DataTemplate PlaceTemplate { get; set; }
  4.         public DataTemplate PersonTemplate { get; set; }
  5.         protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
  6.         {
  7.             if (item is Person)
  8.                 return PersonTemplate;
  9.             if (item is Place)
  10.                 return PlaceTemplate;
  11.  
  12.             return base.SelectTemplateCore(item, container);
  13.         }
  14.     }


I then created an instance in my Main Page’s xaml…

Create Instance
  1. <UserControl.Resources>
  2.     <FlipView:MyDataTemplateSelector x:Key="mySelector" />
  3. </UserControl.Resources>

If you’re used to other xaml technologies you need to be careful with your namespace declaration as the syntax has changed for WinRT:

Using declaration
  1. xmlns:FlipView="using:FlipView"

One thing we haven’t done is to create and set up the DataTemplates:

DataTemplates
  1. <UserControl.Resources>
  2.     <DataTemplate x:Key="myPersonTemplate">
  3.         <Border Background="CornflowerBlue">
  4.             <TextBlock Text="{Binding Name}"
  5.                        FontSize="64"
  6.                        Foreground="Red"
  7.                        HorizontalAlignment="Center"
  8.                        VerticalAlignment="Center" />
  9.         </Border>
  10.     </DataTemplate>
  11.     <DataTemplate x:Key="myPlaceTemplate">
  12.         <Border Background="Orange">
  13.             <Grid>
  14.                 <Image Source="{Binding Image}"></Image>
  15.                 <TextBlock Text="{Binding PlaceName}"
  16.                            FontSize="128"
  17.                            Foreground="AliceBlue"
  18.                            HorizontalAlignment="Center"
  19.                            VerticalAlignment="Center" />
  20.             </Grid>
  21.         </Border>
  22.     </DataTemplate>
  23.     <FlipView:MyDataTemplateSelector x:Key="mySelector"
  24.                                      PersonTemplate="{StaticResource myPersonTemplate}"
  25.                                      PlaceTemplate="{StaticResource myPlaceTemplate}">
  26.     </FlipView:MyDataTemplateSelector>
  27. </UserControl.Resources>

Note that I have created the DataTemplates with a key in the UserControl Resources. This allows me to access the item as a StaticResource; I do this to set the properties on my custom DataTemplateSelector. Now the above may be used with any ItemsControl since that defines an ItemTemplateSelector property on which we can set our custom DataTemplateSelector. It just remains to mock up some data and try it out on a few different Containers:

Dummy Data
  1. private ObservableCollection<object> _collection = new ObservableCollection<object>
  2.     {
  3.         new Person { Name = "fred", Age = 22 },
  4.         new Person { Name = "bob", Age = 22 },
  5.         new Person { Name = "doris", Age = 22 },
  6.         new Place { PlaceName="Moscow", Image="./Images/350px-St__Basil2.jpg"},
  7.         new Person { Name = "mabel", Age = 22 },
  8.     };

Note that I have used the instance type to be the criteria under which I swap the template but of course, the criteria could be anything here. To test on a FlipView just add

FlipView
  1. <FlipView x:Name="myFlip" ItemTemplateSelector="{StaticResource mySelector}" />

 

and set the ItemSource in the code-behind:

ItemSource
  1. myFlip.ItemsSource = _collection;

Just replace the above two steps to try this with a different container.

FlipView seems to suffer from some issues where it rendered unexpected results; sometimes updating the template and sometimes not.

WP_001023 WP_001024

The ListBox gave the expected results:

WP_001027

01
Feb
12

wp7 Collectionviewsource filtering

Having read a recent question on the App Hub Forums I decided to update my previous post on CollectionViewSource http://babaandthepigman.wordpress.com/2011/07/03/wp7-collectionviewsource-sorting-a-listbox/ to enable filtering.

So, I added a text box to enter the filter string,

 

cvs2

 

And the following code to implement the filtering…

     private void FilterBoxTextChanged(object sender, TextChangedEventArgs e)
     {
           
Source.View.Filter = o =>
                                    
{
                                        
var item = o as Item;
                                        
if (item != null)
                                         {
                                            
return item.Text.Contains(filterBox.Text);
                                         }
                                        
return false;
                                     };
        }

and we get filtered results…

 

cvs2-2

Here’s the updated project https://skydrive.live.com/redir.aspx?cid=4f1b7368284539e5&resid=4F1B7368284539E5!436&parid=4F1B7368284539E5!123

18
Jan
12

wp7 skydrive upload

Technorati Tags:

Download the sdk, which at the time of writing is here http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=28195

Next, head over to https://manage.dev.live.com/Applications/Index and add an application. This will provide you with an application Id and a client secret token. You also need to configure a valid redirect url as required by the OAuth handshake.

 

liveappreg

 

Add a reference to Microsoft.Live and Microsoft.Live.Controls. (included with the SDK)

Add a SignInButton to your page.

 

<Controls:SignInButton x:Name="signInButton" Height="120"
                                   ClientId="XXXXXXXXXXXXXXXX"
                                   SessionChanged="SignInButtonSessionChanged"
                                   Scopes="wl.skydrive_update"
                                   RenderTransformOrigin="0.5,0.5" 
                                   d:IsHidden="True">

 

Now, you should be able to click on the sign in button, get redirected to the live login page.  After logging in you will be required to give consent for the requested authorisation. This will look like this:

 

authorise 

We then wire up a handler to the SignInButton SessionChanged event and if the sign in was successful we will get a LiveConnectSession object passed in the event.

            if (e.Status == LiveConnectSessionStatus.Connected)
            {
                VisualStateManager.GoToState(this, "SignedIn", true);
                _liveConnectSession = e.Session;
            }

 

A LiveConnectClient object can be constructed from the session object and used to carry out standard operations, i.e. upload, delete, copy, etc.

 

Find the project here:

https://skydrive.live.com/redir.aspx?cid=4f1b7368284539e5&resid=4F1B7368284539E5!435&parid=4F1B7368284539E5!123




Follow

Get every new post delivered to your Inbox.