Silverlight: Cross-domain, but not cross-zone

A colleague approached me to solve a Silverlight issue where a cross-domain web service call was generating a SecurityException.  We checked that clientaccesspolicy.xml was in the correct place and should allow the call and then we ran Fiddler.  What we noticed was that Silverlight was not even attempting the request for the clientaccesspolicy.xml file!

After some investigation and supposition, we eventually traced it down to an issue with Internet Security Zones.  The Silverlight hosting page was being accessed through a fully qualified domain name and was in the Internet zone, while the service was being accessed via computer name and was in the Intranet zone.  The solution was to setup a full DNS entry for the service and use that from our SL application, because then the service host was also in the Internet zone and so the call was allowed.

Now it definitely does make sense that an Internet site should not be able to make cross-domain calls into your Intranet (and kudos to the Silverlight team for taking security this seriously) but it can be a tricky problem to spot when it’s happening in your dev environment!

RX: Detecting the end of a rapid series of events

Storing application state and user preferences is a pretty common problem.  And knowing when to save them can be a tricky problem in a distributed application (such as a Silverlight client) … save too often and you will use too much bandwidth just for saving preferences, save too infrequently or irregularly and users might not get their preferences saved at all.

Now I have a service for holding and saving user preferences, which is a pretty common situation.  It is notified when the saved preferences are dirty (e.g. as the user changes values on a form, say) and it has to decide when to actually collect and save all the values.  Now my service uses the Reactive Framework (RX) internally and Andy (a fellow RX junkie) insisted I post this:

public class UserPreferenceService : IUserPreferenceService
{
    private readonly TimeSpan _cooloffPeriod = TimeSpan.FromSeconds(10);
    private ISubject<string> _changeNotification;
    
    public void PreferencesAreStale()
    {
        _changeNotification.OnNext( null );
    }

    private void BeginListeningToChangeNotifications()
    {
        _changeNotification = new Subject<string>();

        // We apply a timestamp to all changes.  Then we delay these changes and recombine them with the latest changes.
        //      Comparing these timestamps allows us to work out if there have been any subsequent changes during the 
        //      delay period.  We allow some leeway (50ms) in the timestamps, since the two observable stream are delayed
        //      execution and so can get timestamped slightly differently.

        var timestampedChanges = _changeNotification.Timestamp();
        var delayedChanges = timestampedChanges.Delay( _cooloffPeriod );

        timestampedChanges
            .CombineLatest( delayedChanges, ( latest, delayed ) => latest.Timestamp.Subtract( delayed.Timestamp ) )
            .Where( timeDifference => timeDifference.TotalMilliseconds < 50 )
            .Subscribe( _ => PersistPreferences() );
    }

    private void PersistPreferences()
    {
        // Collects and saves preferences
    }
}

 

I think the comments are pretty clear with regard to the implementation details, but the overall result is that preferences get saved 10 seconds after the last update in a rapid series and no sooner.  Updates coming in more frequently than one every 10 seconds do not trigger a save operation.

November 21 2010

An MVVM marquee control (in Silverlight and WPF)

Marquee controls have been around for a long time and have been abused for much of that time.  Their place in the user experience should really be very small, since they have a number of drawbacks – information isn’t static for the user to absorb, they typically only display a limited amount of information and they assume a certain reading speed (which may be too slow or too fast).  Nevertheless, there are times when marquee controls are useful, news or stock tickers for example.

So I needed a marquee to display a news ticker in Silverlight, and I didn’t want to have use any nasty code-behind.  Nothing seemed entirely appropriate, so I used the marquee control from Jobi Joy as a starting point and extended it:

  1. The control needed to work in an MVVM application.  This meant that it mustn't rely on code calling “ticker.StartAnimation()” or anything like that – it had to all work by binding to a view model.
  2. I changed the animation so that there is always as much content visible as possible, i.e. the first bit of content starts at the left-hand side, not at the right-hand side
  3. Just for kicks, I added a little bit of acceleration to the scrolling, so that it is not always a constant speed
  4. I got the marquee working in WPF as well as Silverlight

Some friends contributed here too – Marcin extracted the control template into generic.xaml, and Marlon fixed an issue where the marquee would zoom uncomfortably fast if there was too much content.  The result is that you can just use a few lines of XAML to achieve the effect:

<Controls:Marquee InitialPause="2"
                  FinalPause="2"
                  Duration="5"
                  Acceleration="0"
                  Height="20"
                  Grid.Row="0">
    <ItemsControl ItemsSource="{Binding Headlines}" ItemTemplate="{StaticResource HeadlineTemplate}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" VerticalAlignment="Bottom" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
</Controls:Marquee>

The control template for this uses a ScrollViewer to house a Canvas.  The content to be scrolled is placed on the canvas.

<ScrollViewer Width="Auto"
              Height="Auto"
              BorderThickness="0"
              HorizontalContentAlignment="Stretch"
              VerticalContentAlignment="Stretch"
              VerticalScrollBarVisibility="Disabled"
              Margin="0"
              Padding="0">
    <Canvas>
        <ContentPresenter x:Name="PART_Content"
                          VerticalAlignment="Center"
                          HorizontalAlignment="Center" />
    </Canvas>
</ScrollViewer>

An animation gets calculated and setup to scroll the content from right to left:

Storyboard _storyboard = new Storyboard();
DoubleAnimationUsingKeyFrames _animation = new DoubleAnimationUsingKeyFrames();

double totalDuration = InitialPause + Duration * _contentPart.ActualWidth / ActualWidth;
_animation.Duration = new Duration(TimeSpan.FromSeconds(totalDuration));

// _animation.KeyFrames setup omitted here for clarity. Get the source code if you want it.

_storyboard.Duration = new Duration(TimeSpan.FromSeconds(value + FinalPause));

if (_storyboard.Children.Count == 0)
{
    _storyboard.Children.Add(_animation);
    Storyboard.SetTargetProperty(_animation, new PropertyPath("(Canvas.Left)"));
    Storyboard.SetTarget(_animation, _contentPart);

    _storyboard.RepeatBehavior = RepeatBehavior.Forever;
}

_storyboard.Begin();

The result should show up below, if you have Silverlight 4 installed on your machine.

The full source code and samples in WPF and Silverlight can be found in the SharpFellows Toolkit.  And just for practice I used the Reactive Framework in the sample to asynchronously download and display some news headlines from a website.  Enjoy!

NBehave: Some C# file templates

Here are a couple of templates that I use for getting started writing a new test fixture for C#-based NBehave tests.  Once you drop these into your templates folder (typically under My Documents in “Visual Studio 2010\Templates\ItemTemplates\Visual C#") then you will get the following when you add a new item:

nbehave templates

NBehaveMSTests.zip (1,021.00 bytes)

NBehaveNUnit.zip (992.00 bytes)

July 12 2010
Newer Posts Older Posts