使用Caliburn将SL4 TreeView绑定到IGrouping

时间:2010-05-04 01:59:03

标签: mvvm treeview silverlight-4.0 caliburn igrouping

我刚刚开始在SL世界中尝试使用Caliburn NavigationShell作为我的起点。我将解决方案转换为SL4并从主干中使用Caliburn。

要创建基本导航,我有点不确定(好吧,相当),我如何将Buttons的原始StackPanel显示为可折叠的Treeview。

我将ITaskBarItem更改为拥有一个简单的GroupName属性

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

然后,我在ShellViewModel中将它暴露给View:

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

如何进行xaml标记以便获得简单的层次结构?

如何在不使用按钮的情况下绑定Actions?

> GroupName
    DisplayName
    DisplayName
    DisplayName

> GroupName
    DisplayName
    DisplayName
    DisplayName
    ...

介意,这是MVVM,所以我不打算使用代码或事件来做到这一点......

2 个答案:

答案 0 :(得分:2)

这里有一些困难。首先,这是我的标记:

<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>

和我的壳牌:

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)将按照惯例绑定itemscontrol,TaskBarItems。但是,由于某些原因,其余部分不会按惯例运作。它位于DataTemplate中,因此我们通常使用Bind.Model。但是,它在这里不起作用,因为itemscontrol中每个项的类型是通用的(IGrouping)。默认约定无法处理为此查找视图。所以我们提供内联的数据模板。

其次,Key属性似乎是作为显式接口实现的。这意味着Silverlight无法绑定它。我做了一个简单的转换器,绑定到组并提取密钥:

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();
    }
}

接下来,由于分组本身就是IEnumerable,我们必须直接绑定嵌套itemscontrol的ItemsSource。我们不能使用约定,因为IGrouping上没有返回项的属性。 (虽然如果有的话,我们可能仍然会有明确的界面问题。)

关于你的第二个问题。您可以将操作绑定到任何事件。请参阅此处的文档: http://caliburnmicro.codeplex.com/wikipage?title=All%20About%20Actions&referringTitle=Documentation

答案 1 :(得分:1)

克里斯托弗答案中的价值转换器可以概括为:


public class ExplicitPropertyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value == null ? null : GetPropertyValue(value, (string)parameter);
    }

    private static object GetPropertyValue(object target, string name)
    {
        return (
                from type in target.GetType().GetInterfaces()
                from prop in type.GetProperties()
                where prop.Name == name && prop.CanRead
                select prop.GetValue(target, new object[0])
            ).FirstOrDefault();
    }

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

用法在这里:


<TextBlock
    Text="{
        Binding
        Converter={StaticResource ExplicitPropertyConverter},
        ConverterParameter=Key
    }"
    />

此转换器支持任何接口的任何属性。有关my blog的更多信息。