Jesse Liberty - Silverlight Geek

By, For and About Silverlight Developers
Dynamically Creating User Controls That Fire Events Back To You

Aha! Okay, I may not fully understand all the requirements, but the following demo will show how to dynamically create a user control and then have that user control close itself, remove itself from the containing page and fire an event to the page so that the page can clean up any associated other controls that might be left laying about.

This is based on the User Control sample that goes with the video that hasn't yet been posted (you don't mind that, do you?) but will be in a couple days. I'll strip it down so as not to get hung up in the parts we don't care about.

First, let's look at the effects. When the application begins there is just a single button marked "Create".

CreateButton

Clicking on that button creates two text blocks and two user controls,

dynamicAddandRemove

In the UserControl video the User Controls are quite nicer looking but here we're interested in their ability to self-destruct; hence the close button.

When you click the close button, not only does the User Control remove itself from its parent panel's children collection, it raises an event to which the page can subscribe so that it can clean up anything else that might be lingering about; in this case the text block (which is not part of the control). Thus, if I close the upper control, I want also to remove the "Event Address" prompt.

Here's how it all works. I assume we have the custom control already and I add the button to it.  The key is to give that user control its own EventArgs type (to hold its unique ID ) and thus also give it a delegate and an event.

public partial class AddressUserControl : UserControl
{
    public class AddressEventArgs : RoutedEventArgs
    {
        public object Tag { get; private set; }
        public AddressEventArgs(object theTag)
        {
            this.Tag = theTag;
        }
    }
Notice both that AddressEventArgs is derived from RoutedEventArgs adn that it is nested within AddressUserControl (my User Control).  It has a constructor and a public property called Tag (to parallel the idea that the control itself has a Tag of type object).

We now give the control a delegate and an event

public delegate void AddressEventHandler(object o, AddressEventArgs e);
public event AddressEventHandler Closed;
The closed event is what the page will subscribe to, in order to be alerted when the control is closed. This event is fired as part of the control's handling of the button's click event,
public AddressUserControl()
{
    InitializeComponent();
    Close.Click += new RoutedEventHandler(Close_Click);
}

void Close_Click(object sender, RoutedEventArgs e)
{
    Panel parent = this.Parent as Panel;
    if (parent != null)
    {
        parent.Children.Remove(this);
        if (Closed != null && this.Tag != null)
        {
            Closed(this, new AddressEventArgs(this.Tag));
        }
    }
}

In the constructor we wire up the Close.Click; our internal handler for when the button is pressed. That handler does two things; it first makes sure we're in a panel, and if so, it removes us from the panel. It then checks to see if anyone has registered with our Closed event and that our Tag is not null; if so then it fires the Closed event to anyone who is interested.

Creating The Control Dynamically

 

All of the above falls into place when you see the control created dynamically. The XAML has nothing but the stack panel to hold the dynamically created controls,

Page.xaml

<UserControl x:Class="UserControlDemo.Page"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:jl="clr-namespace:UserControlDemo;assembly=UserControlDemo"
    Width="600" Height="800">
    <StackPanel x:Name="MasterContainer" Background="White">
        <Button x:Name="Create" Content="Create" Width="60" Height="40" HorizontalAlignment="Left"/>
    </StackPanel>
</UserControl>
Here's how the control is created in Page.xaml.cs:
void Create_Click(object sender, RoutedEventArgs e)
{
    TextBlock tb = new TextBlock();
    tb.Text = "Event Address";
    tb.FontFamily = new FontFamily("Verdana");
    tb.FontSize = 24;
    tb.HorizontalAlignment = HorizontalAlignment.Left;
    tb.Margin = new Thickness(15, 0, 0, 0);
    tb.Tag = "1";
    MasterContainer.Children.Add(tb);

    AddressUserControl auc = new AddressUserControl();
    auc.Tag = "1";
    auc.Closed += new AddressUserControl.AddressEventHandler(auc_Closed);
    MasterContainer.Children.Add(auc);


    tb = new TextBlock();
    tb.Text = "Billing Address";
    tb.FontFamily = new FontFamily("Verdana");
    tb.FontSize = 24;
    tb.HorizontalAlignment = HorizontalAlignment.Left;
    tb.Margin = new Thickness(15, 0, 0, 0);
    tb.Tag = "2";
    MasterContainer.Children.Add(tb);

    auc = new AddressUserControl();
    auc.Tag = "2";
    auc.Closed += new AddressUserControl.AddressEventHandler(auc_Closed);
    MasterContainer.Children.Add(auc);

}
Unpacking this, we start by dynamically creating a textblock and adding it to the stack panel. We then create an AddressUserControl and assign it the same tag as the TextBlock and then we register with the user control's closed event, passing in the name of the method to be invoked when that event is raised (auc_closed). Finally, we add the user control to the stack panel.

This is repeated for the second text block and the second user control.

When the user clicks on the button, the user control takes care of removing itself from the stack panel, but it also fires the Closed event, which the page has now registered for. Per the registration, the method auc_Closed is called,

void auc_Closed(object o, AddressUserControl.AddressEventArgs e)
{
    foreach (UIElement uie in MasterContainer.Children)
    {
        TextBlock tb = uie as TextBlock;
        if (tb != null)
        {
            if (tb.Tag.ToString().Equals(e.Tag.ToString()))
            {
                MasterContainer.Children.Remove(uie);
                break;
            }
        }
    }
}

Auc_Closed iterates through the stack panel's children collection looking for textBlocks. If it finds one it checks the Tag against the tag in the AddressEventArgs (put there when the event was fired) and if they match, then it removes that text block from the stack panel as well.

Sweet.

I've put the entire source code Here

Dynamically creating and destroying containers

Ben H. asked a question within a comment to a previous blog post.

Suppose, there is a button on the main form and when the user clicks on the button, a new container gets instantiated and the new container appears on the top of the main form. However, there is also a "Close" button on that container that when the user clicks on, the container closes. And here is my question. When the user clicks on the the "Close" button, I'll set the visibility of that Container to Collapsed, however I need to raise some kind of event in that Close button that the main form (who originally created the Container), will respond to this event that the container has been closed, therefore I need to remove it from the Children.Remove(Container) and then set the container to null.

I don't know how to raise that event in the "Close" button and how to respond to it in the main form.

A sample or explanation or snippet or pointer to some info is much appreciated!

I fully admit that I may not have answered this completely, but after a few minutes of noodling with it, here is what I have... which may be a good start or may be off point but perhapsinteresting anyway.

I created a page.xaml with a grid (one row, two columns) and a button,

<UserControl x:Class="DynamicControls.Page"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150" />
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Button x:Name="Create" Content="Create" 
              Width="50" Height="30" Grid.Row="0" 
              Grid.Column="0" />
    </Grid>
</UserControl>

In the code behind I created an event handler for the button,

private int id = 0;
public Page()
{
    InitializeComponent();
    Loaded += new RoutedEventHandler(Page_Loaded);
}

void Page_Loaded(object sender, RoutedEventArgs e)
{
    Create.Click +=new RoutedEventHandler(Create_Click);
}

The job of the event handler is to dynamically create a container that holds two buttons, one of which is the close button.

void  Create_Click(object sender, RoutedEventArgs e)
{

    StackPanel sp = new StackPanel();
    sp.Orientation = Orientation.Horizontal;
    sp.VerticalAlignment = VerticalAlignment.Center;
    sp.Width = 300;
    sp.Height = 500;
    sp.SetValue(Grid.RowProperty, 0);
    sp.SetValue(Grid.ColumnProperty, 1);
    sp.Tag = (++id).ToString();
    sp.Background = new SolidColorBrush(Colors.Cyan);

    Button btn = new Button();
    btn.Width = 50;
    btn.Height = 30;
    btn.Content = "Close";
    btn.Margin = new Thickness(5.0, 0, 0, 0);
    btn.Tag = id.ToString();
    btn.Click += new RoutedEventHandler(btn_Click);
    sp.Children.Add(btn);

    btn = new Button();
    btn.Width = 50;
    btn.Height = 30;
    btn.Content = "Hello";
btn.Margin = new Thickness(5.0, 0, 0, 0); btn.Click += new RoutedEventHandler(otherBtn_click); sp.Children.Add(btn); LayoutRoot.Children.Add(sp); }

 

Note that the stack panel is assigned a unique ID in its TAG property as is the button

TagProperty

We'll come back to what this is for in just a moment.  After adding the stack panel we add two buttons. One to close the stack panel, and another just to have something else in the stack panel (in this case a button that knows how to change its background color.

CreatedStackPanel

Note that each of the buttons is added to the stack panel's children collection and the stack panel itself is added to the grid's children collection.

sp.Children.Add(btn);
LayoutRoot.Children.Add(sp);

Events

Each of the buttons has its own event, and its own event handler. The second button has an event handler cleverly named "otherBtn_click" (it was late, I was tired...)

btn.Click += new RoutedEventHandler(otherBtn_click);

That event handler picks one of six colors and sets the background for the button,

void otherBtn_click(object sender, RoutedEventArgs e)
{
    int randomNumber;
    Random r = new Random();
    randomNumber = r.Next(0,5);
    List<Color> myColors = new List<Color>();
    myColors.Add(Colors.Magenta);
    myColors.Add(Colors.Purple);
    myColors.Add(Colors.Red);
    myColors.Add(Colors.Gray);
    myColors.Add(Colors.Green);
    myColors.Add(Colors.Blue);
    Button btn = sender as Button;
    if ( btn != null )
    {
        btn.Background = new SolidColorBrush(myColors[randomNumber]);
        btn.Foreground = new SolidColorBrush(Colors.Black);
    }
}

 

Close The Door!

 

The first button is the one that answers the question. Its job is to close the form.

To be explicit, when the user clicks on the Close button, we want the page to be alerted. To accomplish this, we assign an event to the button

btn.Click += new RoutedEventHandler(btn_Click);

The event handler looks through all the elements in the children of the page to find any of type stack panel. If it finds a stack panel it looks to see if the stack panel's Tag holds an ID that matches the ID of the button that fired the event. If so, it has the right stack panel and it removes it from the page's children collection and <poof> it's gone.

 

void btn_Click(object sender, RoutedEventArgs e)
{
    foreach (UIElement uie in LayoutRoot.Children)
    {
        StackPanel sp = uie as StackPanel;
        Button btn = sender as Button;
        if (sp != null && btn != null)
        {
            if (sp.Tag.ToString().Equals(btn.Tag.ToString()))
            {
                LayoutRoot.Children.Remove(uie);
                break;  
            }
        }
    }           // end foreach
}               // end btn_Click

There may be easier ways, but this works quite cleanly. As an exercise for the reader I suggest implementing this so that each click of the Create button creates a stack panel in a different grid location, so that you can have a few open and see that each close button closes the correct one.

 

 

 

Here's the complete source code

 

 

Page.xaml

<UserControl x:Class="DynamicControls.Page"
    xmlns="http://schemas.microsoft.com/client/2007" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="400" Height="300">
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150" />
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Button x:Name="Create" Content="Create" Width="50" Height="30" Grid.Row="0" Grid.Column="0" />
    </Grid>
</UserControl>

Page.xaml.cs

using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Collections.Generic;

namespace DynamicControls
{
    public partial class Page : UserControl
    {
        private int id = 0;
        public Page()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(Page_Loaded);
        }

        void Page_Loaded(object sender, RoutedEventArgs e)
        {
            Create.Click +=new RoutedEventHandler(Create_Click);
        }

        void  Create_Click(object sender, RoutedEventArgs e)
        {

            StackPanel sp = new StackPanel();
            sp.Orientation = Orientation.Horizontal;
            sp.VerticalAlignment = VerticalAlignment.Center;
            sp.Width = 300;
            sp.Height = 500;
            sp.SetValue(Grid.RowProperty, 0);
            sp.SetValue(Grid.ColumnProperty, 1);
            sp.Tag = (++id).ToString();
            sp.Background = new SolidColorBrush(Colors.Cyan);

            Button btn = new Button();
            btn.Width = 50;
            btn.Height = 30;
            btn.Content = "Close";
            btn.Margin = new Thickness(5.0, 0, 0, 0);
            btn.Tag = id.ToString();
            btn.Click += new RoutedEventHandler(btn_Click);
            sp.Children.Add(btn);

            btn = new Button();
            btn.Width = 50;
            btn.Height = 30;
            btn.Content = "Hello";
            btn.Margin = new Thickness(5.0, 0, 0, 0);
            btn.Click += new RoutedEventHandler(otherBtn_click);
            sp.Children.Add(btn);

            LayoutRoot.Children.Add(sp);

        }

        void btn_Click(object sender, RoutedEventArgs e)
        {
            foreach (UIElement uie in LayoutRoot.Children)
            {
                StackPanel sp = uie as StackPanel;
                Button btn = sender as Button;
                if (sp != null && btn != null)
                {
                    if (sp.Tag.ToString().Equals(btn.Tag.ToString()))
                    {
                        LayoutRoot.Children.Remove(uie);
                        break;  
                    }
                }
            }           // end foreach
        }               // end btn_Click

        void otherBtn_click(object sender, RoutedEventArgs e)
        {
            int randomNumber;
            Random r = new Random();
            randomNumber = r.Next(0,5);
            List<Color> myColors = new List<Color>();
            myColors.Add(Colors.Magenta);
            myColors.Add(Colors.Purple);
            myColors.Add(Colors.Red);
            myColors.Add(Colors.Gray);
            myColors.Add(Colors.Green);
            myColors.Add(Colors.Blue);
            Button btn = sender as Button;
            if ( btn != null )
            {
                btn.Background = new SolidColorBrush(myColors[randomNumber]);
                btn.Foreground = new SolidColorBrush(Colors.Black);
            }
        }

    }                   // end class
}
 
The Silverlight Tutorials & Book & More

In what may be a first (at least for me) I've secured agreement with the very generous folks I work for here and at O'Reilly  to loosely join the tutorials and the chapters of our forthcoming book Programming Silverlight (co-authored by Tim Heuer, O'Reilly 2008) to create an enhanced  approach to learning tool.

Let me be clear: the goal is to provide more for less; it is not the goal to push you to buy the book; and you have my word that the tutorials will not be limited, constrained or curtailed in service to making the book somehow more worthwhile.

My hope is that the book will have additional value, but the tutorials, like the videos will stand on their own. If we do it right, together they will supplement one another.

Here's how it will work.

Phase 1 - Tutorials and Draft Chapters

During Phase 1 I will continue to publish tutorials on Silverlight.NET as well as the first drafts of chapters from Programming Silverlight for those who are curious or who would like to provide feedback (more on providing feedback to come).

Note that these chapters will not have gone through technical edit nor copyedit, and will be quite rough; the final chapters will be updated for Silverlight RTW (Release To Web, as opposed to Beta), numerous rounds of technical edit, development edit and copyedit.

Phase 2 - Publication and Beyond

In Phase 2,  the 1st Edition of the book will be published, ideally providing cohesion, depth and detail that is simply not possible in the tutorials.  It is my plan that the tutorials will continue, supplementing the material already on line, drawing on and extending the book as Silverlight evolves, and serving as both a supplement to the existing edition and a preview of future editions.

Schedule

It is important to understand that the writing schedule for this book does not in any way reflect my knowledge of the timing on the release of Silverlight Beta 2 nor subsequent releases of Silverlight. Further, the current schedule is subject to change and will change. It always does. The Table of Contents will change as well.  I'll post both within a week or so.

Creating Controls in Code

In my new video I demonstrate how you can create controls dynamically at run time. The technique is very straight forward, everything you can create declaratively in XAML you can also create dynamically in C#.

xaml

<Button x:Name="Button1" Width="50" Height="30" Content="Click Me" Grid.Row="3" Grid.Column="0" />

C#

Button button2 = new Button();
button2.Width = 75;
button2.Height = 30;
button2.Content = "No, click me!";
button2.SetValue(Grid.RowProperty, 0);
button2.SetValue(Grid.ColumnProperty, 1);
LayoutRoot.Children.Add(button2);

TwoButtons

 

Why Not Dynamically Instantiate All of 'Em?

The case for why you must dynamically instantiate some objects is clear: there are times you just can't know at design time what kind of object you'll need: you must respond to the user's choices and actions. That of course raises the question of why not eschew the XAML altogether and dynamically instantiate all your objects.

There are two answers to this. The first is that it is faster and easier to declare the button in XAML. The second, more important answer is that the XAML is "toolable" -- that is, the XAML can be read and understood by, for example, Expression Blend, while the C# cannot; which makes developing large applications far easier and far more scalable.

If I open the project that created these two buttons in Blend, this is what I see:

DynamicInBlend

 

Blend can read the grid, and the button declared in XAML but is totally unaware of the button created in code.

Conclusion?

The short conclusion is to create objects declaratively at design time when possible, and dynamically at runtime when necessary.  In the abstract this can seem confusing, but when writing code, it is never ambiguous.

Silverlight Debugging Challenge

In about a week, I'll be posting a video on creating a form that responds to keyboard shortcuts (as an intro to a video on user controls).

This is also covered in the tutorial User Controls)

As a challenge to those of you who are already comfortable with styles and data-binding and who "don't need no stinkin' video" -- I've posted a broken version of the program for you to debug. <chortle>

bug

Your mission, should you decide to accept it, is to find the bug, and fix it.

In the video I show this broken version and why it is broken, and then I fix it;  but if you'd like to get ahead of the curve and try your hand... have at it. It's a bit sneaky.

What is supposed to happen when you run the app is that if you hit Control-C the address of the Computer Museum is filled in and if you hit Control-M the address of Microsoft is filled in.  But it don't. <cackle>

Solving Cross Domain Issues - Tim To the Rescue

TimI received an email today asking that I post a reference to Tim Heuer's excellent blog entry on Silverlight Cross Domain Policy File Helpers. My hope is that you are all subscribed to Tim's blog as it is excellent and he and I now share the job that is officially referred to as "Developer Community Liaison for Silverlight" (or something like that).

Tim's blog entries are great, and he and I will be co-authors on Programming Silverlight (O'Reilly).  He'll also be "specializing" in Line of Business questions as well as Silverlight Serialization, Network Issues and Web/Web Services issues.

  Oh! Don't forget to check out his podcasts!

Slides and Code from Presentation in Atlantic City

[The links have been fixed. Thank you for your patience, and I apologize for the inconvenience.] 

 I very much enjoyed my double presentation at the Microsoft Health and Life Sciences Conference in Atlantic City,

AtlanticCity

where I promised, as always, to post my slides and source code.

During the first session we covered adding controls to a form and events and event bubbling; here is the source code.

During the second session we did not cover all the material we hoped to. We did cover data binding in some detail, and here is the starter code and the completed application.

You may want to check the following videos and tutorials to supplement the presentation:

NB: I have videos coming in the next couple weeks on Styles and Templates as well

Thanks again,

User Controls: Tutorial Available

A quick announcement and some words of thanks. I'm pleased to say that Tutorial #5: Keyboard Input and User Controls is now available for reading on line or as a PDF.

UserControl

The thanks go first to Karen Corby whose amazing presentation at Mix I shamelessly stole as the basis for the tutorial (see my blog entry about Karen) and to Silverlight Cream for such a glowing review that my ego can not resist reproducing it here

Jesse Liberty posted this amazing Tutorial on User Controls ... it's like a treatise or something... wow... download the PDF and code and then run away somewhere for a weekend and try to absorb everything in this tutorial, and then I tell you... good luck! ... great material as usual

Reviews in Perspective

Which leads me to a quick story about writing. Shortly after I wrote my first book (Teach Yourself C++ In 21 Days) I received two emails. The first said

I have read 5 books on C++, and I always get stuck on pointers. Yours is  the first one I understand... 

The second said,

I don't know what it is you do for a living, but it isn't programming or writing, because you are incompetent at both.

  I hung them both up on my wall.

How do you know INotifyPropertyChanged is Working

Today I had the great enjoyment to make two presentations to the Microsoft Health and Life Sciences Conference here in Atlantic City.

While showing DataBinding, I became interested in demonstrating the effects of INotifyPropertyChanged, The basic mechanism is this; you add a PropertyChangedEventHandler to your business object and each time you set a bound property you invoke that event, passing in a reference to the business object and an instance of PropertyChangedEventArgs initialized with the name of the property

PropertyChanged

The bound Silverlight controls will respond to this event and update themselves to the new value. But how to test this?

We tried making a new browser, but no go; we suspected (correctly) that the UI was pointing to two different objects. I proved this to myself by modifying the constructor to generate a random number and store it in a member variable, which I display.

AddedID

 

When you attempt to create two views on the data (by hitting control N on the browser or by copying the URL to a new tab) you generate a new object as you can see by the new ID.

 

SideBySide

 

To ensure that we're seeing the UI update in response to changes to the same object, it is easiest to just add two new rows, one that shows the value of IsPublished and the other that shows Quantity on Hand. When you change the original, the duplicate should be informed through the event.

ReflectionOfBinding

 

We can now run the program again and when we change the isPublished or QuantityOnHand properties, we should see that immediately reflected in the second control. Turn off the notification and the reflection should stop.

 

ReflectedBindingRunning

What is coming in the next few weeks?

A couple readers of my blog and folks eager to learn more about Silverlight 2 have written to me asking for 2 things:

1. Tutorials and Videos on the specific topics of interest to them (great, keep 'em coming) and

2. Greater transparency in my schedule of what I'll be releasing

Normally, I don't like to say "I'll be taping, or writing about this subject or that, because the schedule inevitably changes; for any number of reasons: other things rise on the priority list, something is about to change in the way it works so I decide to wait, someone else is about to cover that topic, etc. etc.

All of that said, since I've been asked, here is my tentative list of what I hope to release in the upcoming weeks

Tutorials

  • Keyboard input events on controls
  • User controls
  • Expression Blend for Silverlight Programmers

HDI Videos

  • Creating Controls Dyanmically (in code vs. XAML)
  • Styles
  • Templates
  • Keyboard input events
  • Creating User Controls
  • Expression Blend For Silverlight Programmers
  • Recreating ScottGu's tutorial on Blend as a video

I'll probably add some, and I can't guarantee the order, but that is the plan, at least right now.  My hope is to turn these out quickly to provide a good base of material.

Thanks for your patience and support.

 

-jesse

Binding Data How Do I Video Posted

I'm pleased to say that we've posted a new How Do I Video on Binding Data to Silverlight 2 Controls.

In the very beginning of this video I say it is about "wiring up events" but I'm confused and befuddled -- it is, of course, about binding UI objects to business objects. This is clarified quickly and there is no confusion once we get past the first few moments.

Update Saturday 4/19.  This video was not encoded properly. We've re-encoded it, and I took the opportunity to fix the beginning of the video and eliminate the confusion. The video should be up and correct no later than Monday or Tuesday in all formats. I very much appreciate your patience.

Podcast Part 2 Posted

Sparkling 

On April 9, I posted a link to my first interview on Sparkling Client. Today I'm happy to post a link to the second and final part of the interview.  Also, be sure to catch their terrific interview with Dave Campbell (Silverlight Cream).

 

 

Organizing Lots of Information

A very smart and frequent participant here wrote in today and said (paraphrasing)

 

...Why do you  organize the Learn section around type (video, quickstart, tutorial) instead of topic/task (data binding, layout, browser integration)?

Today I had a Data Binding question...I remember seeing what I wanted on Silverlight.net but not where. I looked at quick starts, then videos and finally found it in tutorials. Doesn't it make sense to have everything about Data Binding together?

Great question!  I have three parts to my answer at least:

1. We are going to be reorganizing this site in the coming months to make it more useful; that is certain. What I'm about to write, though, has nothing to do with that process.

2. What is useful for one person is not always useful for everyone else, and one reasonably difficult thing to agree on is categorization, though you wouldn't think so.

A quick social psych experiment: next time you are a party, ask someone to empty their pockets and to separate the contents into six logical piles. Refuse to provide further guidance.  Once they are done, ask them to explain their piles.  You'll find over time that everyone can do it, that everyone can explain in some detail why these are the logical mutually exclusive piles, but that everyone's criteria are different.

3. I have not discussed what I'm about to say with anyone else, nor am I sure that this way of organizing our tutorials and videos would be useful to anyone but me, but I did enjoy losing an hour thinking about it.

If I were using this site; I'd like total control of how I access the learning material. I'd want to be able to find the material by topic, by type or even by who created it. But I would want all these "boxes" to be transparent.  

I want to know what is in them before I open them, to minimize hunting around, and I want to be sure that whichever path I take I can always change my mind.

 

Step1

 

 

In this truly geeked out approach, I'm asked to choose if I want to see the available information by Topic, by Medium or by Presenter, but I don't have to guess what is under each of these choices.

Let's assume that I prefer the presentations by that incredibly talented chap Liberty, and so I click on his name. This opens up the sub-menu that displays the contributions he has made, but once again I can choose to see it organized by topic or by medium (of course, just the subset he created)

SubMenu

 

Clicking on his videos presents me with the topics he has videos on, and clicking on a topic presents a list of his videos on that topic.  Not bad.  Not perfect, but not bad.

Organization

 

But...

Where do I look if I want all the information available on using animation to display data?  

How do I find out what has been added since the last time I was here, since I've already seen everything that was available?

It would be nice to have a search... but open ended searches can be incredibly frustrating when you are searching through  a relatively small set of data. Guided searches might be better. Something like the Outlook or iTunes Search comes to mind. 

Search

 

In any case, please remember that these are the random ramblings of an idle mind, and have not even been discussed with anyone else, let alone planned for this or any other site. They are just how I think about finding all the info here. Today. For the moment.

 

Your mileage may vary. Void where prohibited. Contents are hot.

Webcast: Event Handling

Today's Webcast was intended to be a smooth presentation of a topic I know cold. Not uncharacteristically,  I went off on a tangent from which I never returned and ended up writing all my code spontaneously.

EventsWebCast

The good news was it was "fresher" the bad news was a few false starts; fortunately I was talking to pros who were very patient, and the key points were made:

  • You can set the container as the event handler for the contained objects (e.g., the stack panel can receive the click event for all the radio buttons
  • Some events bubble and some do not, and it is important to understand which do and which do not and what will happen accordingly
  • The rule of thumb is that events associated with a control (e.g, click) do not bubble but most events associated with mouse and keyboard do bubble; it's best to check the documentation.

The source code for the initial demo using radio buttons can be downloaded here and the source code for the two buttons can be downloaded here.

A complete walk-through of this idea is also covered in  Part 2 of my video on event handling which also has code available for downloading.

Thanks again for hanging in with me, and I have no idea what Microsoft does to me for running so far over-time. I'm sure I'll get a letter.

Tip of the Day Microblog Launches Today

As of today, I will attempt to add a brief Tip of the Day to the Silverlight Microblog every day.

If you would like to contribute (and I hope you will) please send your tips following the directions listed here.

Thanks!

 

-jesse

Next