Daniel Vaughan

free range code

Knockout Inline Binding Handlers

clock July 13, 2012 09:25 by author Daniel Vaughan

Recently I’ve been working on a HTML5 single page application (SPA). I’ve been relying Knockout with Script#. Nearly all of my application logic is in C#, which has allowed me to reuse a lot of my previously thought out approaches to validation and so forth. I complement that with smatterings of JS in the form of binding handlers and so forth. I'm really pleased with this approach so far.

I’ve been finding myself creating Knockout binding handlers for a lot of one off cases. To avoid this I’ve taken an approach that allows you to place your init and update logic in the binding itself. I don’t recommend using this everywhere, but under some circumstances it has proved useful, and it may prove useful for you too.

It works by creating a Knockout binding handler in the usual manner; placing it in a script file available to your page. The binding handler simply calls through to the bound function, allowing you to place your logic right in the data binding itself. The following shows the binding handler:

ko.bindingHandlers.inline = {
    init: function (element, valueAccessor, allBindingsAccessor, viewModel)
    {
        var boundFunction = ko.utils.unwrapObservable(valueAccessor().init);

        if (boundFunction)
        {
            boundFunction(element, valueAccessor, allBindingsAccessor, viewModel);
        }
    },
    update: function(element, valueAccessor, allValuesAccessor, viewModel) {
        var boundFunction = ko.utils.unwrapObservable(valueAccessor().update);

        if (boundFunction)
        {
            boundFunction(element, valueAccessor, allValuesAccessor, viewModel);
        }
    }
};

The binding handler simply calls through to your init and update functions defined within your value accessor binding.

I have a page that is bound to a viewmodel that takes care of displaying a jQuery dialog. The dialog content itself is resolved using an external template. All of this is wired up in the data binding, as shown in the following excerpt:

<div id="CustomDialogContent" 
     data-bind="inline: { init: function (element) { $(element).dialog({ autoOpen: false }); }, 
                          update: function (element) { $(element).dialog(DialogOpen() ? 'open' : 'close'); }}">
        <div data-bind="template: { name: function() { return DialogTemplate(); }, data: DialogDataContext }" class="ocDialogBody"></div>  
</div>  

So, there you have it, a handy little tip for reducing the number of one off binding handlers in your JS app.

Follow me on twitter



Using T4 to Generate Windows Phone WMAppManifest Files

clock April 6, 2012 01:44 by author Daniel Vaughan

Recently, Eric Schoenholzer began an interesting discussion on the Windows Phone Experts group on linkedin centred around techniques for effectively monetizing your apps on the Windows Phone marketplace. In particular, he raised the interesting question of whether it is better to publish a single app with a trial, or whether it is more effective to go for two apps: a free version with ads and a paid version without ads. These days I favour the later in most cases (I explain why in linkedin discussion). But the downside is that because of the reliance on the WMAppManifest file in your phone app, it often means you have to maintain two versions of your app. Rather than do that, my approach has been to rely on a T4 template to generate the WMAppManifest file, which takes care of changing various fields such as the title of the app depending on the value of a pre-processor directive. This allows you to maintain a single version of your app, and a single version of your WMAppManifest file. It’s an approach that I have used in several published apps, and it has made maintaining them that little bit easier.

To replace the static WMAppManifest file with a dynamic T4 generated file, perform the following steps:

  1. Add a new text file named WMAppManifest.txt to your project.
  2. Place the text file in the Properties directory of your project by dragging it with the Visual Studio Solution Explorer.
  3. Copy the contents of the existing WMAppManifest.xml file to the newly created WMAppManifest.txt file. When you paste the text, you may find it is incorrectly formatted as HTML. This is Visual Studio trying to be helpful, but in this case we want the text pasted as is. Press Ctrl-Z once, and the auto-formatting will be removed.
  4. Add the following T4 directives to the top of the WMAppManifest.txt file:
    <#@ template debug="false" hostspecific="true" language="C#" #>
    <#@ output extension=".xml" #>
    Notice that the template directive specifies that the template is host specific. This gives the template access to the Visual Studio DTE, which is discussed later in this article.
  5. Delete the existing WMAppManifest.xml file.
  6. Rename WMAppManifest.txt to WMAppManifest.tt. This should produce a WMAppManifest.xml file, which is nested beneath the T4 template (as shown in Figure 1).

Solution Explorer with T4 template

Figure 1: Solution Explorer with T4 template

Using a T4 template to generate the WMAppManifest file is, in itself, not difficult. The fun part is determining your project configuration from the T4 template. This can be done by reading a property value, which is set according to a preprocessor directive, from the template. The system I use is convention based. It relies on a class called DeploymentConfiguration, which is expected to contain a Boolean constant named PaidConfiguration (see Listing 1). A preprocessor directive determines the value of the PaidConfiguration constant. The DeploymentConfiguration class contains several other related properties that can be used to determine the visibility and behaviour of visual elements based on whether the app has been purchased or not.

Listing 1: DeploymentConfiguration Class

//#define PAID

class DeploymentConfiguration
{
    /// <summary>
    /// The app identifier for the non-free version of the app. 
    /// This is used to provide a link to buy the paid app from the free app.
    /// </summary>
    public static string PaidAppId
    {
        get
        {
            return "11111111-1111-1111-1111-11111111";
        }
    }

    public static string AdAppId
    {
        get
        {
#if DEBUG
            return "test_client";
#else
            return "11111111-1111-1111-1111-11111111";
#endif
        }
    }

    public static string AdUnitId
    {
        get
        {
            return "11111";
        }
    }

    /* This should be false when publishing a paid version; true otherwise. */
    public static bool ShowAds
    {
        get
        {
            return !PaidConfiguration;
        }
    }

    public static bool Paid
    {
        get
        {
            return PaidConfiguration;
        }
    }

    public const bool PaidConfiguration =
#if PAID
 true;
#else
 false;
#endif
}

As you see in a moment, the WMAppManifest.tt relies on a include file named ProjectVariables.ttinclude (see Listing 2). ProjectVariables.ttinclude relies on the DTE, which is the top level Visual Studio automation object. The DTE allows you to traverse the structure of your solution. In this case, it is used to retrieve the value of the PaidConfiguration constant in the DeploymentConfiguration.cs file.

Listing 2: ProjectVariables.ttinclude

<#@ assembly name="System.Core" #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.Globalization" #>
<# 
/* Retrieve the DTE. */
IServiceProvider hostServiceProvider = (IServiceProvider)Host;
EnvDTE.DTE dte = (EnvDTE.DTE)hostServiceProvider.GetService(typeof(EnvDTE.DTE));
/* Retrieve the project in which this template resides. */
EnvDTE.ProjectItem containingProjectItem = dte.Solution.FindProjectItem(Host.TemplateFile);
Project project = containingProjectItem.ContainingProject;
var projectName = project.FullName;
ProjectItem deploymentConfiguration = GetProjectItem(project, "DeploymentConfiguration.cs");

if (deploymentConfiguration == null)
{
    throw new Exception("Unable to resolve DeploymentConfiguration.cs file");
}

var codeModel = deploymentConfiguration.FileCodeModel;
bool paid = false;

foreach (CodeElement codeElement in codeModel.CodeElements)
{
    if (codeElement.Name == "DeploymentConfiguration")
    {
        CodeClass codeClass = (CodeClass)codeElement;
        foreach (CodeElement memberElement in codeClass.Members)
        {
            if (memberElement.Name == "PaidConfiguration")
            {
                CodeVariable variable = (CodeVariable)memberElement;
                paid = bool.Parse(variable.InitExpression.ToString());
            }
        }
    }
} 
#>
<#+ EnvDTE.ProjectItem GetProjectItem(Project project, string fileName)
{
    foreach (ProjectItem projectItem in project.ProjectItems)
    {
        if (projectItem.Name.EndsWith(fileName))
        {
            return projectItem;
        }
        var item = GetProjectItem(projectItem, fileName);
        if (item != null)
        {
            return item;
        }
    }
    return null;
}

EnvDTE.ProjectItem GetProjectItem(EnvDTE.ProjectItem projectItem, string fileName)
{
    if (projectItem.ProjectItems != null 
        && projectItem.ProjectItems.Count > 0)
    {
        foreach (ProjectItem item in projectItem.ProjectItems)
        {
            if (item.Name.EndsWith(fileName))
            {
                return item;
            }
        }
    }
    return null;
} 
#>

When the ProjectVariables.ttinclude is defined as an include in the WMAppManifest.tt file, the value of the paid variable can be used to determine the title of the app and any other configurable aspects of the app (see Listing 3).

A title variable is assigned according to the value of the paid variable (defined in the ProjectVariables.ttinclude). The title variable is then used within the App element.

You’ll notice that the include file directive immediately precedes the string title variable definition, and that there is no space between them. This isn’t merely a case of sloppy formatting but rather the positioning of line breaks within the T4 template is important. Adding a line break produces an invalid WMAppManifest, because the xml definition must be placed on the first line of the file.

Listing 3:WMAppManifest.tt T4 Template

<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".xml" #>
<#@ assembly name="System.Core" #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text.RegularExpressions" #>
<#@ import namespace="System.Globalization" #>
<#@ include file="ProjectVariables.ttinclude" #><#
string title = paid ? "My App Pro" : "My App with Ads";
#>
<?xml version="1.0" encoding="utf-8"?>
<Deployment xmlns="http://schemas.microsoft.com/windowsphone/2009/deployment" AppPlatformVersion="7.1">
  <App xmlns="" ProductID="{11111111-1111-1111-1111-111111111111}" Title="<#= title #>" RuntimeType="Silverlight" 
       Version="1.0.0.0" Genre="apps.normal"  Author="Example Author" Description="Sample description" Publisher="Example Publisher">

    <IconPath IsRelative="true" IsResource="false">ApplicationIcon.png</IconPath>
    <Capabilities>
      <Capability Name="ID_CAP_GAMERSERVICES"/>
      <Capability Name="ID_CAP_IDENTITY_DEVICE"/>
      <Capability Name="ID_CAP_IDENTITY_USER"/>
      <Capability Name="ID_CAP_LOCATION"/>
      <Capability Name="ID_CAP_MEDIALIB"/>
      <Capability Name="ID_CAP_MICROPHONE"/>
      <Capability Name="ID_CAP_NETWORKING"/>
      <Capability Name="ID_CAP_PHONEDIALER"/>
      <Capability Name="ID_CAP_PUSH_NOTIFICATION"/>
      <Capability Name="ID_CAP_SENSORS"/>
      <Capability Name="ID_CAP_WEBBROWSERCOMPONENT"/>
      <Capability Name="ID_CAP_ISV_CAMERA"/>
      <Capability Name="ID_CAP_CONTACTS"/>
      <Capability Name="ID_CAP_APPOINTMENTS"/>
    </Capabilities>
    <Tasks>
      <DefaultTask  Name ="_default" NavigationPage="/MainPage.xaml"/>
    </Tasks>
    <Tokens>
      <PrimaryToken TokenID="Your App token id" TaskName="_default">
        <TemplateType5>
          <BackgroundImageURI IsRelative="true" IsResource="false">Background.png</BackgroundImageURI>
          <Count>0</Count>
          <Title>Your app title</Title>
        </TemplateType5>
      </PrimaryToken>
    </Tokens>
  </App>
</Deployment>

The app, in the downloadable sample code, supports two configurations: a paid configuration and free with ads configuration. The main page title is set according to the DeploymentConfiguration.Paid property value, as shown in the following excerpt:

public MainPage()
{
    InitializeComponent();

    ApplicationTitle.Text = DeploymentConfiguration.Paid 
                                 ? "MY APP PRO" : "MY APP FREE";
}

This indicates the configuration of the application when the PAID preprocessor directive is changed in the DeploymentConfiguration class (see Figure 2).

Free App landing page Paid App landing page

Figure 2: The main page title changes according to the Paid property.

This enables you to verify that the app has indeed been built for a specific deployment scenario. More importantly, and in both cases, if you switch to the App List after deploying to the emulator you’ll see the application title updated to reflect the value in the generated WMAppManifest.xml file (see Figure 3).

Free App in App List Paid App in App List

Figure 3: App title reflects deployment scenario in the App List.

Thus, there is no longer any need to maintain two copies of your WMAppManifest.xml file or the entire project.

NOTE: The WMAppManifest.tt T4 template must be re-processed when the PAID directive is changed. This does not happen automatically. To rerun the T4 template right on the template and select Run Custom Tool. Alternative, use the Transform All Templates button in the Solution Explorer tool bar (see Figure 4).

Process All Templates Button

Figure 4: Process All Templates Button

If you wish, the preprocessor directive can be associated with a build configuration for your project, allowing you to switch to a different scenario without modifying the DeploymentConfiguration.cs file.

In this article you saw how to use a T4 template to generate the WMAppManifest.xml file for your app. You saw how a preprocessor directive can be used to change the contents of the WMAppManifest.xml file, in particular the application title to support different application deployment scenarios. The Visual Studio DTE was used to traverse the project structure to locate a property in a class; forming a bridge between the T4 template and your project configuration.

This approach allows you to maintain a single version of your app, and a single version of your WMAppManifest file. It’s an approach that I have found useful, and I hope you find it useful too.

Download Source Code (~40kb)

Follow me on twitter



March .NET Dev Meeting in Geneva Final Date

clock March 6, 2012 15:14 by author Daniel Vaughan

The date for the next Geneva Microsoft Technology Developers meeting has been set: 6pm Monday 12 March.

It's going to be an extremenly interesting meeting this month. A couple of members have volunteered to present, and it's bound to be a lot of fun. If you have *any* small pieces of code or something you find interesting, please feel free to jump up and show it to the group! Don't hold back!

Please feel free to invite your colleagues to the group meeting as well! The more the merrier. We'll have pizza at the meeting! (Thanks Dung)

 

The location of the meeting is:

Microsoft Sàrl 
MBC 12 ave. des Morgines 1213 Petit-Lancy, Geneva 
View on Bing Maps 

Getting there:

• Public transport

    o From “Cornavin”, the main train station o Tram #14, direction “Bernex”

    o Get off at “Les Esserts” (15 min)

    o The “ave. des Morgines” is on the right o Walk 1 ½ block

• Car: there’re 2 supermarkets with parking nearby, but I don’t know if they close at night o “Migros”, rue des Bossons 78-80

    o Centre commercial de Lancy, route de Chancy 71

 

Once you’re in front of the building:

· Enter the front door

· Turn right

· Turn left just before the Atrium

· Take elevator E

· 3rd floor

· Turn left

 

The gates to the building close at 6.30 pm, so be sure to arrive before then.

Hope to see you there!

 



Looking to Apollo

clock March 1, 2012 05:39 by author Daniel Vaughan

I’m here in Redmond attending the annual MVP summit. Besides all the terrific sessions, connecting with product teams, and the after parties, I’m ecstatic about what I’ve seen on the upcoming Apollo release of the Windows Phone OS. While an NDA prevents me from providing any detail, I can say that, in my view, Microsoft is making the right choices regarding the direction of the phone that will make it an easy choice for business users. I’ve never been more confident about the future of the platform.

On other news, the terrific people at SAMS have just informed me that Windows Phone 7.5 Unleashed has been shipped to the printer, and the book should be available in vendors shortly after 27 March. Sixteen months, 1150 pages, it's been a long yet enjoyable journey.

Pssst, I'm offering an exclusive preview download of an open-source framework that is a consolodation of the book code, to members of the Windows Phone Experts on LinkedIn.

 



March .NET Dev Meeting in Geneva

clock February 13, 2012 01:10 by author Daniel Vaughan

After the success of last month's .NET developers meeting in Geneva, we're doing it again!

Feel like meeting up with other developers to discuss Microsoft software development, in particular Windows Phone, XAML, WinRT, Silverlight , WPF and ASP.NET? Come join us at the Microsoft building in Geneva between the 12th and 16th of March. A poll has been set up to narrow down the date. Please let us know if you'd like to attend by adding your name.

We'll be discussing the agenda for the meeting on this LinkedIn group

The location of the meeting is:

Microsoft Sàrl 
MBC 12 ave. des Morgines 1213 Petit-Lancy, Geneva 
View on Bing Maps 

Getting there:

• Public transport

    o From “Cornavin”, the main train station o Tram #14, direction “Bernex”

    o Get off at “Les Esserts” (15 min)

    o The “ave. des Morgines” is on the right o Walk 1 ½ block

• Car: there’re 2 supermarkets with parking nearby, but I don’t know if they close at night o “Migros”, rue des Bossons 78-80

    o Centre commercial de Lancy, route de Chancy 71

 

Once you’re in front of the building:

· Enter the front door

· Turn right

· Turn left just before the Atrium

· Take elevator E

· 3rd floor

· Turn left

 

The gates to the building close at 6.30 pm, so be sure to arrive before then.

Hope to see you there!



ExpressionBlend.com is Live!

clock February 9, 2012 10:14 by author Daniel Vaughan

My good friend Brennon Williams has created a new site located at ExpressionBlend.com

On the site are blogs from many Expression Blend related sites, including this one! Definately worth subscribing.



Geneva Developers Meetup Feb 2012

clock January 23, 2012 11:46 by author Daniel Vaughan

Live near the Geneva area of Switzerland? Feel like meeting up with other developers to discuss Microsoft software development, in particular Windows Phone, XAML, WinRT, Silverlight , WPF and ASP.NET? Come join us at the Microsoft building in Geneva on the 7th of February 2012.

Please let us know if you'll attend by adding your name to this poll

The location of the meeting is:

Microsoft Sàrl
MBC 12 ave. des Morgines 1213 Petit-Lancy, Geneva
View on Bing Maps 

Getting there:

• Public transport

    o From “Cornavin”, the main train station o Tram #14, direction “Bernex”

    o Get off at “Les Esserts” (15 min)

    o The “ave. des Morgines” is on the right o Walk 1 ½ block

• Car: there’re 2 supermarkets with parking nearby, but I don’t know if they close at night o “Migros”, rue des Bossons 78-80

    o Centre commercial de Lancy, route de Chancy 71

 

Once you’re in front of the building:

· Enter the front door

· Turn right

· Turn left just before the Atrium

· Take elevator E

· 3rd floor

· Turn left

 

The gates to the building close at 6.30 pm, so be sure to arrive before then.

Hope to see you there!



CodeProject Interview

clock September 29, 2011 10:53 by author Daniel Vaughan

Recently I took part in an interview with CodeProject. It includes some info about my background, projects, interests. 



Binding the WP7 ProgressIndicator in XAML

clock August 26, 2011 08:53 by author Daniel Vaughan

Update:

Since first posting this article, a later version of the WP FCL the ProgressIndicator gained binding support. You can bind it in a page like so:

<shell:SystemTray.ProgressIndicator>

        <shell:ProgressIndicator IsIndeterminate="{Binding Busy}" 

                                 IsVisible="{Binding Busy}" 

                                 Text="{Binding Message}" />

</shell:SystemTray.ProgressIndicator>

--------------------------------

 

The Mango beta of the Windows Phone 7 SDK sees the inclusion of a new way to display progress of asynchronous operations within the phone's system tray. This is done using the new ProgressIndicator class, which is a DependencyObject that hooks in to the native progress bar in the system tray, and allows you to display text message in the system tray, along with allowing you to control the progress bar that can handle both determinate and indeterminate states.

While the ProgressIndicator supports data-binding, the downside is that bindings need to be set up in the page code-beside; which is not very elegant. See the following example of a page constructor wiring up a ProgressIndicator:

 

public FooView()
{
    InitializeComponent();

    DataContext = new FooViewModel();

    Loaded += (o, args) =>
    {
        var progressIndicator = SystemTray.ProgressIndicator;

        if (progressIndicator != null)
        {
            return;
        }

        progressIndicator = new ProgressIndicator();

        SystemTray.SetProgressIndicator(this, progressIndicator);

        Binding binding = new Binding("Busy") { Source = ViewModel };

        BindingOperations.SetBinding(
            progressIndicator, ProgressIndicator.IsVisibleProperty, binding);

        binding = new Binding("Busy") { Source = ViewModel };

        BindingOperations.SetBinding(
            progressIndicator, ProgressIndicator.IsIndeterminateProperty, binding);

        binding = new Binding("Message") { Source = ViewModel };

        BindingOperations.SetBinding(
            progressIndicator, ProgressIndicator.TextProperty, binding);
    };

}

 

While completing my latest chapter of Windows Phone 7 Unleashed, on local databases, I spent a few minutes writing a wrapper for the ProgressIndicator. The ProgressIndicatorProxy, as it's called, can be placed in XAML, and doesn't rely on any code-beside:

<Grid x:Name="LayoutRoot" Background="Transparent">
    <u:ProgressIndicatorProxy IsIndeterminate="{Binding Indeterminate}" 
                                Text="{Binding Message}" 
                                Value="{Binding Progress}" />
</Grid>

 

The element itself has no visibility; its task is to attach a ProgressIndicator to the system tray, and to provide bindable properties that flow through to the ProgressIndicator instance.

When the element's Loaded event is raised, it instantiates a ProgressIndicator, assigns it to the system tray, and binds its properties to the ProgressIndicatorProxy objects properties. The class is shown in the following excerpt:

public class ProgressIndicatorProxy : FrameworkElement
{
    bool loaded;

    public ProgressIndicatorProxy()
    {
        Loaded += OnLoaded;
    }

    void OnLoaded(object sender, RoutedEventArgs e)
    {
        if (loaded)
        {
            return;
        }

        Attach();

        loaded = true;
    }

    public void Attach()
    {
        if (DesignerProperties.IsInDesignTool)
        {
            return;
        }

        var page = this.GetVisualAncestors<PhoneApplicationPage>().First();

        var progressIndicator = SystemTray.ProgressIndicator;
        if (progressIndicator != null)
        {
            return;
        }

        progressIndicator = new ProgressIndicator();

        SystemTray.SetProgressIndicator(page, progressIndicator);

        Binding binding = new Binding("IsIndeterminate") { Source = this };
        BindingOperations.SetBinding(
            progressIndicator, ProgressIndicator.IsIndeterminateProperty, binding);

        binding = new Binding("IsVisible") { Source = this };
        BindingOperations.SetBinding(
            progressIndicator, ProgressIndicator.IsVisibleProperty, binding);

        binding = new Binding("Text") { Source = this };
        BindingOperations.SetBinding(
            progressIndicator, ProgressIndicator.TextProperty, binding);

        binding = new Binding("Value") { Source = this };
        BindingOperations.SetBinding(
            progressIndicator, ProgressIndicator.ValueProperty, binding);
    }

    #region IsIndeterminate

    public static readonly DependencyProperty IsIndeterminateProperty
        = DependencyProperty.RegisterAttached(
            "IsIndeterminate",
            typeof(bool),
            typeof(ProgressIndicatorProxy), new PropertyMetadata(false));

    public bool IsIndeterminate
    {
        get
        {
            return (bool)GetValue(IsIndeterminateProperty);
        }
        set
        {
            SetValue(IsIndeterminateProperty, value);
        }
    }

    #endregion

    #region IsVisible

    public static readonly DependencyProperty IsVisibleProperty
        = DependencyProperty.RegisterAttached(
            "IsVisible",
            typeof(bool),
            typeof(ProgressIndicatorProxy), new PropertyMetadata(true));

    public bool IsVisible
    {
        get
        {
            return (bool)GetValue(IsVisibleProperty);
        }
        set
        {
            SetValue(IsVisibleProperty, value);
        }
    }

    #endregion

    #region Text

    public static readonly DependencyProperty TextProperty
        = DependencyProperty.RegisterAttached(
            "Text",
            typeof(string),
            typeof(ProgressIndicatorProxy), new PropertyMetadata(string.Empty));

    public string Text
    {
        get
        {
            return (string)GetValue(TextProperty);
        }
        set
        {
            SetValue(TextProperty, value);
        }
    }

    #endregion

    #region Value

    public static readonly DependencyProperty ValueProperty
        = DependencyProperty.RegisterAttached(
            "Value",
            typeof(double),
            typeof(ProgressIndicatorProxy), new PropertyMetadata(0.0));

    public double Value
    {
        get
        {
            return (double)GetValue(ValueProperty);
        }
        set
        {
            SetValue(ValueProperty, value);
        }
    }

    #endregion
}

 

The sample code included with this post, contains a viewmodel with three properties, as listed:

  • Indeterminate, a Boolean that provides the IsIndeterminate value of the ProgressIndicator.
  • Progress: a double that is the source property of the Value property of the ProgressIndicator. This takes effect when the ProgressIndicator.IsIndeterminate property is true.
  • Message: a string value displayed via the ProgressIndicator.

The page is bound to an instance of the MainPageViewModel. The ProgressIndicatorProxy binds to the three viewmodel properties. In addition, a ToggleSwitch is used to control the indeterminate state of the ProgressIndicator via the Indeterminate property in the viewmodel, and a Slider controls the ProgressIndicator's Value property in the same manner. See the following excerpt:

<u:ProgressIndicatorProxy IsIndeterminate="{Binding Indeterminate}" 
                            Text="{Binding Message}" 
                            Value="{Binding Progress}" />

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <StackPanel>
        <toolkit:ToggleSwitch 
            IsChecked="{Binding Indeterminate, Mode=TwoWay}" 
            Header="Indeterminate" />

        <Slider Value="{Binding Progress, Mode=TwoWay}"
                Maximum="1" LargeChange=".2" />
    </StackPanel>
</Grid>

 

The sample page is shown in Figure 1.

 

Progress indicator proxy screenshot

Figure 1: ProgressIndicator is controlled via a XAML binding.

 

Note that there is no requirement to use the MVVM infrastructure located in the sample. And that the ProgressIndicatorProxy is entirely independent. I will, however, be releasing Calcium for Windows Phone 7 soon, which contains a cavalcade of useful components for building MVVM apps for WP7.

The custom ProgressIndicatorProxy provides a simple way to harness the new ProgressIndicator from your XAML. I hope you find it useful.

ProgressIndicatorProxyExample.zip (767.78 kb)

 

If you are interested in up-to-the-minute WP7 info, check out the Windows Phone Experts group on LinkedIn.

 

Follow me on twitter

 



A Batch File for Closing Zune and Launching the WPConnect Tool

clock March 24, 2011 17:14 by author Daniel Vaughan

In a post from late last year, I looked at using a .bat file to detect the platform and launch the WPConnect tool using the path appropriate to the OS (32bit or 64 bit).

I've since updated the batch file, which now closes the Zune software, waits a few seconds, and then attempts to use the WPConnect tool. It's not rocket science, but it eases the burden a little when debugging on a Window Phone device.

I had hoped to be able to respond to stdout/err of the WPConnect executable. Seems I couldn't redirect the output to monitor it, and retry the connection if it failed. If you know a work-around, please let me know.

Anyway, without further ado, here's the new batch file.

If you'd prefer to copy and paste; the content of the file is as follows:

 

@ECHO OFF

ECHO (c) Daniel Vaughan 2011 http://danielvaughan.orpius.com

:LoopStart

SET %errorlevel% = 0

taskkill /IM zune.exe
ECHO Waiting for Zune to close...
@choice /T 15 /C y /CS /D y | REM

IF PROCESSOR_ARCHITECTURE == x86 (
    "%ProgramFiles%\Microsoft SDKs\Windows Phone\v7.0\Tools\WPConnect\WPConnect.exe"
) ELSE "%ProgramFiles(x86)%\Microsoft SDKs\Windows Phone\v7.0\Tools\WPConnect\WPConnect.exe"

@choice /T 5 /C y /CS /D y | REM

:LoopEnd

 

If you are interested in up-to-the-minute WP7 info, check out the Windows Phone Experts group on LinkedIn.

 

Follow me on twitter



Order the Book

Ready to take your Windows Phone development skills to the next level? My book is the first comprehensive, start-to-finish developer's guide to Microsoft's Windows Phone 8. In it I teach through complete sample apps that illuminate each key concept with fully explained code and real-world context. Windows Phone 8 Unleashed

Windows Phone Experts Windows Phone Experts
LinkedIn Group

 

Bio

Daniel VaughanDaniel Vaughan is co-founder and president of Outcoder, a Swiss software and consulting company dedicated to creating best-of-breed user experiences and leading-edge back-end solutions, using the Microsoft stack of technologiesin particular WPF, WinRT, and Windows Phone. 

Daniel is a four-time Microsoft MVP for Client Application Development, with experience across a wide range of industries including finance, e-commerce, and digital media. 
Daniel is the author of Windows Phone 7.5 Unleashed and Windows Phone 8 Unleashed, published by SAMS.

Daniel is a Silverlight and WPF Insider, a member of the WPF Disciples, and a member of the Microsoft Developer Guidance Advisory Council.
Daniel also sits on the advisory board of PebbleAge, a Swiss Financial Software company.

While originally from Australia and the UK, Daniel is currently based in Zurich Switzerland. 

Daniel is the developer behind several acclaimed Windows Phone apps including Intellicam and Splashbox; and is the creator of a number of popular open-source projects including the Calcium and Clog.

Daniel also manages the Windows Phone Experts group on LinkedIn; a group that has over 3000 independent developers, Microsoft employees, and Windows Phone enthusiasts.


E-mail Send mail

 

Microsoft MVP logo Disciple
WPF and Silverlight Insiders
 

 

 

Sign in