Monthly Archives: March 2013

This and that – Javascript identity crisis

If you usually program in a language such as C#, you’ll be used to the this keyword.  If you aren’t then in C#, this means this; that is, it means the current object that you’re calling this from.  For example, you might have a class called house, which has properties called DoorOpen and WindowOpen, and a method called ShutTheDoor:

    class House
    {
        public bool DoorOpen {get; set;}
        public bool WindowOpen { get; set; }

        public void ShutTheDoor()
        {
            this.DoorOpen = false;
        }
    }

And the calling code:


    class Program
    {
        static void Main(string[] args)
        {
            House house = new House();

            house.DoorOpen = true;
            house.ShutTheDoor();
            Console.WriteLine(house.DoorOpen);


        }
    }

That makes sense to me. The object House contains the method ShutTheDoor AND the property DoorOpen, so I can call one from the other. As a matter of fact, this is even optional. Any property or method inside House will recognise DoorOpen. I can call this from anywhere, and it will have the same behaviour; for example:

    public void ShutHouseDoor(House house)
    {
        house.ShutTheDoor();
    }

In Main:


    house.DoorOpen = true;
    HouseMinder minder = new HouseMinder();
    minder.ShutHouseDoor(house);
    Console.WriteLine(house.DoorOpen);

How does Javascript deal with this then? Well, pretty much the same way for the most part (the code samples here are using WinJS):


    house: WinJS.Class.define(
        function() {},
        {
            doorOpen: true,
            windowOpen: true,
            shutTheDoor: function shutTheDoor() {                
                this.doorOpen = false;                
            }
        }
    )

The Problem

So that’s cool – it works in the same way. Well, not quite; say I want a program that shuts the house door when I click the canvas:

            var body = document.getElementById("body");
            var canvas = document.createElement("canvas");
            canvas.id = "houseCanvas";

            body.appendChild(canvas);

            var canvasContext = canvas.getContext("2d");

            canvas.width = window.outerWidth;
            canvas.height = window.outerHeight;

            canvasContext.fillStyle = "#f00";            

            canvas.addEventListener("MSPointerUp", house.shutTheDoor, false);

That’ll work, right – because shutTheDoor calls this.doorOpen. Well, and for me this is the most annoying thing about javascript, it will certainly compile. However, when it calls shutTheDoor, it calls in on the canvas, not on the house class. Let me say that again: NOT ON THE HOUSE CLASS.

So it’ll fall over?

No.

What it actually does it helpfully realise that you’ll called a property (this.doorOpen) which doesn’t exist, so it simply creates it for you and sets it to false… on the canvas object.

The Solution

canvas.addEventListener("MSPointerUp", house.shutTheDoor.bind(house), false);

The .bind tells javascript to use the object that you’re passing as the context.

Conclusion

Javascript’s dynamic creation of properties can be useful, but I can’t help thinking that problems like this are why statically typed languages are always going to be easier to work with. You get your first unit test for free: it compiles. In Javascript, not only will an incorrectly named property compile, it will exist – even if it doesn’t.

Always in the last place you look (programmatically finding controls in a C# / XAML store app)

I’ve seen a few articles on this, but none dealing directly with a Windows 8 Store App.  Not that much changes in the general approach, but this article is more about working out why the wheel is round than trying to re-invent it.

The Problem

So, the basis for the article is a standard sample Windows 8 Grid App in C# / XAML.  Here’s the XAML as it stands – it should fit neatly into the template Grid app with a bit of adaptation:

<FlipView.ItemTemplate>
    <DataTemplate>
        <UserControl Loaded="StartLayoutUpdates" Unloaded="StopLayoutUpdates">
            <ScrollViewer x:Name="scrollViewer" 
                    Style="{StaticResource VerticalScrollViewerStyle}" 
                        Grid.Row="1">
                <StackPanel>
                    <MediaElement x:Name="media" Source="/Assets/mymedia.mp4" 
                          AutoPlay="False"/>                                                                                   
                    <Button x:Name="playVideo" Content="Play" 
                          Click="playVideo_Click" HorizontalAlignment="Right"/>

                </StackPanel>
            </ScrollViewer>;
        </UserControl>
    </DataTemplate>
</FlipView.ItemTemplate>
So to quickly summarise, I have a media element and a play button.  So, the actual media file will, in real life, be bound to the data source, but the play button should have the same effect regardless.  The problem that I have it that I can’t reference the MediaElement “media”, because the code behind doesn’t know which “media” I mean.

The Solution

To start off with, let’s have a look at the visual tree (this should also guide the way to the solution).  This function tells me what the XAML visual tree looks like:
private void DisplayVisualTree(DependencyObject control, int indent)
{
    string tab = "";
    for (int i = 1; i <= indent; i++)
        tab += "t";
    
    System.Diagnostics.Debug.WriteLine(string.Format("{0}{1}",
        tab, control.ToString()));

    int childNumber = VisualTreeHelper.GetChildrenCount(control);

    for (int i = 0; i < childNumber; i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(control, i);

        DisplayVisualTree(child, indent + 1);
    }    
}
&#91;/sourcecode&#93;

<div>It's not the finest piece of code I've ever written, but if we wire into the play button, it'll show what the tree looks like in the output window:</div>
<div></div>
<div>

private void playVideo_Click(object sender, RoutedEventArgs e)
{
     DisplayVisualTree(this, 0);
}
Okay – so now we know what the visual tree looks like, so let’s see if we can work out what each element is called.  The trick to this is just casting the FrameworkElement (change the DisplayVisualTree function as follows):
    string tab = "";
    for (int i = 1; i <= indent; i++)
        tab += "t";

    FrameworkElement ctrl = control as FrameworkElement;
    System.Diagnostics.Debug.WriteLine(string.Format("{0}, {1}, {2}",
        tab, ctrl.Name, control.ToString()));

    int childNumber = VisualTreeHelper.GetChildrenCount(control);
&#91;/sourcecode&#93;
<div>So now when you run it, you can see each element's name.  You can simply search the output window and see the "media" element there.  Now we want to return that.  Basically, we want the DisplayVisualTree function to find the control and return it; something like this would do that:</div>
<div></div>
<div>

private DependencyObject FindChildControl<T>;(DependencyObject control, string ctrlName)
{
    int childNumber = VisualTreeHelper.GetChildrenCount(control);
    for (int i = 0; i < childNumber; i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(control, i);
        FrameworkElement fe = child as FrameworkElement;
        // Not a framework element or is null
        if (fe == null) return null;

        if (child is T &amp;&amp; fe.Name == ctrlName)
        {
            // Found the control so return
            return child;
        }
        else
        {
            // Not found it - search children
            DependencyObject nextLevel = FindChildControl<T>;(child, ctrlName);
            if (nextLevel != null)
                return nextLevel;
        }
    }
    return null;
}
If you call this in the Play button, you’ll be able to get a handle to the control:
private void playVideo_Click(object sender, RoutedEventArgs e)
{
    MediaElement media = FindChildControl<MediaElement>;(this, "media") as MediaElement;
    media.Play();
        
    //DisplayVisualTree(this, 0));
}

Conclusion

This does look like a lot of trouble to go to to simply control a media element (especially since sinple clicking the element itself will start the play), however, once you start dealing with databound XAML, it’s only a matter of time before you decide you need to access and control an element inside a databound template.