Posts Tagged ‘silverlight’

3
Dec
2010

Watching Silverlight Dependency Properties with Reactive Extensions

by Stuart Harris

At yesterday’s Sliverlight Firestarter, Scott announced that Silverlight 5 will have a DataContextChanged event.  Great news!  How often have you wanted to grab the view model in the code behind and been frustrated by the fact that in Silverlight (unlike WPF) you can’t be easily notified when you have a new view model – you can’t even add your own handler by overriding the DataContext property’s metadata.

So we will wait patiently for Silverlight 5 (and all its other goodness – I was very excited by the 3D demo).  But in the meantime we could use something like Prism’s DependencyPropertyListener or BindingListener.  The former uses the traditional approach of using an attached property (with your own handler) to bind to the dependency property in question.  You have to create a binding, attach and detach it in the right place and hook onto (and off) the listener’s Changed event.  Quite a bit of plumbing.  Prism’s BindingListener sits on top of this and allows you to supply a handler and deal directly with elements and bindings.  All very useful.

But when I want the DataContext, or I just want to know when a dependency property’s value has changed, I really don’t want to dig out a pattern from the recesses of my mind and write a ton of code (which is likely wrong first time) just to be notified when something changes.  It’s gotta be one line of code!  Like this:

this.GetChanges(new Binding()).Subscribe(this.DataContextChanged);

Or if I want to know when the Width of a Canvas changes:

this.GetChanges(new Binding("Width") { Source = this.canvas })    
    .Subscribe(args => Debug.WriteLine(args.NewValue));

Obviously I can create any binding I want and pass it to GetChanges(), which is a simple extension method on FrameworkElement that returns an IObservable of ValueChangedEventArgs.  I can subscribe to this with a handler that will be called each time the binding’s value changes.  The extension method looks like this:

public static IObservable<ValueChangedEventArgs> GetChanges(
    this FrameworkElement element, Binding binding)
{
    return Observable.CreateWithDisposable<ValueChangedEventArgs>(
        observer =>
            {
                var listener = new DependencyPropertyListener();
                return Observable.FromEvent<ValueChangedEventArgs>(
                    handler =>
                        {
                            listener.ValueChanged += handler;
                            listener.Attach(element, binding);
                        }, 
                    handler =>
                        {
                            listener.ValueChanged -= handler;
                            listener.Detach();
                        }).Select(@event => @event.EventArgs).Subscribe(observer);
            });
}

So this is the DependencyPropertyListener that was adopted from Prism:

public class DependencyPropertyListener
{
    private readonly DependencyProperty dependencyProperty;

    private FrameworkElement targetElement;

    public DependencyPropertyListener()
    {
        this.dependencyProperty = DependencyProperty.RegisterAttached(
            Guid.NewGuid().ToString(), 
            typeof(object), 
            typeof(DependencyPropertyListener), 
            new PropertyMetadata(null, this.OnValueChanged));
    }

    public event EventHandler<ValueChangedEventArgs> ValueChanged;

    public void Attach(FrameworkElement target, Binding binding)
    {
        if (target == null)
        {
            throw new ArgumentNullException("target");
        }

        if (binding == null)
        {
            throw new ArgumentNullException("binding");
        }

        this.Detach();
        this.targetElement = target;
        this.targetElement.SetBinding(this.dependencyProperty, binding);
    }

    public void Detach()
    {
        if (this.targetElement != null)
        {
            this.targetElement.ClearValue(this.dependencyProperty);
            this.targetElement = null;
        }
    }

    private void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        EventHandler<ValueChangedEventArgs> handler = this.ValueChanged;
        if (handler != null)
        {
            handler(this, new ValueChangedEventArgs(e.OldValue, e.NewValue));
        }
    }
}

Presumably the System.Windows.DependencyPropertyChangedEventArgs is not derived from EventArgs because it’s a struct for performance reasons.  It’s up to you whether you use that or create your own EventArgs like this:

public class ValueChangedEventArgs : EventArgs
{
    private readonly object newValue;

    private readonly object oldValue;

    public ValueChangedEventArgs(object oldValue, object newValue)
    {
        this.oldValue = oldValue;
        this.newValue = newValue;
    }

    public object NewValue
    {
        get
        {
            return this.newValue;
        }
    }

    public object OldValue
    {
        get
        {
            return this.oldValue;
        }
    }
}

Binding to the Windows Phone 7 Application Bar

The Application Bar in Windows Phone 7 (and its buttons and menu items) are not derived from DependencyObject and so can’t easily participate in data binding.  Using Silverlight 3 behaviours, we can attach functionality to them, however, including bindings for ICommands (with parameters), Text and Icons.

<phone:PhoneApplicationPage.ApplicationBar>
    <shell:ApplicationBar IsVisible="True"
                          IsMenuEnabled="True">
        <shell:ApplicationBarIconButton IconUri="/Images/appbar.add.rest.png"
                                        Text="Add" />
        <shell:ApplicationBarIconButton IconUri="/Images/appbar.delete.rest.png"
                                        Text="Delete" />
        <shell:ApplicationBar.MenuItems>
            <shell:ApplicationBarMenuItem Text="MenuItem 1" />
            <shell:ApplicationBarMenuItem Text="MenuItem 2" />
        </shell:ApplicationBar.MenuItems>
    </shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

<i:Interaction.Behaviors>
    <Behaviors:ApplicationBarIconButtonCommand TextKey="Add"
                                               CommandBinding="{Binding Path=AddCommand}"
                                               TextBinding="{Binding Source={StaticResource LocalizedStrings}, Path=LocalizedResources.Add}"
                                               IconBinding="{Binding Path=AddIcon}" />
    <Behaviors:ApplicationBarIconButtonCommand TextKey="Delete"
                                               CommandBinding="{Binding Path=DeleteCommand}"
                                               TextBinding="{Binding Source={StaticResource LocalizedStrings}, Path=LocalizedResources.Delete}" />
</i:Interaction.Behaviors>

I’ve attached a sample project that demonstrates binding to the Application Bar buttons.  There are behaviours for binding Prism’s DelegateCommand to the app bar buttons (and menu items) and to regular buttons and other FrameworkElements.  I haven’t included the full Prism source (just the bits needed to run the sample).  Also there is no IoC container so the MainViewModel is instantiated in App.xaml for this.

Enjoy!

Source Code (Visual Studio 2010 sample solution, built against Build 2787 of Reactive Extensions for WP7):

AppBarBinding.zip (44.42 kb)

20
Aug
2010

Hosting XNA within Silverlight on Windows Phone 7 and why you shouldn’t do it

by David Wynne

When anyone starts working with XNA, it doesn’t take too long before they get fed up of dividing vectors by the viewport width and ask whether it’s possible to use the goodness of the WPF/Silverlight layout system to do their 2D stuff and the power of XNA to do the 3D stuff.  The answer is invariably “well, kinda… not really”.  Many have tried, some have had limited success and Microsoft have generally said “it’s something we want to do”.

With the imminent release of Windows Phone 7 the question has never been more relevant – a platform on which you can only develop in Silverlight or XNA.

By far the best implementation of rendering XNA within a WPF app we’ve seen, is that detailed in Nick Gravelyn’s blog post: Rendering with XNA Framework 4.0 inside of a WPF application.  We really liked the pure approach he’d taken and decided to try the same thing on WP7 with Silverlight.  With a few alterations (largely around getting hold of a handle with which to create a Graphics Device) we got it working.  Magic.

So why not do it?  Put simply, it will fail Market Place Ingestion.  If your Silverlight application uses anything from the Microsoft.Xna.Framework.Game or Microsoft.Xna.Framework.Graphics assemblies your app will automatically fail Ingestion.  (As a side note, if your XNA app uses anything from the System.Windows.Controls namespace, you’re also in for ingestion failure.)

So what now?  Back to dividing vectors?  Well here at Red Badger we’ve been busily working away on a new layout system for XNA called XPF.  Expect more announcements soon, but needless to say if you’re longing for some familiar controls like a Grid or a ScrollViewer in XNA – watch this space…

@dwynne