Daniel Vaughan

free range code

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

 



Loading Data when the User Scrolls to the End of a List in Windows Phone 7

clock January 24, 2011 22:18 by author Daniel Vaughan

Most phone users are concerned about network usage. Network traffic comes at a premium, and a user's perception of the quality of your app depends a lot on its responsiveness. When it comes to fetching data from a network service, it should be done in the most efficient manner possible. Making the user wait while your app downloads giant reams of data doesn't cut it. It should, instead, be done in bite-sized chunks.

To make this easy for you, I have created a ScrollViewerMonitor which uses an attached property to monitor a ListBox and fetch data as the user needs it. It's as simple as adding an attached property to a control which contains a ScrollViewer, such as a ListBox, as shown in the following example:

<ListBox ItemsSource="{Binding Items}"
         u:ScrollViewerMonitor.AtEndCommand="{Binding FetchMoreDataCommand}" />

Notice the AtEndCommand. That's an attached property that allows you to specify a command to be executed when the user scrolls to the end of the list. Easy huh! I'll explain in a moment how this is accomplished, but first some background.

Background

For almost the last year, I've been building infrastructure for WP7 development. A lot has been going into the book I am writing, and even more is making its way into the upcoming Calcium for Windows Phone. I am pretty much at bursting point; wanting to get this stuff out there.

The chapter of Windows Phone 7 Unleashed, which discusses this code, demonstrates an Ebay search app that makes use of the Ebay OData feed (see Figure 1). It's simple, yet shows off some really nice techniques for handling asynchronous network calls.

Figure 1: The Ebay Seach app from Windows Phone 7 Unleashed.

 

The Ebay app isn't in the downloadable code for this post. But there is a simpler app that displays a list of numbers instead.

The way the ScrollViewerMonitor works is by retrieving the first child ScrollViewer control from its target (a ListBox in this case). It then listens to its VerticalOffset property for changes. When a change occurs, and the ScrollableHeight of the scrollViewer is the same as the VerticalOffset, the AtEndCommand is executed.

 

public class ScrollViewerMonitor
{
    public static DependencyProperty AtEndCommandProperty
        = DependencyProperty.RegisterAttached(
            "AtEndCommand"typeof(ICommand),
            typeof(ScrollViewerMonitor),
            new PropertyMetadata(OnAtEndCommandChanged));

    public static ICommand GetAtEndCommand(DependencyObject obj)
    {
        return (ICommand)obj.GetValue(AtEndCommandProperty);
    }

    public static void SetAtEndCommand(DependencyObject obj, ICommand value)
    {
        obj.SetValue(AtEndCommandProperty, value);
    }


    public static void OnAtEndCommandChanged(
        DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        FrameworkElement element = (FrameworkElement)d;
        if (element != null)
        {
            element.Loaded -= element_Loaded;
            element.Loaded += element_Loaded;
        }
    }

    static void element_Loaded(object sender, RoutedEventArgs e)
    {
        FrameworkElement element = (FrameworkElement)sender;
        element.Loaded -= element_Loaded;
        ScrollViewer scrollViewer = FindChildOfType<ScrollViewer>(element);
        if (scrollViewer == null)
        {
            throw new InvalidOperationException("ScrollViewer not found.");
        }

        var listener = new DependencyPropertyListener();
        listener.Changed
            += delegate
            {
                bool atBottom = scrollViewer.VerticalOffset
                                    >= scrollViewer.ScrollableHeight;

                if (atBottom)
                {
                    var atEnd = GetAtEndCommand(element);
                    if (atEnd != null)
                    {
            atEnd.Execute(null);
                    }                   
                }
            };
        Binding binding = new Binding("VerticalOffset") { Source = scrollViewer };
        listener.Attach(scrollViewer, binding);
    }

    static T FindChildOfType<T>(DependencyObject root) where T : class
    {
        var queue = new Queue<DependencyObject>();
        queue.Enqueue(root);

        while (queue.Count > 0)
        {
            DependencyObject current = queue.Dequeue();
            for (int i = VisualTreeHelper.GetChildrenCount(current) - 1; 0 <= i; i--)
            {
                var child = VisualTreeHelper.GetChild(current, i);
                var typedChild = child as T;
                if (typedChild != null)
                {
                    return typedChild;
                }
                queue.Enqueue(child);
            }
        }
        return null;
    }
}

 

Of course there is a little hocus pocus that goes on behind the scenes. The VerticalOffset property is a dependency property, and to monitor it for changes I've borrowed some of Pete Blois's code, which allows us to track any dependency property for changes. This class is called BindingListener and is in the downloadable sample code.

Sample Code

The ViewModel for the MainPage contains a FetchMoreDataCommand. When executed, this command sets a Busy flag, and waits a little while, then adds some more items to the ObservableCollection that the ListBox in the view is data-bound too.

Snippet

public class MainPageViewModel : INotifyPropertyChanged
{
    public MainPageViewModel()
    {
        AddMoreItems();

        fetchMoreDataCommand = new DelegateCommand(
            obj =>
                {
                    if (busy)
                    {
                        return;
                    }
                    Busy = true;
                    ThreadPool.QueueUserWorkItem(
                        delegate
                        {
                            /* This is just to demonstrate a slow operation. */
                            Thread.Sleep(3000);
                            /* We invoke back to the UI thread. 
                                * Ordinarily this would be done 
                                * by the Calcium infrastructure automatically. */
                            Deployment.Current.Dispatcher.BeginInvoke(
                                delegate
                                {
                                    AddMoreItems();
                                    Busy = false;
                                });
                        });
                    
            });
    }

    void AddMoreItems()
    {
        int start = items.Count;
        int end = start + 10;
        for (int i = start; i < end; i++)
        {
            items.Add("Item " + i);
        }
    }

    readonly DelegateCommand fetchMoreDataCommand;

    public ICommand FetchMoreDataCommand
    {
        get
        {
            return fetchMoreDataCommand;
        }
    }

    readonly ObservableCollection<string> items = new ObservableCollection<string>();

    public ObservableCollection<string> Items
    {
        get
        {
            return items;
        }
    }

    bool busy;

    public bool Busy
    {
        get
        {
            return busy;
        }
        set
        {
            if (busy == value)
            {
                return;
            }
            busy = value;
            OnPropertyChanged(new PropertyChangedEventArgs("Busy"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        var tempEvent = PropertyChanged;
        if (tempEvent != null)
        {
            tempEvent(this, e);
        }
    }
}

 

There's a lot more infrastructure provided with the book code. But I tried hard to slim everything down for this post. The MainPage.xaml contains a Grid with a ProgressBar, whose visbility depends on the Busy property of the viewmodel.

Snippet

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <ListBox ItemsSource="{Binding Items}"
                u:ScrollViewerMonitor.AtEndCommand="{Binding FetchMoreDataCommand}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <Image Source="Images/WindowsPhoneExpertsLogo.jpg" 
                            Margin="10" />
                    <TextBlock Text="{Binding}" 
                                Style="{StaticResource PhoneTextTitle2Style}"/>                            
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <Grid Grid.Row="1"
            Visibility="{Binding Busy, 
                Converter={StaticResource BooleanToVisibilityConverter}}">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <TextBlock Text="Loading..." 
                    Style="{StaticResource LoadingStyle}"/>
        <ProgressBar IsIndeterminate="{Binding Busy}"
                        VerticalAlignment="Bottom"
                        Grid.Row="1" />
    </Grid>
</Grid>

 

You may be wondering why there is a databinding for ProgressBar's IsIndeterminate property. This is for performance reasons, as when indeterminate the ProgressBar is notorious for consuming CPU. Check out Jeff Wilcox's blog for a solution.

Now, when the user scrolls to the bottom of the list, the FetchMoreDataCommand is executed, providing an opportunity to call some network service asynchronously (see Figure 2).

 

 

Figure 2: Loading message is displayed when the user scrolls to the end of the list.

 

I hope you enjoyed this post, and that you find the attached code useful.

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

 

DanielVaughan.ScrollViewerMonitor.zip (126.56 kb)

 

Follow me on twitter



ReaderWriterLockSlim: Conquering Mismatched Enter and Exit Calls

clock August 14, 2010 13:43 by author Daniel Vaughan

The ReaderWriterLockSlim class is used to protect a resource that is read by multiple threads and written to by one thread at a time. The class exists in the desktop FCL, but is noticeably absent from the Silverlight FCL. To readily support both platforms, some time ago, I incorporated the open-source mono implementation of the ReaderWriterLockSlim class into the Silverlight version of my core library, which is downloadable from http://calcium.codeplex.com/SourceControl/list/changesets

ReaderWriterLockSlim is a light-weight alternative to the Monitor class, for providing for concurrency. I say light-weight because the Monitor class only provides for exclusive access; where only a single thread can enter, regardless of the kind of operation.

The Monitor class, however, has an advantage: its syntax can be simplified using the lock statement, as shown in the following code snippet:

System.Object resourceLock = new System.Object();
System.Threading.Monitor.Enter(resourceLock);
try
{
DoSomething();
}
finally
{
System.Threading.Monitor.Exit(resourceLock);
}

 

Which is equivalent to the following, when using a lock statement:

lock (x)
{
DoSomething();
}

 

Using the lock statement means that we never get caught out forgetting to exit the lock, which could lead to a thread being blocked indefinitely.

No such baked-in infrastructure exists for the ReaderWriterLockSlim. So, I've created a number of extension methods to simulate the lock statement for the ReaderWriterLockSlim.

Using Extension Methods to Simulate Lock Syntax

If you've used the ReaderWriterLockSlim a lot, you'll know that mismatching Enter and Exit calls can be easy to do, especially when pasting code. For example, in the following excerpt we see how a call to enter a write protected section of code is mismatched with a call to exit a read section:

ReaderWriterLockSlim lockSlim = new ReaderWriterLockSlim();

try
{
lockSlim.EnterWriteLock();
DoSomething();
}
finally
{
lockSlim.ExitReadLock();
}

 

This code will result in a System.Threading. SynchronizationLockException being raised.

The extension methods that have been written, allow a Func or an Action to be supplied, which will be performed within a try/finally block. The previous excerpt can be rewritten more concisely as:

ReaderWriterLockSlim lockSlim = new ReaderWriterLockSlim();
lockSlim.PerformUsingWriteLock(() => DoSomething);

 

In the downloadable code I have included a unit test to demonstrate how the ReaderWriterLockSlim extension methods are used, (see Listing 1).

Listing 1: LockSlimTests Class

[TestClass]
public class LockSlimTests : SilverlightTest
{
readonly static List<string> sharedList = new List<string>();

[TestMethod]
public void ExtensionsShouldPerformActions()
{
ReaderWriterLockSlim lockSlim = new ReaderWriterLockSlim();

string item1 = "test";

// Rather than this code:
// try
// {
// lockSlim.EnterWriteLock();
// sharedList.Add(item1);
// }
// finally
// {
// lockSlim.ExitWriteLock();
// }
// We can write this one liner:
lockSlim.PerformUsingWriteLock(() => sharedList.Add(item1));

// Rather than this code:
// string result;
// try
// {
// lockSlim.EnterReadLock();
// result = sharedList[0];
// }
// finally
// {
// lockSlim.ExitReadLock();
// }
// We can write this one liner:
string result = lockSlim.PerformUsingReadLock(() => sharedList[0]);

Assert.AreEqual(item1, result);

string item2 = "test2";

// Rather than this code:
// try
// {
// lockSlim.EnterUpgradeableReadLock();
// if (!sharedList.Contains(item2))
// {
// try
// {
// lockSlim.EnterWriteLock();
// sharedList.Add(item2);
// }
// finally
// {
// lockSlim.ExitWriteLock();
// }
// }
// }
// finally
// {
// lockSlim.ExitUpgradeableReadLock();
// }
// We can write this:
lockSlim.PerformUsingUpgradeableReadLock(() =>
{
if (!sharedList.Contains(item2))
{
lockSlim.PerformUsingWriteLock(() => sharedList.Add(item2));
}
});

// Rather than this code:
// try
// {
// lockSlim.EnterReadLock();
// result = sharedList[1];
// }
// finally
// {
// lockSlim.ExitReadLock();
// }
// We can write this:
result = lockSlim.PerformUsingReadLock(() => sharedList[1]);

Assert.AreEqual(item2, result);
}

}

 

The result of executing this test is shown in Figure 1.

 

Figure 1: Result of running the ReaderWriterLockSlimExtension tests.

 

The ReaderWriterLockSlimExtensions accept a simple Action or a Func to return value, and take care of calling the appropriate Enter and Exit methods, inside a try/finally block, (see Listing 2).

Listing 2: ReaderWriterLockSlimExtensions Class

public static class ReaderWriterLockSlimExtensions
{
public static void PerformUsingReadLock(this ReaderWriterLockSlim readerWriterLockSlim, Action action)
{
ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
ArgumentValidator.AssertNotNull(action, "action");
try
{
readerWriterLockSlim.EnterReadLock();
action();
}
finally
{
readerWriterLockSlim.ExitReadLock();
}
}

public static T PerformUsingReadLock<T>(this ReaderWriterLockSlim readerWriterLockSlim, Func<T> action)
{
ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
ArgumentValidator.AssertNotNull(action, "action");
try
{
readerWriterLockSlim.EnterReadLock();
return action();
}
finally
{
readerWriterLockSlim.ExitReadLock();
}
}

public static void PerformUsingWriteLock(this ReaderWriterLockSlim readerWriterLockSlim, Action action)
{
ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
ArgumentValidator.AssertNotNull(action, "action");
try
{
readerWriterLockSlim.EnterWriteLock();
action();
}
finally
{
readerWriterLockSlim.ExitWriteLock();
}
}

public static T PerformUsingWriteLock<T>(this ReaderWriterLockSlim readerWriterLockSlim, Func<T> action)
{
ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
ArgumentValidator.AssertNotNull(action, "action");
try
{
readerWriterLockSlim.EnterWriteLock();
return action();
}
finally
{
readerWriterLockSlim.ExitWriteLock();
}
}

public static void PerformUsingUpgradeableReadLock(this ReaderWriterLockSlim readerWriterLockSlim, Action action)
{
ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
ArgumentValidator.AssertNotNull(action, "action");
try
{
readerWriterLockSlim.EnterUpgradeableReadLock();
action();
}
finally
{
readerWriterLockSlim.ExitUpgradeableReadLock();
}
}

public static T PerformUsingUpgradeableReadLock<T>(this ReaderWriterLockSlim readerWriterLockSlim, Func<T> action)
{
ArgumentValidator.AssertNotNull(readerWriterLockSlim, "readerWriterLockSlim");
ArgumentValidator.AssertNotNull(action, "action");
try
{
readerWriterLockSlim.EnterUpgradeableReadLock();
return action();
}
finally
{
readerWriterLockSlim.ExitUpgradeableReadLock();
}
}
}

 

The ArgumentValidator class is present in my base library. Calls to its AssertNotNull can be replaced with a null check, and if null throw an ArgumentNullException. If you'd like the code for the ArgumentValidator etc., you can find it in the Core class library in the source available at http://calcium.codeplex.com/SourceControl/list/changesets

Conclusion

In this post we have seen how extension methods can be used to ensure that the ReaderWriterLockSlim class is correctly exited after a thread critical region. This avoids the problem of mismatched Enter and Exit calls, which can result in exceptions and indefinite blocking.

I hope you have enjoyed this post, and that you find the code and ideas presented within it useful.

 

Download code: ReaderWriterLockSlimExtensions.zip (1.14 mb)



Enforcing Single Instance WPF Applications

clock August 1, 2010 17:39 by author Daniel Vaughan

Introduction

Today the WPF Disciples, and in particular my good friend and fellow WPF Disciple, Pete O'Hanlon, were sitting around the proverbial campfire, discussing how to enforce single instance WPF apps, for Pete's cool Goldlight project. By single instance WPF apps, I mean limiting an executable to only one instance in execution. This can be useful in scenarios where multiple application instances may play havoc with shared state. I took some time away from writing my book, to see if I could come up with something usable.

Building a Single Instance Application Enforcer

The singleton application model works like this:

  1. User starts app1.
  2. User starts app2.
  3. App2 detects app1 is running.
  4. App2 quits.

 

There is, however, a second part to our challenge, as Pete pointed out. What happens if we wish to pass some information from app2 to app1 before app2 quits? If, for example, the application is associated with a particular file type, and the user happens to double click on a file of that type, then we would have app2 tell app1 what file the user was trying to open.

To accomplish this we need a means to communicate between the two application instances. There are a number of approaches that could be taken, and some include:

  • Named pipes
  • Sending a message to the main application's window with a native API call
  • MemoryMappedFile

I chose to go for the MemoryMappedFile, along with an EventWaitHandle. The consensus by the Disciples was for a Mutex (not an EventWaitHandle), but the Mutex turned out not to provide for the initial signaling that I needed. I have encapsulated the logic for the singleton application enforcement, into a class called SingletonApplicationEnforcer (see Listing 1). The class instantiates the EventWaitHandle, and informs the garbage collector via the GC.KeepAlive method, that it should not be garbage collected. If this is the only application that has instantiated the EventWaitHandle with the specified name, then the createdNew argument will be set to true. This is how we determine, if the application is the singleton application.

Listing 1: SingletonApplicationEnforcer Class

/// <summary>
/// This class allows restricting the number of executables in execution, to one.
/// </summary>
public sealed class SingletonApplicationEnforcer
{
    readonly Action<IEnumerable<string>> processArgsFunc;
    readonly string applicationId;
    Thread thread;
    string argDelimiter = "_;;_";

    /// <summary>
    /// Gets or sets the string that is used to join 
    /// the string array of arguments in memory.
    /// </summary>
    /// <value>The arg delimeter.</value>
    public string ArgDelimeter
    {
        get
        {
            return argDelimiter;
        }
        set
        {
            argDelimiter = value;
        }
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="SingletonApplicationEnforcer"/> class.
    /// </summary>
    /// <param name="processArgsFunc">A handler for processing command line args 
    /// when they are received from another application instance.</param>
    /// <param name="applicationId">The application id used 
    /// for naming the <seealso cref="EventWaitHandle"/>.</param>
    public SingletonApplicationEnforcer(Action<IEnumerable<string>> processArgsFunc, 
        string applicationId = "DisciplesRock")
    {
        if (processArgsFunc == null)
        {
            throw new ArgumentNullException("processArgsFunc");
        }
        this.processArgsFunc = processArgsFunc;
        this.applicationId = applicationId;
    }

    /// <summary>
    /// Determines if this application instance is not the singleton instance.
    /// If this application is not the singleton, then it should exit.
    /// </summary>
    /// <returns><c>true</c> if the application should shutdown, 
    /// otherwise <c>false</c>.</returns>
    public bool ShouldApplicationExit()
    {
        bool createdNew;
        string argsWaitHandleName = "ArgsWaitHandle_" + applicationId;
        string memoryFileName = "ArgFile_" + applicationId;

        EventWaitHandle argsWaitHandle = new EventWaitHandle(
            false, EventResetMode.AutoReset, argsWaitHandleName, out createdNew);

        GC.KeepAlive(argsWaitHandle);

        if (createdNew)
        {
            /* This is the main, or singleton application. 
                * A thread is created to service the MemoryMappedFile. 
                * We repeatedly examine this file each time the argsWaitHandle 
                * is Set by a non-singleton application instance. */
            thread = new Thread(() =>
                {
                    try
                    {
                        using (MemoryMappedFile file = MemoryMappedFile.CreateOrOpen(memoryFileName, 10000))
                        {
                            while (true)
                            {
                                argsWaitHandle.WaitOne();
                                using (MemoryMappedViewStream stream = file.CreateViewStream())
                                {
                                    var reader = new BinaryReader(stream);
                                    string args;
                                    try
                                    {
                                        args = reader.ReadString();
                                    }
                                    catch (Exception ex)
                                    {
                                        Debug.WriteLine("Unable to retrieve string. " + ex);
                                        continue;
                                    }
                                    string[] argsSplit = args.Split(new string[] { argDelimiter }, 
                                                                    StringSplitOptions.RemoveEmptyEntries);
                                    processArgsFunc(argsSplit);
                                }

                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Debug.WriteLine("Unable to monitor memory file. " + ex);
                    }
                });

            thread.IsBackground = true;
            thread.Start();
        }
        else
        {
            /* Non singleton application instance. 
                * Should exit, after passing command line args to singleton process, 
                * via the MemoryMappedFile. */
            using (MemoryMappedFile mmf = MemoryMappedFile.OpenExisting(memoryFileName))
            {
                using (MemoryMappedViewStream stream = mmf.CreateViewStream())
                {
                    var writer = new BinaryWriter(stream);
                    string[] args = Environment.GetCommandLineArgs();
                    string joined = string.Join(argDelimiter, args);
                    writer.Write(joined);
                }
            }
            argsWaitHandle.Set();
        }

        return !createdNew;
    }
}

If the process happens to be the singleton application, then a new thread is started that will block until it receives a signal (via the argsWaitHandle). This signal indicates that the MemoryMappedFile contains data to be read. It is non-singleton applications instances that perform this signalling, via the argsWaitHandle.Set method, after the string arguments have been written to the MemoryMappedFile.

Demonstrating the SingletonApplicationEnforcer Class

The downloadable code includes two solutions, and two projects. Each use the SingletonApplicationEnforcer class in their respective App (App.xaml.cs) classes. To try out the sample, open both solutions. Start debuging the SingleApp project first, and then launch the SingleApp2 project. What will hopefully result is that the SingleApp2 project will detect that it is not the singleton application, and it will write its command line arguments to a MemoryMappedFile. The SingleApp application will detect that data has been written to the file, and present the command line arguments in its main window (see Figure 1).

Figure 1: The demo application consists of a single window, which displays received command line arguments.

 

The entry point for either projects is the App class. It is in this class that we consume the SingletonApplicationEnforcer class, to detect whether the application should be allowed to execute (see Listing 2). The App classes constructor uses the SingletonApplicationEnforcer's ShouldApplicationExit method; which, as we saw in Listing 1, uses an EventWaitHandle to determine if it is the only instance in execution. If it isn't then the method returns true, and the application is explicitly shutdown.

Listing 2: App Class

/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
    readonly SingletonApplicationEnforcer enforcer = new SingletonApplicationEnforcer(DisplayArgs);

    public App()
    {
        if (enforcer.ShouldApplicationExit())
        {
            this.Shutdown();
        }
    }

    public static void DisplayArgs(IEnumerable<string> args)
    {
        foreach (var arg in args)
        {
            string message = string.Format("Received arg: {0}", arg);
            Debug.WriteLine(message);
        }
            
        var dispatcher = Current.Dispatcher;
        if (dispatcher.CheckAccess())
        {
            ShowArgs(args);
        }
        else
        {
            dispatcher.BeginInvoke(
                new Action(delegate
                {
                    ShowArgs(args);
                }));
        }
    }

    static void ShowArgs(IEnumerable<string> args)
    {
        var mainWindow = Current.MainWindow as MainWindow;
        if (mainWindow != null && args != null)
        {
            foreach (var arg in args)
            {
                mainWindow.ViewModel.Args.Add(arg);
            }
        }
    }

}

As usual, this application uses the MVVM pattern. The MainWindow has its DataContext property set to an instance of the MainWindowViewModel (see Listing 3).

Listing 3: MainWindow XAML

<Window x:Class="SingleApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Singleton Application Enforcer Example" 
        Height="350" Width="525" ResizeMode="NoResize" Background="Black">
    <StackPanel>
        <Image Source="Images/DisciplesBackground.jpg" />
        <StackPanel Margin="10">
            <TextBlock Text="Received Args:" FontSize="16" Padding="10" Foreground="White"/>
            <ListBox ItemsSource="{Binding Args}" 
                     VerticalAlignment="Stretch" Height="185" />
        </StackPanel>
    </StackPanel>
</Window>

The viewmodel (MainWindowViewModel), shown in Listing 2, exposes an ObsertableCollection of strings, that reflect arguments that are passed to the application, from other application instances.

Listing 4: MainWindowViewModel

public class MainWindowViewModel : INotifyPropertyChanged
{
    static ObservableCollection<string> args = new ObservableCollection<string>();

    public ObservableCollection<string> Args
    {
        get
        {
            return args;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string propertyName)
    {
        var temp = PropertyChanged;
        if (temp != null)
        {
            temp(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}


Conclusion

In this post we have seen how a MemoryMappedFile can be used in conjunction with a EventWaitHandle, to provide for cross process communication in order to limit execution to a single application instance. We also saw how to communicate command line arguments to the singleton application, so that it can respond adequately to user intent.

I hope you enjoyed this post, and that you find the code and ideas presented here useful.

Download code: SingletonEnforcementV2.zip (345.05 kb)



ViewModel Active Awareness in a Prism Based Application

clock February 5, 2010 15:13 by author Daniel Vaughan

Yesterday, while chatting with the highly talented Jeremiah Morrill and other WPF Disciples about some MVVM subtleties (for the full post see here), Jeremiah briefly touched on the topic of providing ViewModels with the awareness of being active or inactive within a Prism based application. I wanted to explore this further, and decided to integrate this functionality into Calcium. What I provide here isn't rocket science, and merely serves to illustrate one of indeed many design approaches that could be applied to accomplish the same thing.

For this I had two goals. The first, to provide the capability without coupling the ViewModel to the View. That is, without requiring the ViewModel to have a reference to the View. The second, to not depend on a base class for the functionality; forever tying the developer to my base class implementation (ViewModelBase). So, indeed, I chose an interface based approach. To be Prism-esque I have adapted Jeremiah's approach which was to implement Prism's IActiveAware interface on my base view class. I then feed an intermediary object to the ViewModel via an interface named IViewAware. The intermediary object is an instance of ActiveAwareUIElementAdapter. This class is used to provide a UIElement instance with Prisms IActiveAware interface. It does so by monitoring its Got and LostFocus events.

 

ActiveAwareUIElementAdapter

 

/// <summary>
/// Wraps a <see cref="UIElement"/> to provide an <see cref="IActiveAware"/>
/// implementation based on its focus state.
/// </summary>
public class ActiveAwareUIElementAdapter : IActiveAware
{
    bool active;

    public ActiveAwareUIElementAdapter(UIElement uiElement)
    {
        ArgumentValidator.AssertNotNull(uiElement, "uiElement");
        uiElement.GotFocus += OnGotFocus;
        uiElement.LostFocus += OnLostFocus;
    }

    void OnLostFocus(object sender, RoutedEventArgs e)
    {
        IsActive = false;
    }

    void OnGotFocus(object sender, RoutedEventArgs e)
    {
        IsActive = true;
    }

    public bool IsActive
    {
        get
        {
            return active;
        }
        set
        {
            if (active != value)
            {
                active = value;
            }
            OnIsActiveChanged(EventArgs.Empty);
        }
    }

    #region event IsActiveChanged

    event EventHandler isActiveChanged;

    public event EventHandler IsActiveChanged
    {
        add
        {
            isActiveChanged += value;
        }
        remove
        {
            isActiveChanged -= value;
        }
    }

    protected void OnIsActiveChanged(EventArgs e)
    {
        if (isActiveChanged != null)
        {
            isActiveChanged(this, e);
        }
    }

    #endregion
}

We then use this class within any IView UIElement implementation, but in particular the base ViewControl class. We instantiate the ActiveAwareUIElement adapter within the view's constructor, and pass it the instance of the view itself. The ActiveAwareUIElement then simply subscribes to the GotFocus and LostFocus events of the view, which is of course a UIElement.

 

ViewControl Implementation

 

/// <summary>
/// The base class for <see cref="IView"/>s.
/// </summary>
public class ViewControl : UserControl, IView, IActiveAware /* (not abstract for Blendability) */
{
    #region ViewModel Dependency Property

    public static DependencyProperty ViewModelProperty = DependencyProperty.Register(
        "ViewModel", typeof(IViewModel), typeof(ViewControl), new PropertyMetadata(null, OnViewModelChanged));

    static void OnViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var viewControl = (ViewControl)d;
        viewControl.SetViewAwareAssociations((IViewModel)e.OldValue, (IViewModel)e.NewValue);
    }

    [Description("The view model for this view.")]
#if !SILVERLIGHT
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
#endif
    public IViewModel ViewModel
    {
        get
        {
            return (IViewModel)GetValue(ViewModelProperty);
        }
        set
        {
            SetValue(ViewModelProperty, value);
        }
    }

    #endregion

    /// <summary>
    /// Initializes a new instance of the <see cref="ViewControl"/> class.
    /// </summary>
    public ViewControl()
    {
        Loaded += OnLoaded;
        activeAwareUIElementAdapter = new ActiveAwareUIElementAdapter(this); 
    }

    bool alreadyLoaded;

    void OnLoaded(object sender, RoutedEventArgs e)
    {
        if (!alreadyLoaded)
        {
            alreadyLoaded = true;
            OnViewLoaded(e);
        }
    }

    #region ViewLoaded event

    event EventHandler<EventArgs> viewLoaded;

    /// <summary>
    /// Occurs when the view has been loaded.
    /// </summary>
    public event EventHandler<EventArgs> ViewLoaded
    {
        add
        {
            viewLoaded += value;
        }
        remove
        {
            viewLoaded -= value;
        }
    }

    /// <summary>
    /// Closes the view.
    /// </summary>
    /// <param name="force">if set to <c>true</c> the control will be forced
    /// to close even if e.g., there is unsaved data and the user chooses 
    /// to cancel the closure.</param>
    /// <returns></returns>
    public virtual bool Close(bool force)
    {
        var viewService = ServiceLocatorSingleton.Instance.GetInstance<IViewService>();
        return viewService.CloseView(this, force);
    }

    /// <summary>
    /// Raises the <see cref="E:ViewLoaded"/> event.
    /// </summary>
    /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
    protected void OnViewLoaded(EventArgs e)
    {
        if (viewLoaded != null)
        {
            viewLoaded(this, e);
        }
    }
    #endregion

    /// <summary>
    /// Gets a value indicating whether the control is in a designer.
    /// </summary>
    /// <value><c>true</c> if design time; otherwise, <c>false</c>.</value>
    protected bool DesignTime
    {
        get
        {
            return DesignerProperties.GetIsInDesignMode(this);
        }
    }

    #region IActiveAware and related

    void SetViewAwareAssociations(IViewModel oldViewModel, IViewModel newViewModel)
    {
        var oldViewAware = oldViewModel as IViewAware;
        var newViewAware = newViewModel as IViewAware;
        if (oldViewAware != null)
        {
            oldViewAware.DetachActiveAware();
        }

        if (newViewAware != null)
        {
            newViewAware.Attach(activeAwareUIElementAdapter);
        }
    }

    readonly ActiveAwareUIElementAdapter activeAwareUIElementAdapter;

    bool IActiveAware.IsActive
    {
        get
        {
            return activeAwareUIElementAdapter.IsActive;
        }
        set
        {
            activeAwareUIElementAdapter.IsActive = value;
        }
    }

    event EventHandler IActiveAware.IsActiveChanged
    {
        add
        {
            activeAwareUIElementAdapter.IsActiveChanged += value;
        }
        remove
        {
            activeAwareUIElementAdapter.IsActiveChanged -= value;
        }
    }

    #endregion
}

We see that the dependency property ViewModel, when changed, prompts the attachment of the ActiveAwareUIElement instance to the ViewModel. The mechanism for performing this is via the IViewAware implementation. If an IViewModel wishes to be aware of its view's state, in particular when it becomes active or inactive; without having to have a direct reference to the view, then it can implement the IViewAware interface.

 

IViewAware Interface


/// <summary>
/// Provides for advanced presentation behaviour in a <see cref="IViewModel"/>s.
/// </summary>
public interface IViewAware
{
    /// <summary>
    /// Attaches the specified active aware instance so that changes in the <see cref="IActiveAware.IsActive"/>
    /// state can be monitored.
    /// </summary>
    /// <param name="activeAware">The active aware.</param>
    void Attach(IActiveAware activeAware);

    /// <summary>
    /// Detaches the active aware instance. Changes in the <see cref="IActiveAware.IsActive"/>
    /// state will no longer be monitored.
    /// </summary>
    void DetachActiveAware();
}

The ViewModel base class implementation is provided next in full:

/// <summary>
/// A base implementation of the <see cref="IViewModel"/> interface.
/// </summary>
public abstract class ViewModelBase : IViewModel, INotifyPropertyChanged, IViewAware
{
    IActiveAware activeAwareInstance;

    protected ViewModelBase()
    {
        notifier = new PropertyChangeNotifier(this);
    }

    #region Title Property

    object title;

    [Description("The text to display on a tab.")]
#if !SILVERLIGHT
    [Browsable(true)]
    [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
#endif        
    public object Title
    {
        get
        {
            return title;
        }
        set
        {
            notifier.Assign("Title", ref title, value);
        }
    }

    #endregion

    #region Property Change Notification
    readonly PropertyChangeNotifier notifier;

    protected PropertyChangeNotifier Notifier
    {
        get
        {
            return notifier;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged
    {
        add
        {
            notifier.PropertyChanged += value;
        }
        remove
        {
            notifier.PropertyChanged -= value;
        }
    }

    protected AssignmentResult Assign<TProperty>(
        string propertyName, ref TProperty property, TProperty newValue)
    {
        return notifier.Assign(propertyName, ref property, newValue);
    }

    #endregion

    #region Active Aware

    void IViewAware.Attach(IActiveAware activeAware)
    {
        ReplaceActiveAware(activeAware);
    }

    void IViewAware.DetachActiveAware()
    {
        ReplaceActiveAware(null);
    }

    void ReplaceActiveAware(IActiveAware activeAwareInstance)
    {
        if (this.activeAwareInstance != null)
        {
            this.activeAwareInstance.IsActiveChanged -= OnIsActiveChanged;
        }
        this.activeAwareInstance = activeAwareInstance;
        if (activeAwareInstance != null)
        {
            activeAwareInstance.IsActiveChanged += OnIsActiveChanged;
        }
    }

    bool lastActiveState;

    void OnIsActiveChanged(object sender, EventArgs e)
    {
        Notifier.NotifyChanged("Active", lastActiveState, Active);
        lastActiveState = Active;
    }

    /// <summary>
    /// Gets a value indicating whether this instance is being notified 
    /// of when it becomes active or inactive, 
    /// this may occur for example when its view gains focus or loses focus.
    /// </summary>
    /// <value><c>true</c> if monitoring the active state 
    /// of its view; otherwise, <c>false</c>.</value>
    public bool ActiveAware
    {
        get
        {
            return activeAwareInstance != null;
        }
    }

    /// <summary>
    /// Gets a value indicating whether this <see cref="ViewModelBase"/> 
    /// is active within the user interface.
    /// </summary>
    /// <value><c>true</c> if active; otherwise, <c>false</c>.</value>
    public bool Active
    {
        get
        {
            return activeAwareInstance != null ? activeAwareInstance.IsActive : false;
        }
    }

    #endregion

    public override string ToString()
    {
        return title != null ? title.ToString() : base.ToString();
    }
}

So there it is. Just one way to provide a ViewModel with active awareness. Please be aware that this code is preliminary and may be subject to change. The full source code will be available via the Calcium source download page soon.

 

Thanks to Kent Boogaart for his post on MVVM Infrastructure ActiveAwareCommand which the ActiveAwareUIElementAdapter was inspired from.



Synchronous Invocation of Delegates with the Silverlight Dispatcher

clock January 10, 2010 18:14 by author Daniel Vaughan

Introduction

In this post I would like to briefly discuss the System.Windows.Threading.Dispatcher class, and the significant differences between its Silverlight and Desktop CLR implementations. We are going to look at solving two things:

  1. Consuming the UI’s Dispatcher in Silverlight before a page has been instanciated.
  2. Allowing for synchronous invocation of delegates on the UI thread.

Background

Recently my good friend Sacha Barber published an article, and in the comments of which we briefly touched on a cross threading issue that we have both experienced with the Silverlight Dispatcher class. I thought it was about time that I wrote some of this stuff up. This is the result.

Silverlight Thread Affinity

When working with Silverlight, one has to contend with the usual single threaded apartment model (STA) that is also present when working with WPF or Windows Forms. This means that one must interact with UI components, in particular DependencyObject derived types, from the thread in which they were created on. Fortunately Silverlight/WPF/Windows Forms includes infrastructure that makes acquiring and invoking calls on the UI thread simpler; specifically the System.Windows.Threading.Dispatcher, which is a prioritized message loop that handles thread affinity.

There is an excellent article describing the Dispatcher in detail.

Consuming the UI’s Dispatcher

In Silverlight a Dispatcher becomes associated with the main page during initialization, thereby making it available via the Applications RootVisual property like so:

Application.Current.RootVisual.Dispatcher

We can consume the Dispatcher this way, as long as we do so after the RootVisual has been defined. But in the case where we would like to consume the Dispatcher from the get-go, it leaves us out in the cold. Fortunately though, the Silverlight Dispatcher instance is also available via the System.Windows.Deployment.Current.Dispatcher property. This instance is defined when the Application starts, thereby making it possible to commence asynchronous operations before the first page is instanciated.

Synchronous Invocation of Delegates on the UI Thread

The Silverlight Dispatcher is geared for asynchronous operations. As we can see from the following image, unlike the Desktop CLR Dispatcher, the Silverlight Dispatcher class’s Invoke method overloads have internal visibility.

It has to be said that the Desktop CLR Dispatcher, when compared with the Silverlight version, as with many other classes, has a much richer API. In order to provide a means to synchronously invoke a delegate on the UI thread we need another approach. The approach I have taken is to utilize the System.Windows.Threading.DispatcherSynchronizationContext

By using the Post and Send methods of the DispatcherSynchronizationContext we are able to regain the synchronous Invoke capabilities within the Silverlight environment.

I have rolled this up into a set of reusable classes, located in my core Silverlight library, which you can find in the DanielVaughan.Silverlight project in the Calcium http://www.calciumsdk.net download.

/// <summary>
/// Singleton class providing the default implementation 
/// for the <see cref="ISynchronizationContext"/>, specifically for the UI thread.
/// </summary>
public class UISynchronizationContext : ISynchronizationContext
{
    DispatcherSynchronizationContext context;
    Dispatcher dispatcher;
    
    #region Singleton implementation

    static readonly UISynchronizationContext instance = new UISynchronizationContext();
    
    /// <summary>
    /// Gets the singleton instance.
    /// </summary>
    /// <value>The singleton instance.</value>
    public static ISynchronizationContext Instance
    {
        get
        {
            return instance;
        }
    }

    #endregion

    public void Initialize()
    {
        EnsureInitialized();
    }

    readonly object initializationLock = new object();

    void EnsureInitialized()
    {
        if (dispatcher != null && context != null)
        {
            return;
        }

        lock (initializationLock)
        {
            if (dispatcher != null && context != null)
            {
                return;
            }

            try
            {
                dispatcher = Deployment.Current.Dispatcher;
                context = new DispatcherSynchronizationContext(dispatcher);
            }
            catch (InvalidOperationException)
            {
                /* TODO: Make localizable resource. */
                throw new ConcurrencyException("Initialised called from non-UI thread."); 
            }
        }
    }

    public void Initialize(Dispatcher dispatcher)
    {
        ArgumentValidator.AssertNotNull(dispatcher, "dispatcher");
        lock (initializationLock)
        {
            this.dispatcher = dispatcher;
            context = new DispatcherSynchronizationContext(dispatcher);
        }
    }

    public void InvokeAsynchronously(SendOrPostCallback callback, object state)
    {
        ArgumentValidator.AssertNotNull(callback, "callback");
        EnsureInitialized();

        context.Post(callback, state);
    }

    public void InvokeAsynchronously(Action action)
    {
        ArgumentValidator.AssertNotNull(action, "action");
        EnsureInitialized();

        if (dispatcher.CheckAccess())
        {
            action();
        }
        else
        {
            dispatcher.BeginInvoke(action);
        }
    }

    public void InvokeSynchronously(SendOrPostCallback callback, object state)
    {
        ArgumentValidator.AssertNotNull(callback, "callback");
        EnsureInitialized();

        context.Send(callback, state);
    }

    public void InvokeSynchronously(Action action)
    {
        ArgumentValidator.AssertNotNull(action, "action");
        EnsureInitialized();

        if (dispatcher.CheckAccess())
        {
            action();
        }
        else
        {
            context.Send(delegate { action(); }, null);
        }
    }

    public bool InvokeRequired
    {
        get
        {
            EnsureInitialized();
            return !dispatcher.CheckAccess();
        }
    }
}

A further advantage of using either a Silverlight or Desktop CLR implementation of the ISynchronizationContext is that we are able to write CLR agnostic code. That is, code that was written for the Desktop CLR can be easily moved to the Silverlight.

Using the code:

UISynchronizationContext.Instance.InvokeSynchronously(delegate
                                {
/* Code to execute on the UI thread. */
                                });

Conclusion

In this post we have looked at consuming the UI’s Dispatcher in Silverlight as soon as an Application starts. We also saw how it is possible in Silverlight to accomplish synchronous invocation of delegates on the UI thread.

The full source shown in this article is available on the Calcium Codeplex site

 

 

 



Using T4 to Generate Pack URIs for XAML Files

clock November 25, 2009 15:25 by author Daniel Vaughan

Yesterday my fellow WPF Disciple Paul Stovell got me thinking about resolving XAML file paths.

As Paul points out, there doesn't appear to be an easy way to locate the URI for a XAML file. Internally, the generated .g.cs makes use of the path, as shown in the following excerpt:

public void InitializeComponent() 
{ 
  if (_contentLoaded) 
  { 
    return; 
  } 
  _contentLoaded = true; 
  System.Uri resourceLocater = new System.Uri("/PageCollection;component/pages/page1.xaml", System.UriKind.Relative); 
  #line 1 "..\..\..\Pages\Page1.xaml" 
  System.Windows.Application.LoadComponent(this, resourceLocater); 
  #line default 
  #line hidden 
}

But, how can we get our hands on it? What I’ve done is to incorporate the generation of XAML resource pack URIs into the T4 template I did a little while ago.

To demonstrate I have created a dummy UserControl in a subfolder in the sample application.

Image Figure: Dummy UserControl has a pack URI generated

 

The resulting output from the T4 template now enables us to determine the path to the XAML file in a safe way. The following excerpt shows the generated Pack URI:

namespace CSharpDesktopClrDemo.XamlMetadata.Folder1.Folder2.Metadata
{
    /// <summary>Metadata for XAML UserControl1.xaml</summary>
    public static class UserControl1XamlMetadata
    {
            /// <summary>Resource pack URI for XAML file.</summary>
            public const string XamlPackUri 
= @"/DanielVaughan.MetaGen.Demo;component/Folder1/Folder2/UserControl1.xaml"; } }

Now we have this, we can write:

Uri uri = new Uri(CSharpDesktopClrDemo.XamlMetadata.Folder1.Folder2.Metadata
                 .UserControl1XamlMetadata.XamlPackUri, UriKind.Relative);
var control = System.Windows.Application.LoadComponent(uri) 
       as DanielVaughan.MetaGen.Demo.Folder1.Folder2.UserControl1;

No more magic string pack URIs!

Download the template and sample application: MetaGen_01_04.zip (393.35 kb)

 



Compile-Time Validation of Composite Object Data Binding Expressions

clock November 7, 2009 18:06 by author Daniel Vaughan

Introduction

Prompted by a recent comment on the T4 Metadata Generation template article, which I released some weeks ago, I have implemented a new mechanism for concatenating property paths. This allows compile time validation of properties that exist on composite or nested members.

Background

Previously I have demonstrated how generated metadata can be used to provide compile-time validation of binding expressions. Rather than using string literals in binding expressions, one is able to use the x:Static markup extension and a T4 generated constant to indicate the binding path; as shown in the following excerpt.

<Label Content="{Binding Path={x:Static Metadata:PersonMetadata.NamePath}}"/>

Overcoming Limitations

This approach works fine when targeting a property from a single instance in a DataContext, but what happens when we wish to target a nested instance’s property? For example, and as demonstrated in the downloadable sample from the article mentioned above, if we have a ListBox populated with Person instances, and we wish to bind a label to the listbox’s SelectedItem.Address.StreetAddress property, we can do so using the following XAML:

<ListBox x:Name="listBox" Background="Black">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <StackPanel Orientation="Horizontal">
        <Label Content="{Binding Path={x:Static Metadata:PersonMetadata.NamePath}}"/>
      </StackPanel>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>
<Label Content="{Binding ElementName=listBox, 
    Path={Demo:JoinPath 
                SelectedItem, 
                {x:Static Metadata:PersonMetadata.Address}, 
                {x:Static Metadata:AddressMetadata.StreetLine}}}"/>

Here we see a custom MarkupExtension called JoinPathExtension is used to enable the concatenation of path strings to create a PropertyPath that is used to target the nested Address instance. In this case, the string values of ‘SelectedItem’, ‘Address’, and ‘StreetLine’ combine to produce a PropertyPath ‘SelectedItem.Address.StreetLine’.

You will notice, when you open the CS Window1.xaml file in the sample download, that errors are reported for the Path expressions. These don’t prevent the designer from loading in either Visual Studio or Blend. They are, however, annoying.

 

Diagram: Visual Studio Xaml designer errors.

Attempting to resolve this issue I switched to using named arguments. No luck there either I’m afraid, with the x:Static expression resulting in a compile time error:

(Unknown property 'Converter' for type 'MS.Internal.Markup.MarkupExtensionParser+UnknownMarkupExtension' encountered while parsing a Markup Extension. Line x position Y)

My fellow disciple Philipp Sumi has a great post outlining the VS designer bug. 

I have experimented with a number of approaches, including (as Philipp suggests) explicit property syntax, and have settled on the one shown above.

The main parts of the JoinPathExtension are shown:

CS:

/// <summary>
/// Allows a set of property path strings to be concatenates 
/// into a <see cref="PropertyPath"/> instance.
/// </summary>
[MarkupExtensionReturnType(typeof(PropertyPath))]
public class JoinPathExtension : MarkupExtension
{
  readonly List<string> members = new List<string>(); 
 
  public JoinPathExtension()
  {
    /* Intentionally left blank. */
  }
 
  public JoinPathExtension(string member0)
  {
    if (member0 == null)
    {
      throw new ArgumentNullException("member0");
    }
    members.Add(member0);
  }
 
  public JoinPathExtension(string member0, string member1)
    : this(member0)
  {
    if (member1 == null)
    {
      throw new ArgumentNullException("member1");
    }
    members.Add(member1);
  }
 
  public override object ProvideValue(IServiceProvider serviceProvider)
  {
    var path = string.Join(".", members.ToArray());
    var result = new PropertyPath(path);
    return result;
  }
 
  void SetMember(int index, string value)
  {
    if (value == null)
    {
      throw new ArgumentNullException("value");
    }
    if (members.Count < index + 1)
    {
      members.Add(value);
      return;
    }
    members[index] = value;
  }
 
  #region Named member properties
  [ConstructorArgument("member0")]
  public string Member0
  {
    get
    {
      return members[0];
    }
    set
    {
      SetMember(0, value);
    }
  }
 
  public string Member1
  {
    get
    {
      return members[1];
    }
    set
    {
      SetMember(1, value);
    }
  }
 
}

VB.NET:

Imports System.Windows.Markup

Public Class JoinPathExtension
    Inherits MarkupExtension
    ' Methods
    Public Sub New()
        Me.members = New List(Of String)
    End Sub

    Public Sub New(ByVal memberList As String())
        Me.members = New List(Of String)
        If (memberList Is Nothing) Then
            Throw New ArgumentNullException("memberList")
        End If
        Me.members.AddRange(memberList)
    End Sub

    Public Sub New(ByVal member1 As String)
        Me.members = New List(Of String)
        If (member1 Is Nothing) Then
            Throw New ArgumentNullException("member1")
        End If
        Me.members.Add(member1)
    End Sub

    Public Sub New(ByVal member1 As String, ByVal member2 As String)
        Me.New(member1)
        If (member2 Is Nothing) Then
            Throw New ArgumentNullException("member2")
        End If
        Me.members.Add(member2)
    End Sub

    Public Overrides Function ProvideValue(ByVal serviceProvider As IServiceProvider) As Object
        Return New PropertyPath(String.Join(".", Me.members.ToArray), New Object(0 - 1) {})
    End Function


    ' Properties
    <ConstructorArgument("member1")> _
    Public Property Member() As String
        Get
            Return Me.members.Item(0)
        End Get
        Set(ByVal value As String)
            If (value Is Nothing) Then
                Throw New ArgumentNullException("value")
            End If
            If (Me.members.Count < 1) Then
                Me.members.Add(value)
            Else
                Me.members.Item(0) = value
            End If
        End Set
    End Property

    <ConstructorArgument("member2")> _
    Public Property Member2() As String
        Get
            Return Me.members.Item(1)
        End Get
        Set(ByVal value As String)
            If (value Is Nothing) Then
                Throw New ArgumentNullException("value")
            End If
            If (Me.members.Count < 2) Then
                Me.members.Add(value)
            Else
                Me.members.Item(1) = value
            End If
        End Set
    End Property


    ' Fields
    Private ReadOnly members As List(Of String)
End Class

Conclusion

We have seen how by using a custom MarkupExtension we are able to concatenate generated property name constants to produce PropertyPaths, which can be consumed by Path binding expressions. Having the capability to join path expression adds a lot to the flexibility of the generated metadata approach. We are now able to fully express property paths for nested objects in binding expressions, without resorting to string literals; increasing dramatically the flexibility of this approach.

Download the sample code from here.

 

 



Calling Web Services from Silverlight as the Browser is Closed

clock October 19, 2009 23:07 by author Daniel Vaughan

Introduction

Today I was reading an excellent post by my fellow Disciple Laurent Bugnion, which led on to a short discussion about performing actions after a user attempts to close a browser window. It got me thinking about the capability to dispatch a web service call in Silverlight just after a user attempts to close the browser window or navigate elsewhere. I have been asked the question before, yet before now, have not attempted to answer it. So today I decided to do some experimenting.

There are two things I wanted to look at. Firstly, I wanted to allow a web service to be called after the Silverlight application’s Exit event is raised. Secondly, I wanted to provide the Silverlight application with the opportunity to cancel, or at least interrupt the close window process.

In the first scenario I found the way I could achieve the call after the Silverlight applications Exit event was raised, was to call a JavaScript method from Silverlight, and then finally a PageMethod; to perform the housekeeping.

 

Figure: A web service is called after the user closes the browser.

We see that in our App.xaml.cs the Exit event handler is called, which then calls a JavaScript function, as demonstrated in the following excerpt:

void Application_Exit(object sender, EventArgs e)
{
    HtmlPage.Window.Invoke("NotifyWebserviceOnClose", 
          new[] { guid.ToString() });
}

We then call a PageMethod on the page hosting the application like so:

function NotifyWebserviceOnClose(identifier) {
    PageMethods.SignOff(identifier, OnSignOffComplete);            
}

The PageMethod is where we are able to update a list of connected clients, or do whatever takes our fancy.

[WebMethod]
[System.Web.Script.Services.ScriptMethod] 
public static void SignOff(string identifier)
{
    /* Update your list of signed in users here etc. */
    System.Diagnostics.Debug.WriteLine("*** Signing Off: " + identifier);
}

Caveat lector- According to Laurent this is not reliable. So, you will need to test it for yourself. I’ve tested it locally in Firefox 3.5 and IE8. But, your results may differ.

Now the second thing I wanted to look at was the ability to provide some interaction with the user, either cancelling or calling a web service, when the user attempts to close the browser; but before the browser is actually closed.

The way I did this was to place an onbeforeunload handler in the body tag of the page, as shown:

<body onbeforeunload="OnClose()">

I then created the OnClose handler in a JavaScript script block as shown in the following excerpt:

function OnClose() {           
    var plugin = document.getElementById("silverlightControl");
    var shutdownManager = plugin.content.ShutdownManager;
    var shutdownResult = shutdownManager.Shutdown();
    if (shutdownResult) {
        event.returnValue = shutdownResult;
    }
}

Here we see that we retrieve the Silverlight application and resolve an instance of the ShutdownManager class present in the Silverlight App class. The ShutdownManager is a class that is able to perform some arbitrary duty when the application is closing. It is made accessible to the host webpage by registering it with a call to RegisterScriptableObject.

void Application_Startup(object sender, StartupEventArgs e)
{
    HtmlPage.RegisterScriptableObject("ShutdownManager", shutdownManager);
    this.RootVisual = new MainPage();
}

ShutdownManager

The ShutdownManager is decorated with two attributes that allow it to be consumed by an external source. They are SciptableType and ScriptableMember. As we see below, they are used to allow the ShutdownManager class to be called via Ajax.

[ScriptableType]
public class ShutdownManager
{
    [ScriptableMember]
    public string Shutdown()
    {
        string result = null;
        var page = (MainPage)Application.Current.RootVisual;

        if (page.Dirty)
        {
            var messageBoxResult = MessageBox.Show(
                "Save changes you have made?", "Save changes?", MessageBoxButton.OKCancel);
            if (messageBoxResult == MessageBoxResult.OK)
            {
                var waitingWindow = new WaitingWindow();
                waitingWindow.Show();

                waitingWindow.NoticeText = "Saving work on server. Please wait...";
                page.SetNotice("Saving work on server. Please wait...");

                var client = new ShutdownServiceClient();
                client.SaveWorkCompleted += ((sender, e) =>
                    {
                        waitingWindow.NoticeText = "It is now safe to close this window.";
                        page.SetNotice("It is now safe to close this window.");
                        page.Dirty = false;
                        waitingWindow.Close();
                    });
                client.SaveWorkAsync("Test id");
                result = "Saving changes.";
            }
            else
            {
                result = "If you close this window you will lose any unsaved work.";
            }
        }

        return result;
    }
}

Here we see that once the Shutdown method is called we test if the main (Silverlight) page is dirty. If so, we prompt the user to save changes. If changes are to be saved we dispatch our async web service call using a service client. The key thing to note here is that we are returning a string value if the page is deemed dirty. This string value then indicates to the consuming JavaScript code that the window should not be closed immediately. Once the call makes it back to our JavaScript onbeforeload handler, we assign the event.returnValue the value of this string. If this value is not an empty string it will cause the web browser to display a dialog; asking the user whether they really wish to leave the page.

Figure: Browser prompts with ‘Are you sure ...’ message.

In the demo application accompanying this post, you will notice that we simulate a user modification. This is done by ticking the Page dirty checkbox.

 

Figure: The demonstration application simulates a modification to the data model.

Unticked, closing the browser will result in the window closing immediately. However, ticked will cause the presentation of a Save Changes dialog, as shown below.

Figure: Save changes dialog prompts user.

What happens if the user cancels the operation? Remember our event.returnValue string in the JavaScript OnClose function. If the user cancels, then this value is assigned a string value of “If you close this window you will lose any unsaved work.” We can see how the browser chooses to display the string shown below:

Figure: User is prompted with browser initiated dialog.

Obviously we must deal with when the user selects the nominal Ok button in the save dialog. To provide a somewhat more agreeable user experience, I have dropped in a Silverlight ChildWindow control, with a ProgressBar control for good measure.

Figure: A progress bar is presented to the user while saving.

Once the user hits Ok on the Save Changes dialog, that web service call is dispatched almost immediately. In order for the web service call to occur though, we must perform interrupt the thread so that our Silverlight App has a chance to dispatch the call. We can do that with a JavaScript alert call, or as we see here, we assign the event.returnValue, which causes a dialog to be displayed in much the same manner.

Conclusion

In this post we have seen how it is possible to call a web service after a Silverlight App’s Exit event has been raised. While this may not be reliable, I’d be interested to know your experience with this approach, and certainly of any alternate approaches. Finally we looked at interacting with the user, to allow cancellation of a close window event or to perform last minute web service calls. This was achieved using the onbeforeunload event and a JavaScript handler.

Thank you for reading.

Download the sample (557.06 kb)



Banishing String Literals from XAML Resource References

clock October 3, 2009 19:15 by author Daniel Vaughan

Introduction

Since my initial experimentation with generating project metadata data using T4 (Text Template Transformation Toolkit), there have been several obvious opportunities to expand its scope. One such opportunity has been to use T4 to generate static properties representing XAML keys. This serves to reduce the reliance on string literals when referencing resources. I have subsequently augmented my MetadataGeneration.tt template to do just that.

x:Key Property Generation

To demonstrate, I have updated the sample application provided with my previous article, and employed a couple ResourceDictionaries to show how we can reference a ‘default’ dictionary using constant names, and also how we can cross reference with an auxiliary ResourceDictionary, overriding the resources using constant name values.

In the following excerpt we see a button that has its Background defined using a Resource whose key is defined as a static property in a generated class.

<Button 
Background="{StaticResource {x:Static Keys:MainDictionaryXamlMetadata.ButtonBackgroundKey}}"
Margin
="0,5,0,0" Content="Change" HorizontalAlignment="Left" Click="Button_ChangeClick"/>

This is useful, because it means if we modify the name of the background brush in the ResourceDictionary and forget to update references to it, we will be alerted at compile time, rather than at runtime.

The MetadataGeneration.tt template scours your project looking for XAML files, and then generates classes for them containing all x:Key attributes, represented as static properties. As we can see in the following excerpt, that the ButtonBackGround key is defined as a LinearGradientBrush in the MainDictionary.xaml.

MainDictionary.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <LinearGradientBrush x:Key="ButtonBackground">
        <GradientStop Color="AliceBlue" Offset="0" />
        <GradientStop Color="Yellow" Offset=".7" />
    </LinearGradientBrush>
    <SolidColorBrush x:Key="WindowForegroundBrush" Color="White"/>
</ResourceDictionary>

Being able to reference one ResourceDictionary from another is useful. If we take another ResourceDictionary, which redefines the resources of the first, we are able to do so in a safer way; expressing our intent with a dedicated property, and using the non-literal string key names derived from the MainDictionary.xaml.

SecondaryDictionary.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Metadata="clr-namespace:CSharpDesktopClrDemo.XamlMetadata.Folder1.Metadata">
    <LinearGradientBrush x:Key="{x:Static Metadata:MainDictionaryXamlMetadata.ButtonBackgroundKey}">
        <GradientStop Color="AliceBlue" Offset="0" />
        <GradientStop Color="Blue" Offset=".7" />
    </LinearGradientBrush>
    <SolidColorBrush x:Key="{x:Static Metadata:MainDictionaryXamlMetadata.WindowForegroundBrushKey}" Color="Azure"/>
</ResourceDictionary>

So, we can define our resources wherever we like; in a separate assembly for example, yet we still retain compile time validation of resource key references.

App.xaml

<Application x:Class="DanielVaughan.MetaGen.Demo.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml">
    <Application.Resources>
        <ResourceDictionary Source="pack://application:,,,/DanielVaughan.MetaGen.Demo;component/Folder1/MainDictionary.xaml"/>
        <!--<ResourceDictionary Source="pack://application:,,,/DanielVaughan.MetaGen.Demo;component/Folder1/SecondaryDictionary.xaml"/>-->
    </Application.Resources>
</Application>

Implementation

To accomplish the discovery of XAML files and associated Keys, and the subsequent generation of metadata classes, during project traversal we must do two things: detect when the project item is a XAML file, and keep a track of the current project directory. Now accomplishing the first is easy. Detecting when the current project item is a project folder, on the other hand, turned out to be hack-worthy, as you will notice in the following excerpt.

string processingDirectory = string.Empty;

public void ProcessProjectItem(ProjectItem projectItem,
    Dictionary<string, NamespaceBuilder> namespaceBuilders, string activeNamespace)
{
    FileCodeModel fileCodeModel = projectItem.FileCodeModel;

    if (fileCodeModel != null)
    {
        foreach (CodeElement codeElement in fileCodeModel.CodeElements)
        {
            WalkElements(codeElement, null, null, namespaceBuilders);
        }
    }
    
    string activeNamespaceCopy = activeNamespace;
    if (string.IsNullOrEmpty(activeNamespaceCopy))
    {
        if (string.IsNullOrEmpty(xamlRootNamespace))
        {
            activeNamespaceCopy = rootNamespace; 
        }
        else
        {
            activeNamespaceCopy = string.Format("{0}.{1}", 
                rootNamespace, xamlRootNamespace);
        }
    }
    
    if (projectItem.ProjectItems != null 
        && projectItem.ProjectItems.Count > 0)
    {
        /* This is a hack to determine if we have a directory.
            If you know the proper way for doing this, please let me know. */
        try
        {
            var foo = projectItem.Document;
        }
        catch (Exception ex)
        {
            string newNamespace = projectItem.Name.Replace(" ", string.Empty); 
            activeNamespaceCopy += "." + newNamespace; 
        }
    }
    
    string itemName = projectItem.Name; 
    if (generateXamlKeys && itemName.EndsWith(".xaml", true, CultureInfo.InvariantCulture))
    {    
        /* Retrieve or create the namespace builder. */
        NamespaceBuilder namespaceBuilder;

        if (!namespaceBuilders.TryGetValue(activeNamespaceCopy, out namespaceBuilder))
        {
            namespaceBuilder = new NamespaceBuilder(activeNamespaceCopy, null, 0);
            namespaceBuilders[activeNamespaceCopy] = namespaceBuilder;
        }
        
        string fileName = projectItem.get_FileNames(0);
        string text = System.IO.File.ReadAllText(fileName);
        MatchCollection matches = xClassRegex.Matches(text);                

        if (matches.Count > 0)
        {
            string xamlMetadataClassName = ConvertProjectItemNameToTypeOrMemberName(itemName.Substring(0, itemName.Length - 4));                
            var classComments = new List<string> {string.Format("/// <summary>Metadata for XAML {0}</summary>", itemName)};
            XamlBuilder xamlBuiler = new XamlBuilder(xamlMetadataClassName, classComments, 1);
            namespaceBuilder.AddChild(xamlBuiler);
            
            foreach (Match match in matches)
            {
                Group keyGroup = match.Groups["KeyName"];
                string keyName = keyGroup.Value;
                var keyComments = new List<string> {string.Format("/// <summary>Represents x:Key=\"{0}\"/></summary>", keyName)};
                xamlBuiler.AddChild(new XamlKeyBuilder(keyName, keyComments));
            }
        }
    }

    if (projectItem.ProjectItems != null)
    {
        foreach (ProjectItem childItem in projectItem.ProjectItems)
        {
            ProcessProjectItem(childItem, namespaceBuilders, activeNamespaceCopy);
        }
    }
}

We see that generating XAML metadata works in the same way as the class and interface metadata generation, in that we represent the XAML file using a XamlBuilder, and keys within the XAML file are represented as XamlKeyBuilders.

Generating Namespaces for XAML Metadata Classes

To avoid collisions with type names and generated namespace, I offer a customizable xamlRootNamespace configuration variable. This variable is used to construct namespace names for generated XAML metadata classes as the following example illustrates:

If we have a XAML file called Window1.xaml. It will be represented by a class named [generatedClassPrefix]Window1[generatedXamlClassSuffix][generatedClassSuffix]

Conclusion

We have seen how XAML Resource keys, ordinarily referenced using magic strings, can be eliminated using generated Type and File metadata.

I am still rather pleased at what one is able to achieve by combining T4 and the DTE. Visual Studio 2010 will see T4 move to a more visible position within the IDE. This, together with the new features of T4 in VS2010, will surely make it an indispensible tool.

To download the template source and demo applications, please visit the updated T4 Metadata article on Codeproject.

 




Windows Phone Experts Windows Phone Experts
LinkedIn Group

 

About the author

Daniel VaughanDaniel Vaughan is a Microsoft MVP for Client Application Development, with a decade of commercial experience across a wide range of industries including finance, e-commerce, and multimedia. While originally from Australia and the UK, Daniel is currently based in Geneva Switzerland; consulting on Windows Phone 7, WPF, Silverlight, WCF, and WF. Daniel is a Silverlight and WPF Insider, a member of the WPF Disciples, and a CodeProject MVP. Daniel is currently writing Windows Phone 7.5 Unleashed, which is due out in early 2011. Daniel is also the creator of a number of open-source projects, including Calcium, and Clog. E-mail me Send mail

 

Microsoft MVP logo Disciple
CodeProject MVP
WPF and Silverlight Insiders

 

 

Books

Order Windows Phone 7 Unleashed

RecentComments

Comment RSS

Sign in