Oct 19 2011

Jumping through hoops with the JumpViewer

Windows 8^HDeveloper Preview is out, yay !

 

And with it, comes a whole lot of new toys to play with : Visual Studio 11, Blend 5, but most important : the Metro Ui goodness is also available for desktop developers to play with !

And along with new shiny Ui’s come new paradigms, new API’s, and new User controls.

The one we’re going to have a look today is the JumpViewer : a new control that works a little bit like a Master-Detail view, only there is only one view shown at once, and the user can Switch back and forth by tapping master items and “zoom-pinching out” the detail view.

Okay, enough for the concept, after all, there is a whole lot of videos around from the latest Build conference : What we are interested in is how we will actually code an app that uses our new toy.

The usual way to go is to take microsoft’s examples, look how they’ve done it, mimic, copy, paste, adapt, smile, and voilà : you know everything about your new friend.

Only this time, I wasn’t exactly thrilled by the way Microsoft had set up their example :

For those who don’t know the JumpViewer : there are two views : one called JumpView, the other ContentView.

In microsoft’s example, which you can find here, the  ContentView’s ItemsSource was bound to a CollectionViewSource, using a regular data binding, but the JumpView’s – the master, if you will – was simply not even set. A little bit of investigation will show that the ItemSource property is set in the codebehind, and in my book, that spells code smell.

So, from there, how would we make it MVVM friendly ?

My first attempt was to try to use the exact same binding on the JumpView. It required creating a Template for the Group items, and collapse the Items themselves. Unfortunately, it seems the internals of the JumpViewer control bases its navigation between the two views on the collectionView’s CollectionGroups. To make it simple : the item clicked in the JumpView must be the group of the ContentView, in order to navigate to it.

Therefore, using the same binding for both views would not expose such hierarchy, and even though the visual result would be OK, the navigation would not work.

The second attempt was to edit the binding to provide an additional Path in the JumpView’s binding in order to try an reach the CollectionGroups, but for some reason, the CollectionGroups was never reached. Adding a converter to allow us to set a breakpoint in the middle of the binding was also a failure : The breakpoint was never hit, meaning that the binding could not reach the CollectionGroups.

Reverting to the same binding as in the ContentView with the DebuggerConverter still applied to the binding would show that the passed value, the CollectionViewSource, was a Windows Runtime object. In other words : a COM object. I can only guess that the CollectionGroups was lost in the marshalling of the system object.

The third and last approach was to use a ValueConverter for the JumpView’s binding : since the CollectionGroups property was not reachable through a binding, but was reachable, after an explicit cast in C#, it was then a no-brainer : we could use a ValueConverter to join the dots and return the CollectionGroups property that was not accessible with a plain binding. The converter would then look like this:

publicclassGroupedCollectionToGroupsCollectionConverter : IValueConverter

 

{

 

publicobject Convert(object value, string typeName, object parameter, string language)

 

{

 

return ((ICollectionView)(value)).CollectionGroups;

}

 

       publicobject ConvertBack(object value, string typeName, object parameter, string language)

       {

           thrownewNotImplementedException();

 

        }

}

 


Apr 10 2011

NavigationService in Silverlight gets in the way of Dependency Injection scenarios

Today, I was working on a Windows Phone 7 application, and I really wanted to do things properly, with nice dependency injections in order expose all my dependencies. And by the time I tried to navigate from one page to an other, I realized that the NavigationService in Windows Phone 7 and Silverlight ( as of version 4.0 ) was simply not satisfying.

Why is it so bad ? because, unlike in WPF, there is no way to use the NavigationService to Navigate to an instance of a page : we can only specify an URI to navigate to.
What would that change, one might ask ?
Well, it may seem like nothing to some, but for those out there who are very fond of Dependency Injection (DI) this is really a painful restriction :

let’s see : what can we do by navigating to an instance of a page that we can’t do by just passing the URI to the NavigationService ?

well, for one, we can instantiate the page ourselves and not rely on the NavigationService to instantiate it for us.
If we control the Page creation, we can pass any argument we please to its constructor, Including a view model for instance.

And if we can inject it, we can mock it.
And if we can mock it, we can test the rest of our code properly.

And perhaps most importantly from an architectural point of view, we can clearly communicate the dependencies our page relies on, but more on that later.

I can already hear some people claiming we could always use a view model locator, but in my humble opinion, a view model locator is not a first-class solution to this problem.

The reason why I think so is that using a locator (or an IoC resolution for that matters) to retrieve a resource needed within the class will hide the fact that we are dependent on this resource. If someone forgets to register a view model prior to using it, the application will crash as soon (or as-late, might I say) as it is resolved.
If we use Dependency Injection, we will not even be able to compile the project : if we forget to feed a dependency, that’s how soon the problem should be highlighted, and that’s why it is so important to communicate clearly our dependencies.

… Come on Microsoft, show us some love and give us a decent NavigationService.


Mar 19 2011

The age of stream

Allright, on the menu today, we have Streams as a main course.

While working on open syno one of the big challenge was to figure out how I could render an audio file, that is, read a stream, while writing to it.

First, you might try to have a look at the WebClient class, only to be disappointed, since the OpenReadAsync method’s behavior depends on the AllowReadStreamBuffering : if buffering is allowed, then the OpenReadAsync method will notify it got the job done only once the whole file has been downloaded (or “buffered”). And if buffering is not allowed, the notification will be raised right away, without even reading a single byte… and that part of the job will be left to us. That means we might as well use HttpWebRequests and deal with the download ourselves, since we’ll have to face the dreadful “You-Read-While-I-Write” problem anyway.

So, where are we now ?

  1. We cannot leave the hard work of downloading the file to the WebClient
  2. We have to write the routine that saves the buffered data, chunk by chunk, ourselves.
  3. MediaElement uses Streams (or MediaStreamSource, which in turn uses Streams as well)
  4. We need to be thread safe, since the writing and the reading are done in parallel
  5. We need to access the same stream at different positions, one for reading, one for writing… uh-huh…

Okay, while the two first points are not really a  huge technical challenge, we’ll leave it as an exercise for the reader. The real thing here, is that if we are writing to a stream, it will always be at the current Position. Same for reading from a stream : it will always be based to the current Position. Now, one might have the brilliant idea to say something like “Piece of cake : let’s just change the value of the position just before writing, do our thing, and revert the position back to where it was : no harm no foul”… Only it doesn’t work that way. remember the 4th point ? we need to be thread safe, so after writing to the stream, by the time we want to move the position back to where it was so the stream can be read properly, an other read request might have happened in the meantime, changing the position, and there’s a big chance the application will crash just because you just read something you were not supposed to read (remember ? you just cut the grass from under the reader’s feet !)

Now, if someone is a bit experienced with threading and mutual exclusions, he’ll probably the Semaphore / Mutex into the discussion and argue that we just have to restrict to read and write access so only one can do it at the same time. Well, he would be right, only this is not really feasible as-is. Remember point 3 ? We want to use a MediaElement. In other words, we don’t control the way the stream is read. Adding a semaphore or a mutex around the read statement is simply out of the question since we don’t control the way our stream is read… BUT… we do control our stream, right ? it is provided as an argument to the MediaStreamSource.

From there, it is pretty straightforward. We can subclass a Stream class. (in my case, I subclassed MemoryStream because that was the class I was using firsthand) and override the read and write methods. Once we can add our logic within the stream, we can introduce any thread-synchronization mechanism we like. Since all the operations are located in the same class, I went for a lock statement in each overridden method. Note that the locks must all be based on the same object, so I instantiated an Object whose sole purpose is to act like a token for the lock statements of all the protected methods.

 

        private readonly object _lockObject = new object();

        public override int Read(byte[] buffer, int offset, int count)
        {
            lock (_lockObject)
            {
                return base.Read(buffer, offset, count);
            }
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            lock (_lockObject)
            {
                var oldPosition = base.Position;
                base.Position = base.Length;
                base.Write(buffer, offset, count);
                base.Position = oldPosition;
            }
        }