views:

103

answers:

1

I am just starting in the SL world and am trying to use the Caliburn NavigationShell as my starting point. I converted the solution to SL4 and use Caliburn from the trunk .

To create the basic navigation, I am a bit unsure (well, quite), how I can display the original StackPanel of Buttons as a collapsible Treeview.

I changed ITaskBarItem to own a simple GroupName property

public interface ITaskBarItem : IEntryPoint
{
    BitmapImage Icon { get; }
    string DisplayName { get; }
    string GroupName { get;}
}

then, I expose this in ShellViewModel to the View:

    public IEnumerable<IGrouping<string, ITaskBarItem>> TaskBarItems
    {
        get { return _taskBarItems.GroupBy(t => t.GroupName); }
    }

How can I do the xaml markup so that I get a simple hierarchy?

How can I bind Actions without the use of buttons?

> GroupName
    DisplayName
    DisplayName
    DisplayName

> GroupName
    DisplayName
    DisplayName
    DisplayName
    ...

Mind, this is MVVM, so I am not going to use code behind or events to do that...

A: 

There are a couple of difficulties here. First, here is my markup:

<ItemsControl x:Name="TaskBarItems">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Converter={StaticResource groupName}}"
                            FontWeight="Bold" />
                <ItemsControl ItemsSource="{Binding}"
                                Margin="12 0 0 0">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <TextBlock Text="{Binding DisplayName}" />
                            </StackPanel>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

and my Shell:

public class ShellViewModel : IShell
{
    readonly TaskBarItemViewModel[] taskBarItems;

    public ShellViewModel()
    {
        taskBarItems = new[]
            {
                new TaskBarItemViewModel {GroupName = "Animal", DisplayName = "Monkey"},
                new TaskBarItemViewModel {GroupName = "Animal", DisplayName = "Cat"},
                new TaskBarItemViewModel {GroupName = "Animal", DisplayName = "Dog"},
                new TaskBarItemViewModel {GroupName = "Mineral", DisplayName = "Biotite"},
                new TaskBarItemViewModel {GroupName = "Mineral", DisplayName = "Phlogopite"},
                new TaskBarItemViewModel {GroupName = "Mineral", DisplayName = "Lepidolite"},
            };
    }

    public IEnumerable<IGrouping<string, TaskBarItemViewModel>> TaskBarItems
    {
        get
        {
            return taskBarItems.GroupBy(t => t.GroupName).ToList();
        }
    }
}

Calibrun Micro (cm) will bind the itemscontrol, TaskBarItems, by convention. However, the rest won't work by convention for a couple of reasons. It's in a DataTemplate, so we would usually use Bind.Model. However, it won't work here because the type of each item in the itemscontrol is generic (IGrouping). The default conventions can't handle finding a view for that. So we provide a data template inline.

Secondly, the Key property appears to be implemented as an explicit interface. That means Silverlight can't bind to it. I made a simple converter that binds to the group and extracts the key:

public class GroupNameConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ((IGrouping<string,TaskBarItemViewModel>)value).Key;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Next, since the grouping is itself the IEnumerable we have to bind the ItemsSource of the nested itemscontrol directly. We can't use conventions because there is not property on IGrouping that returns the items. (Though if there was, we'd probably still have the explicit interface issue.)

Regarding your second question. You can bind an action to any event. See the documentation here: http://caliburnmicro.codeplex.com/wikipage?title=All%20About%20Actions&amp;referringTitle=Documentation

bennage
Sorry that this was 4 months after you needed it.
bennage
Thanks for the exhaustive answer, it will be of use to somebody else, for sure and I also learned a lot of stuff that will come handy another time :)
Jan Limpens