Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

Dynamic Data Forms for Silverlight with a Data Template Selector Control

The basic idea behind this post is to show a simple way for items/list controls to display each item data with a different template. The ideal candidate for such exercise are data forms, where user can enter different kinds of information - text, numbers, check marks, etc. Imagine a scenario, where each data form field would be presented as a separate ListBox item… no matter of what data type that field is.

The data model for this solution is going to be very simple and generic. We’ll need a generic class, which will represent a single field in a form. Each field will have an id, a caption, a value (entered by the user) and a value type (what’s the type of the value – text, integer, date, etc.):

public class AutoFormField
{
    public Guid Id { get; private set; }
    public string Caption { get; set; }
    public string Value { get; set; }
    public string Type { get; set; }

    public AutoFormField()
    {
        Id = Guid.NewGuid();
    }
}

When the user requests a form, the associated web service will return a collection of AutoFormFields, representing all fields in the form that user should fill out. I’m not using any database for this example, so I’ve hardcoded the fields, returning to the client, in the service itself:

public class AutoFormService : IAutoFormService
{
    public Collection<AutoFormField> GetForm()
    {
        Collection<AutoFormField> form = new Collection<AutoFormField>();
        form.Add(new AutoFormField()
        {
            Caption = "Name: ",
            Type = typeof(string).FullName
        });
        form.Add(new AutoFormField()
        {
            Caption = "Last name: ",
            Type = typeof(string).FullName
        });
        form.Add(new AutoFormField()
        {
            Caption = "Birth date: ",
            Type = typeof(DateTime).FullName
        });
        form.Add(new AutoFormField()
        {
            Caption = "Is employed: ",
            Type = typeof(bool).FullName,
            Value = false.ToString()
        });
        return form;
    }
}
 
The above code shows that the form consists of two text fields, a date and a yes/no field. We would naturally want to display TextBoxes for text entry, DatePicker for a date, and a CheckBox for a yes/no field entry. The Type property contains an identifier, which will tell the client what kind of entry field to display; field data type names are used here for convenience.
Let’s move to the client and implement this.
 
I’ll use the ItemsControl to display the items, because I don’t need the notion of a selected item (yet). Let’s first get the basics out of the way; this is how the ItemsControl looks like, displaying all the form’s captions:
 
<ItemsControl ItemsSource="{Binding Fields, Source={StaticResource viewModel}}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Caption}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
Its ItemsSource property is bound to a ViewModel’s Fields property, which gets populated when a call to the GetForm() web service method returns. The ItemTemplate is set up so that TextBlock displays the fields’ captions.

What we need to do next is display the actual entry fields the user will fill in. I already mentioned the Type property; this will be the key in deciding what kind of control to display.

If we would be coding this in WPF, we would use a DataTemplateSelector to help us out with selecting the right template to load for a specific type. Unfortunately, this feature is not implemented in Silverlight, so we’re on our own here. As it turns out, there isn’t much code required to come up with a solution. This is something that I call…

… a data template selector control…

For our example, we need templates for: a TextBox, a DatePicker and a CheckBox. The following user control will accept all these templates as properties and contain logic to choose between them based on a certain property, which will be bound to AutoFormField’s Type property:

public class FormFieldTemplateSelector : UserControl { public DataTemplate StringTemplate { get; set; } public DataTemplate DateTimeTemplate { get; set; } public DataTemplate BooleanTemplate { get; set; } public DataTemplate SignatureTemplate { get; set; } public static readonly DependencyProperty FieldTypeProperty = DependencyProperty.Register("FieldType", typeof(string), typeof(FormFieldTemplateSelector), new PropertyMetadata(string.Empty));

 

public string FieldType { get { return (string)GetValue(FieldTypeProperty); } set { SetValue(FieldTypeProperty, value); } } public FormFieldTemplateSelector() { Loaded += new RoutedEventHandler(OnLoaded); } private void OnLoaded(object sender, RoutedEventArgs e) { string fieldType = FieldType; if (fieldType == typeof(string).FullName) { Content = StringTemplate.LoadContent() as UIElement; } else if (fieldType == typeof(DateTime).FullName) { Content = DateTimeTemplate.LoadContent() as UIElement; } else if (fieldType == typeof(bool).FullName) { Content = BooleanTemplate.LoadContent() as UIElement; } else { Content = null; } } }

The way to set it up in the item template is simple too. Here’s the complete ItemTemplate:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition MinWidth="100" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>
    <TextBlock Text="{Binding Caption}" VerticalAlignment="Center" />
    <local:FormFieldTemplateSelector Grid.Column="1" FieldType="{Binding Type}" Margin="0,2,0,2">
        <local:FormFieldTemplateSelector.StringTemplate>
            <DataTemplate>
                <TextBox Text="{Binding Value, Mode=TwoWay}" Width="100"/>
            </DataTemplate>
        </local:FormFieldTemplateSelector.StringTemplate>
        <local:FormFieldTemplateSelector.DateTimeTemplate>
            <DataTemplate>
                <basics:DatePicker SelectedDate="{Binding Value, Mode=TwoWay}" Width="100" />
            </DataTemplate>
        </local:FormFieldTemplateSelector.DateTimeTemplate>
        <local:FormFieldTemplateSelector.BooleanTemplate>
            <DataTemplate>
                <CheckBox IsChecked="{Binding Value, Mode=TwoWay}" />
            </DataTemplate>
        </local:FormFieldTemplateSelector.BooleanTemplate>
    </local:FormFieldTemplateSelector>
</Grid>

Of course, this is just one way to put it together. You're free to style each field completely to your liking. This is what we have so far:

To wrap this up, you just have to add a button to submit the form back to the server. I’m not discussing this here since it’s pretty straightforward.

I will, however, continue to build up on this example in the next couple of posts. Some topics I’ll dig into is styling, positioning and more (interesting) templates. I’ll also post the full code in the final post of this series.

Disabling items in a Silverlight ListBox

This is a quick tip on making the ListBox items behave as disabled.

You know the semaphore, right? STOP on red, GO on green? OK. I’m drilling this with my two-year old when driving her to kindergarten every morning so lately it’s probably stuck in my mind a bit more than it should be.

OK. This is a ListBox:

image

Yes, it is:

<ListBox ItemsSource="{Binding Lights}" BorderThickness="0">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Ellipse Fill="{Binding Brush}" Width="50" Height="50" Stroke="Black" Cursor="Hand" />
        </DataTemplate>
    </ListBox.ItemTemplate>
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem" >
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ListBoxItem">
                        <ContentPresenter x:Name="contentPresenter" Margin="4" />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

The data context of this ListBox is a ViewModel with the Lights property. Lights is a collection of five Light objects.

One property that the Light object exposes is the Brush property; it will simply point to a solid color brush of a red, yellow or green color, respectively. The Ellipse’s Fill property is bound to the Brush property as can observed in the above code.

Semaphores usually change colors in an order. The ones in this sample will blink randomly, changing their colors in 2 second intervals:

public Light()
{
    this.SetColor();
    DispatcherTimer timer = new DispatcherTimer()
    {
        Interval = TimeSpan.FromSeconds(2.0)
    };
    
    timer.Tick += (s, e) => { this.SetColor(); };
    timer.Start();
}

private void SetColor()
{
    Color[] colorArray = new Color[] { Colors.Red, Colors.Yellow, Colors.Green };
    Color color = colorArray[randomizer.Next(0, 3)];
    this.Brush = new SolidColorBrush(color);
    this.IsEnabled = color == Colors.Green;
}

Now, we want to allow the user click only on green light, OK? The last line in the above SetColor method sets the IsEnabled property on the Light object only when the current color is set to Green.

With the IsEnabled property up and about, it gets really easy. To prevent the user from clicking on the ListBox item, simply set bind its IsHitTestVisible property to IsEnabled property on the Light class (bold underlined part added):

<ControlTemplate TargetType="ListBoxItem">
    <ContentPresenter x:Name="contentPresenter" Margin="4" 
        IsHitTestVisible="{Binding IsEnabled}" Cursor="Hand" /> </ControlTemplate>

[Cursor property is there for instant visual feedback on when the item is enabled]

That’s it, really. You can test it by adding i.e. a Click event handler to the contentPresenter and display a message box or something (included in the sample below). You would also want to build a better templates for the enabled/disabled items. If built around the bound IsEnabled property, it should work fine.

Declarative Role-based “security” for Silverlight Xaml elements

Tim Heuer published a great example on how to implement user authentication and role validation with ASP.NET Application Services in his Application Corner a while ago. It really works as expected, even with custom membership / role providers. And you get to do declarative role based security checks on your server side classes too.

When building MVVM pattern applications, you tend to have as less code as possible in your views’ code-behind classes. Call me a MVVM purist [ :), see Tim’s video interview for pixel8 ], but (close to) zero lines of custom code is what I like to have in my code-behinds. Not at all costs, but usually it doesn’t take much to code additional helper class, an attached property or a controller of some sort.

What I wanted to do, was replace the following piece of code with something more declarative, which could be used in Xaml:

private void EnableAppFeatures(ObservableCollection<string> roles)
{
    EmployeeButton.IsEnabled = (roles.Contains("Admin") || roles.Contains("HR"));
    OrderButton.IsEnabled = (roles.Contains("Admin") || roles.Contains("Sales"));
    CustomersButton.IsEnabled = (roles.Contains("Admin") || roles.Contains("Sales"));
    ReportsButton.IsEnabled = (roles.Contains("Admin") || roles.Contains("Sales"));
}

[the roles string collection comes in as a result of the Roles service call]

Solution #1 - Good

If you’re using MVVM, adding some additional properties to your ViewModels (like IsInHRRole, IsInSalesRole, etc) should be easy, right? You would just need to bind al the buttons’ IsEnabled properties to their ViewModel counterparts and you’re done.

<Button ... x:Name="ReportsButton" ... IsEnabled="{Binding IsInSalesRole}">

True, but you’ll probably end up “polluting” all your ViewModels with such properties since usually the majority of the Views have some elements, depending on a role the user is in. Additionally, you’d have to create additional properties for combined roles, e.g. IsInSalesOrAdminRole,

Solution #2 - Better

I was thinking somewhere in the lines of attaching a new attached property to each button, which would enable the button when the user would be in one of the specified roles:

<Button ... x:Name="ReportsButton" ... sec:SecurityAction.DemandRole="Sales,Admin">

SecurityAction.DemandRole in this case is an attached property, specifying all the roles, which would make the button enabled. The logic is simple – if the user is in one of the specified roles, the button (or any other control with this attribute appended) would have its IsEnabled property set to true. 

To make this possible, I first had to come up with a class to hold all the current roles, something like a Principal… This is a short class, supporting roles only that will do a job for this demonstration:
 
public class SilverlightPrincipal
{
    public static ObservableCollection<string> Roles { get; private set; }

    static SilverlightPrincipal()
    {
        Roles = new ObservableCollection<string>();
    }

    public static void SetRoles(IList<string> roles)
    {
        Roles.Clear();
        for (int i = 0; i < roles.Count; i++)
        {
            Roles.Add(roles[i]);
        }
    }
    public static bool IsInRole(string role)
    {
        return Roles.Contains(role);
    }

    public static bool IsInOneOfRoles(string[] roles)
    {
        for (int i = 0; i < roles.Length; i++)
        {
            if (Roles.Contains(roles[i]))
            {
                return true;
            }
        }
        return false;
    }
}

The roles collection will contain all roles the user is currently in. IsInRole() and IsInOneOfRoles() will return true, if user is in one of the passed in roles. The SetRoles() method is here for simplicity – it servers just as a roles setter, called from wherever the Roles service calls returns.

Perhaps the class above probably doesn’t even deserve to be called a Principal, but it will serve well for the purpose of this post. For more ideas to implement a more complete Silverlight Principal, check this blog post.

To plug it in Tim’s code, I used the aforementioned EnableAppFeatures method, which now looks like:

private void EnableAppFeatures(ObservableCollection<string> roles)
{
    SilverlightPrincipal.SetRoles(roles);
}

The next thing to do was create the SecurityAction.DemandRole attached property that could be used to set the required roles to a specific control. You’ll find this attached property in the sample code attached to this post. I’m not including the code here because it will make this post much longer and I’m not really fond of using it anyway, because of the reasons for solution #3 below. However, feel free to try the property and please leave comment if you like (or dislike) it.

Solution #3 - Best

After creating #2, I thought – if user can never access the functionality behind the buttons, there is no need to show the buttons to her in the first place, right? Why not showing her the dashboard, created specifically for her role? Sounds familiar? ASP.NET? LoginView?

Here’s my simple LoginView control for Silverlight. You can define as many LoginView templates for as many roles you have:

<controls:LoginView>
    <controls:LoginView.Templates>
        <controls:LoginViewDataTemplate Roles="HR>
            <!-- Layout for HR role -->
        </controls:LoginViewDataTemplate>
        <controls:LoginViewDataTemplate Roles="Sales>
        <!-- Layout for Sales role -->
        </controls:LoginViewDataTemplate>
        <controls:LoginViewDataTemplate Roles="Admin>
            <!-- Layout for Admin role -->
        </controls:LoginViewDataTemplate>
     </controls:LoginView.Templates>
</controls:LoginView>
 
First, here’s the LoginViewTemplate class:
 
public class LoginViewDataTemplate : DataTemplate
{
    public string Roles { get; set; }
}
Yeah, that’s pretty much it. The Roles property will hold the list of roles, which are allowed to see the template.
 
The LoginView control itself is simple too:
 
public class LoginView : UserControl
{
    public Collection<LoginViewDataTemplate> Templates { get; set; }

    public LoginView()
    {
        Templates = new Collection<LoginViewDataTemplate>();

        SilverlightPrincipal.RegisterForRoleChangeNotification(this, LoadTemplate);
        Loaded += (s,e) => { LoadTemplate(); };
    }

    private void LoadTemplate()
    {
        for (int i = 0; i < Templates.Count; i++)
        {
            string[] roleNames = Templates[i].Roles.Split(new char[] { ',', ' ' }, 
                StringSplitOptions.RemoveEmptyEntries); bool isInRole = SilverlightPrincipal.IsInOneOfRoles(roleNames); if (isInRole) { Content = Templates[i].LoadContent() as UIElement; return; } } Content = null; } }

[Update 06-13: updated the above code; should work now]

There’s not much to comment here… The Templates collection holds the collection of, errr., LoginViewDataTemplates, and the LoadTemplate method is there to Load the first template, having one of the specified roles match the current role that user is in. This could be easily extended to support the default template, if needed. The default template would be loaded when no other template would match the current user’s role.

RoleChanged notification /execution

The right template is loaded with the control and whenever the Roles might change, the control would reload the template. I’ve implemented this behavior by adding a registration method for role change notification. Any visual element (or whatever object for that matter) can register itself by passing in the delegate to whatever method should be called whenever role(s) would change. The registration method was conveniently added to existing SilverlightPrincipal class:

public static void RegisterForRoleChangeNotification(object o, Action action)
{
    bool existsInCollection = references.Keys.FirstOrDefault(reference => reference.Target == o) != null;
    if (!existsInCollection)
    {
        references.Add(new WeakReference(o), action);
    }
}

Whenever the roles would change, register objects’ delegate would be called:

private static void OnRolesChanged()
{
    CleanUp();
    foreach (var reference in references)
    {
        reference.Value();
    }
}

The CleanUp method takes care for dead/disposed objects:

private static void CleanUp()
{
    List<WeakReference> list = references.Keys.ToList<WeakReference>();
    for (int i = list.Count - 1; i >= 0; i--)
    {
        WeakReference r = list[i];
        if (!r.IsAlive)
        {
            references.Remove(r);
        }
    }
}

Classes, included in the package: SilverlightPrincipal, SecurityAction, LoginView:

The magic happened… again

I wrote this short program some two years ago and yesterday came time for an upgrade.

Yesterday evening, a gift of life was given to another beautiful princess, Evita, 3730g, 51cm.

Her big sister is very proud and already looking after her, and mom’s doing great.

Binding to Enums

I’ve seen numerous questions regarding data binding to Enums, together with many solutions on how to do it, but the question I’m asking myself is – do I really want to bind anything to an Enum?

I like to think about Enums purely as a coding aid – to help programmer code with some descriptive names instead of messing with pure numeric values. Similar to what constants are for, except Enums provide a set of values for describing a single parameter.

Instead of:

product.Quality = 3;

the programmer would write:

product.Quality = Quality.Good;
 
… providing that Quality Enum is declared something like:
 
public enum Quality
{
    JustBad, Poor, OK, Good, Excellent
}

Of course, you could set your enum values to some concrete numbers, like:

public enum Quality
{
    JustBad = 1, Poor = 2, OK = 3, Good = 4, Excellent = 5
}

… but in most cases you shouldn’t need to. Like I said, I see Enums only as a before-compilation, human <-> code communication, and therefore I believe no part of Enum should ever see the light of day (i.e. be exposed to the UI). And with that, there goes the need for binding to Enums…

Why would I want to bind to Enums anyway? Enum enumerators have no description (other than their names). If you need to provide spaces or even support localized descriptions, you’ll need to extend them significantly, so why not create a new class anyway? Here’s what I use instead of an Enum:

public sealed class Quality
{
    public const int JustBad = 1;
    public const int Poor = 2;
    public const int OK = 3;
    public const int Good = 4;
    public const int Excellent = 5;

    public Dictionary<int, string> Collection { get; private set; }

    public Quality()
    {
        Collection = new Dictionary<int, string>()
        {
            {JustBad,   "Just bad :("},
            {Poor,      "Poor"},
            {OK,        "OK"},
            {Good,      "Good"},
            {Excellent, "Excellent!"},
        };
    }
}

The programmer would still write:

product.Quality = Quality.Good;

so it makes it easy to refactor existing code. Additionally, you can put in any description for the values, support localization, and it’s easy bindable in Xaml - declare the class instance as a local resource:

<local:Quality x:Key="quality" />
and bind away:
 
<ListBox DisplayMemberPath="Value" 
         ItemsSource="{Binding Collection, Source={StaticResource quality}}" />

WPF vs. Silverlight: a subset or what?

For a WPF developer, crossing over to Silverlight development can be a pretty mindboggling adventure.

I mean - if you’re currently engaged with Windows Forms or ASP.NET and seeking new advancements, Silverlight would (should?) be a logical step forward in your life as a developer. There are, of course, a whole variety of new concepts and patterns to be learned, but compared to WPF, Silverlight is really not that big. When comparing Silverlight and WPF, I often describe WPF as Silverlight’s older brother: calm, capable & wise business man, dressed in a grey suit. On the other hand, Silverlight would be a very agile, very smart and witty teenager, popular among the crowd, although sometimes crossing the boundaries of what’s considered a good behavior. But at the same time he would be pushing the tolerance limits of his older brother, teaching him some new things and giving him a different, fresh perspective on life.

How so?

WPF is pretty big, framework-wise. Silverlight is substantially smaller, but:

a] Silverlight had Visual State Manager in v2. WPF VSM was announced only after Silverlight was out and is in the making, as of now. VSM was introduced to replace styling with the support of triggers, which don’t really exist in Silverlight (there’s the EventTrigger, but that’s pretty much it).
b] Silverlight had a DataGrid in v2. WPF DataGrid v1 has just been released.
c] Silverlight additionally allows some simpler Xaml constructs, like TargetTyping to a type name (TargetType=”Button”) rather than a type reference (WPF: TargetType=”{x:Type Button}”), etc. WPF is going to follow Silverlight on this too.

Silverlight clearly took the lead with introducing new features into the framework and improving what was considered as not so good in WPF. And with Silverlight v2 being RTW for only a few months now, we’re expecting some big announcements on MIX09about v3 , which is said to be released later this year. Silverlight is maturing fast.

Of course, there are currently some crucial things missing in Silverlight that ruins the experience with developing a decent (LOB) application:

a] No commanding support.
b] No real business objects validation support.
c] etc, etc… The web is full of Silverlight missing features. Google it. I’ll only post two MSDN links on differences between WPF and Silverlight: here, here.

If you’ve learned (and practiced) WPF prior to Silverlight, those differences could easily turn out to be a wall, which you’re going to hit into when actively engaged in developing a real-world Silverlight project. Take, for example, the DependencyObject. The guy who posted this question obviously studied the wrong documentation when learning Silverlight. And it’s so easy to take a wrong turn when navigating through the links describing Silverlight classes and functionality. One wrong click and you may be directed to the WPF-version of the page, describing DependencyObject, for example. Not knowing that you’re really studying the WPF implementation (which differs significantly from what’s in Silverlight) you read all about it; and you learn it wrong!  I myself didn’t know about this difference until the mentioned post got me to start Reflecting on both versions of DependencyObject.

Here’s the short story: if you declare a DependencyProperty on the DependencyObject in WPF, any change to the value of this property will raise the PropertyChanged event, without the need to implement the INotifyPropertyChanged interface. In Silverlight, this is no go. Silverlight’s DependencyObject doesn’t implement the OnPropertyChanged method like WPF DO does, so you have to implement INotifyPropertyChanged interface on your object for it to properly propagate PropertyChanged event to its listeners. There is, however, a reasoning behind this: Silverlight’s Binding construct doesn’t support the ElementName property, which allows binding to some other control on the same page. All controls are descendants of a DependencyObject so therefore, if bound to, they should notify their listeners if one of dependency properties has changed. But because you can’t bind to those controls, there is no need for DependencyObjects to support PropertyChanged notification on dependency properties. You commonly bind your controls to business objects in Silverlight anyway, and putting DependencyProperties into business objects is not recommended even in WPF. Business objects should implement INotifyPropertyChanged-enabled properties, be that in Silverlight or WPF.

All those tiny little differences don’t make it easy for someone concurrently involved with Silverlight and WPF projects. Imagine working on two simultaneous projects, but one in C# and the other in VB. The syntax differences of those two can be easily compared to differences between Silverlight and WPF. Constantly switching between two similar mindsets can be a pain.

We’ve all been told several times that Silverlight is a subset of WPF. Well, rather than a subset, I like to call Silverlight a REset of WPF. I mean, with Silverlight, Microsoft now has this great opportunity to gradually create a fresh, true cross-platform, “runs-everywhere” presentation framework from the ground up, being able to cover all kinds of applications imagined, from games to business; the latter of course greatly powered by the web (services / cloud). They’ve learned what works and what not from working on WPF, so Silverlight would get only those bits that do work. At the same time WPF will continue to improve together with Silverlight, until… until Silverlight grows powerful enough to forget all about WPF :) Might be far-fetched, but hey…

So, will WPF eventually die? Is it a dead end? When?
Let me answer this question with another answer: is Windows Forms dead yet?

On the other hand, look what we’ve been programming about 10-15 years ago… looking 15 years in the future, I’m afraid there will be neither Silverlight nor WPF, but something uber-both. So whatever solves your current business problem, goes.

photoSuru install experience

Realizing that i don’t have any decent photo slideshow player installed on my machine I thought I’d install photoSuru and see what it can do for me.

photoSuru

While it’s a beautiful subscription-based WPF photo viewer, built on a Syndicated Client Experiences (SCE) Starter Kit , it was something else that caught my eye:

install

What kind of installer is this? Looks like the application itself… did I already install it and it’s now updating itself?

Yes, photoSuru is a ClickOnce application. Deployment-wise, it uses a hybrid MSI/ClickOnce installer, providing a consistent look, matching the appearance of the application itself. If you’ve deployed any ClickOnce application before, you know that you had no power to change that dull install dialog in any way.

.NET 3.5 SP1 changed this. With SP1 installed, you now do have the power to customize and brand your application’s progress dialog, including optional end-user license agreement page, localization, etc., you just have to do it all by putting together a bunch of Xml files, describing what you want it to look like.  Yup, there is no visual support for this yet (as in Visual Studio 2008 SP1). The future looks bright, though. Client Profile Configuration Designer is currently a part of WPF Futures, a taste of what is about to come. You can download and play with it - it’s certainly going to be of some help to you, at least to get you started and set up the basic dialogs and progress flow, but you might still have to get into the Xml files to fine-tune some details.

I’ve tried the CPC Designer with one of my WPF apps some time ago and I did manage to put together a quite decent looking installer, it just took me more time as it would if I went with the default ClickOnce option. But that goes without saying, doesn’t it?

Making the Silverlight TreeView bindable two-way

One of the most common scenarios in LOB applications is a list control, displaying some sort of items, and clicking on an item provides the user with some details about selected item. This is called a Master-detail scenario. Take Microsoft Outlook, as a typical three level example [Folder-Mail-Content]. I’m going to implement this scenario with Silverlight Toolkit’s TreeView using the MVVM pattern.

I’ll use the same PageViewModel, used in the first post of my TreeView Editing series and begin working on the user interface, first using a ListBox, not the TreeView. The PageViewModel is, again, set as the DataContext of the main page.

ListBox

Selecting a help topic from the list will get its description shown in a TextBlock below the ListBox. How this works is that when an item is selected, the ViewModel is notified. The ViewModel then gets the selected item’s details and notifies the TextBlock when the details are available. Sounds complicated? It’s not, really.

Let’s do this the easy way – I’m going to use the HelpTopic class as a list item and as a detail. That means both the ListBox and the TextBlock will be bound to the new SelectedTopic property on the ViewModel:

private HelpTopic selectedTopic;
public HelpTopic SelectedTopic
{
    get { return selectedTopic; }
    set
    {
        if (selectedTopic == value)
        {
            return;
        }
        selectedTopic = value;
        OnPropertyChanged("SelectedTopic");
    }
}

with ListBox and TextBlock bound as displayed in this parts of Xaml:

<ListBox ItemsSource="{Binding HelpTopics}" DisplayMemberPath="Name"
SelectedItem="{Binding SelectedTopic, Mode=TwoWay}" />

<TextBlock Text="{Binding SelectedTopic.Name}" />

Now let’s add a Tree and bind it the same way as the ListBox. Here’s the complete Xaml:

<StackPanel>
    <StackPanel Orientation="Horizontal">
        <ListBox ItemsSource="{Binding HelpTopics}" DisplayMemberPath="Name" 
                 SelectedItem="{Binding SelectedTopic, Mode=TwoWay}" Width="300"
                 HorizontalAlignment="Stretch" /> <slt:TreeView VerticalAlignment="Stretch" ItemsSource="{Binding HelpTopics}"
                      SelectedItem="{Binding SelectedTopic, Mode=TwoWay}" Width="300"> <slt:TreeView.ItemTemplate> <slt:HierarchicalDataTemplate ItemsSource="{Binding SubTopics}"> <TextBlock Text="{Binding Name}" VerticalAlignment="Center" /> </slt:HierarchicalDataTemplate> </slt:TreeView.ItemTemplate> </slt:TreeView> </StackPanel> <Border BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Stretch"> <StackPanel Orientation="Horizontal"> <TextBlock Text="You selected: " Margin="4" /> <TextBlock Text="{Binding SelectedTopic.Name}" VerticalAlignment="Center" Margin="4" /> </StackPanel> </Border> </StackPanel>

We have two controllers now (ListBox and TreeView). But let’s observe how they like being controlled.

image

image

TreeView differs from the ListBox in having a private SelectedItem property setter, which makes two-way binding impossible. Almost impossible anyway, there is a way around it.

Let’s extend the TreeView by creating a new attached property which will provide us with “the-missing-way binding”, needed to update the TreeView from the ViewModel:

public class SelectionService
{
    public static readonly DependencyProperty SelectedItemProperty = 
           DependencyProperty.RegisterAttached("SelectedItem", typeof(object), typeof(SelectionService),
           new PropertyMetadata(null, OnSelectedItemChanged)); public static void SetSelectedItem(DependencyObject o, object propertyValue) { o.SetValue(SelectedItemProperty, propertyValue); } public static object GetSelectedItem(DependencyObject o) { return o.GetValue(SelectedItemProperty); } private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { TreeView treeView = d as TreeView; if (treeView == null) { return; } TreeViewItem item = treeView.ItemContainerGenerator.ContainerFromItem(e.NewValue) as TreeViewItem; if (item == null) { return; } item.IsSelected = true; } }

There’s really just two lines of code that actually do anything. In the OnSelectedItemChangedMethod, I’m getting the container TreeViewItem of the selected HelpTopic and set its IsSelected property to true.

To attach this property to the TreeView, add the following to the above-defined TreeView:

<slt:TreeView ... local:SelectionService.SelectedItem="{Binding SelectedTopic}">

There’s however two minor issues to this approach… TreeView’s native SelectedItem property is still two-way bound so when ViewModel tries to call its private setter, an exception is still thrown, which may affect performance. What we would need here is a OneWayToSource type binding, which exists in WPF, but unfortunately not in Silverlight.

The other issue is that the above code only works for the root level. If you want to select any node in the hierarchy, you would traverse the tree unit you find the one that should be selected. But… the TreeView creates TreeViewItems only when needed (when their parent node is expanded). In order to fix this, each item has to be expanded before inspecting their children and then collapsed, if that was its original state. Additionally, this approach can be even more time consuming. Let’s look at the quick and dirty implementation:

private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    TreeView treeView = d as TreeView;
    if (treeView == null)
    {
        return;
    }

    TreeViewItem item = treeView.ItemContainerGenerator.ContainerFromItem(e.NewValue) as TreeViewItem;
    if (item != null)
    {
        item.IsSelected = true;
        return;
    }

    for (int i = 0; i < treeView.Items.Count; i++)
    {
        SelectItem(e.NewValue, treeView.ItemContainerGenerator.ContainerFromIndex(i) as TreeViewItem);
    }
}

private static void SelectItem(object o, TreeViewItem parent)
{
    if (parent == null)
    {
        return;
    }

    bool isExpanded = parent.IsExpanded;
    if (!isExpanded)
    {
        parent.IsExpanded = true;
        parent.UpdateLayout();
    }
    TreeViewItem item = parent.ItemContainerGenerator.ContainerFromItem(o) as TreeViewItem;
    if (item != null)
    {
        item.IsSelected = true;
        return;
    }

    for (int i = 0; i < parent.Items.Count; i++)
    {
        SelectItem(o, parent.ItemContainerGenerator.ContainerFromIndex(i) as TreeViewItem);
    }

    if (parent.IsExpanded != isExpanded)
    {
        parent.IsExpanded = isExpanded;
    }
}

OK, now we have a two-way bindable TreeView, playing nice with the ViewModel, but with some performance hit for that “other-way binding”. I’m sure the Silverlight Toolkit guys would make this much more performant, so if you would like to see TreeView’s SelectedItem property to be made public, you can vote here.

Design a Vista-like account display picture for Silverlight application

If you like the way how Windows Vista shows your account picture on the Login screen, or how Windows Live Messenger’s display picture looks like on, you have probably already thought about putting something like it in your Silverlight application, either for a login screen or just to display a picture in a nice frame.

To take a short break from coding, I’m going to write about how to design a frame, similar to what the above examples use, and put it on a Silverlight page.

I’ll start by opening Expression Design.

Create a new document, then select a Rectangle tool and draw two squares on the canvas. Their size should be set to 110x110 and 97x97. Make sure the stroke of both is set to 1 px width, black.

Set the smaller square’s Corner Radius to 2 px, and the bigger one should be set to 4px.

With the bigger square selected, select Object | Envelope Distort | Make Warp Group then decrease group’s resolution by selecting Object | Envelope Distort | Decrease Resolution.

Squares

With the Direct Selection tool selected, select each of the four handles on the sides (not corners) and move them away from the center by approx. 4 px.

Rectagle

With the square still selected, select Object | Envelope Distort | Edit Warp Group.

In the Properties window, under Appearance, select Fill Gradient Color tool. Choose your base color (I’ve chosen one from the default set) and build a custom gradient on it. Setting it up like this:

Gradient

got me this:

Gradient

Return to the main panel. If the square isn’t updated with the gradient, do something to it to get it refresh itself.

Now, select both rectangles and align them vertically and horizontally (Arrange | Align | Vertical Centers, Arrange | Align | Horizontal Centers). If the smaller square disappears (falls behind the bigger one), send the big one to back (Arrange | Order | Send to Back).

Select the smaller square and set its fill color to White and allow some transparency (80% Opacity in this case).

Voila:

Picture frame

If that's not enough, you can experiment by setting the outer square’s stroke color to a lighter black/grey, add a drop shadow, etc. Expression Design allows great effects to be applied to your objects, would be a waste not to use them :)

Now, for the Silverlight part…

Select Edit | Options | Clipboard (XAML)… Set Clipboard format to XAML Silverlight Canvas. You can uncheck the Place grouped objects in a XAML layout container option.

Group all objects (Arrange | Group) into one group and move the whole thing into left top corner. Edit | Copy XAML (Ctrl+Shift+C) and paste into your Silverlight page (Xaml view).

Note: all of the above applies if you’re building a display picture for your WPF application too. Just select the proper Clipboard/XAML settings in Expression Designer and you’re ready to go.

Now, replace the Canvas declaration with a Grid and remove all Canvas-related attributes from its child elements.

Now you can fill the empty content with a picture of your choice.

Display picture

In one of the forthcoming posts I’ll make this a custom control and most likely build a multiple user login screen, but in a rather unusual way ;)

Silverlight TreeView: MVVM and editing [5 – Add]

In the previous post, we enabled editing for our TreeView. The last operation we need to implement is adding a new item to the hierarchy. With our tree item editor in place, there’s not so much left to do…

The only change we need to make with the View is add an Add button, right next to the Edit button. We’ll wire it to the Add command, which already exists.

The next stop is the ViewModel. We need to change the existing OnAddTopicExecuted handler to add a new child to the HelpTopic, passed into the method through CommandParameter:

private void OnAddTopicExecuted(object sender, ExecutedEventArgs e)
{
    HelpTopic topic = new HelpTopic();
    HelpTopic parent = e.Parameter as HelpTopic;
    if (parent == null)
    {
        HelpTopics.Add(topic);
    }
    else
    {
        parent.SubTopics.Add(topic);
    }
    topic.BeginEdit();
}

Note: when CommandParameter is not set to a valid HelpTopic (when it’s null), we’re adding a child to the root.

There is something wrong with the code above. I’m assuming that the SubTopics collection was already initialized when I created a new HelpTopic class instance. I this case, I assumed wrong and the above code would throw a nasty error.

I need to assure that SubTopics property is never null as this puts the HelpTopic in an invalid state. I’ll do that by inserting the collection initialization code in its constructor:

public HelpTopic()
{
    SubTopics = new ObservableCollection<HelpTopic>();
}

Better. But we’re not done yet. There is no way for user to cancel the newly added item. Sure, she can press the Cancel button when editing, but the node will not be removed from the tree.

This is the time to provide the HelpTopic class with an unique identificator field. When working with the database, the type of this field would align with whatever your database table primary key type is. For simplicity, I’ll use Guids here, just because their generation results in more unique results than a number randomization would.

The logic behind is this: when a new HelpTopic is being added, its Id is set to null. If the item is confirmed, the new Id is set, otherwise the item is removed from the hierarchy. Here’s how modified OnEndEditTopic and OnCancelEditTopic now look like:

private void OnEndEditTopic(object sender, ExecutedEventArgs e)
{
    HelpTopic topic = e.Parameter as HelpTopic;
    if (!topic.Id.HasValue)
    {
        topic.Id = Guid.NewGuid();
    }
    topic.EndEdit();
}

private void OnCancelEditTopic(object sender, ExecutedEventArgs e)
{
    HelpTopic topic = e.Parameter as HelpTopic;
    if (!topic.Id.HasValue)
    {
        topic.RemoveFromStructure(HelpTopics, item => { return item.SubTopics; });
    }
    topic.CancelEdit();
}

Wait! Before we end this, let me just put another button in a TreeView to enable user to add a new HelpTopic to the root of the tree. This is the modified template with a new button in place (added lines in bold italic):

<ControlTemplate TargetType="slt:TreeView">
    <Grid x:Name="Root" >
        <Grid.Resources>
            <SolidColorBrush x:Key="BorderBrush" Color="#FF000000" />
        </Grid.Resources>
        <Border x:Name="Border" BorderBrush="{StaticResource BorderBrush}" 
            BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="2"> <Border Padding="{TemplateBinding Padding}" Background="{TemplateBinding Background}" Margin="1"> <ScrollViewer x:Name="ScrollViewer" HorizontalScrollBarVisibility="Auto"
                    VerticalScrollBarVisibility="Auto" Background="{x:Null}" BorderBrush="Transparent"
                    BorderThickness="0" IsTabStop="False" TabNavigation="Once"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Button HorizontalAlignment="Left" ToolTipService.ToolTip="Add Topic" input:CommandService.Command="AddTopic"> <Image Source="/EditableTreeView;component/Resources/add.png" Stretch="None" /> </Button> <ItemsPresenter x:Name="TreeItems" Grid.Row="1" Margin="5" /> </Grid> </ScrollViewer> </Border> </Border> </Grid> </ControlTemplate>

Editable TreeView

OK, we’ve got our TreeView to allow basic inline editing now, but not in very realistic scenario and it lacks usability. I’m going to end this series with this post and spin off to more general topics posts, covering more MVVM, LOB scenarios and Silverlight in general. A taste of things to come: improving, extending and expanding on the current state of this sample, going over the wire, testing and user experience.

The source code for this sample is available: