0

I'm sitting with a problem, where I have two separate ObservableCollection in a ViewModel. One list contains the following object:

public class TypeCategory {
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

The other list is:

public class Type {
    public string Name { get; set; }
    public string Description { get; set; }
    public int CategoryId { get; set; }
}

The ViewModel is like:

public class TheViewModel {
    public ObservableCollection<TypeCategory > TypeCategories { get; private set; }
    public ObservableCollection<Type> Types { get; private set; }
}

The Type is a childNode to the TypeCategory, where the connection to the parent node is the CategoryId. Would it be possible to generate a TreeView by using for example multibinding and converter to connect the two lists ? Or is the only solution to extend the parent class to contain it's children ?

dennis_ler
  • 659
  • 1
  • 9
  • 36

1 Answers1

1

You can try like this :

Use Dictionary<string,List<string>> which hold's TypeCategory Name as Key & List<string> which contains Type Names under this Category.

public class TheViewModel
{
    public ObservableCollection<TypeCategory> TypeCategories { get; set; }
    public ObservableCollection<Type> Types { get; set; }
    public Dictionary<string,List<string>> TreeViewItemSource { get; set; }

    public TheViewModel()
    {
        TypeCategories = new ObservableCollection<TypeCategory>();
        Types = new ObservableCollection<Type>();
        TreeViewItemSource = new Dictionary<string, List<string>>();

        for (int i = 0; i < 10; i++)
        {
            TypeCategories.Add(new TypeCategory() { Id = i, Name = "TypeCategory "+ i, Description = string.Empty });
        }

        for (int i = 0; i < 50; i++)
        {
            Types.Add(new Type() { CategoryId = i / 5, Name = "Type " + i, Description = string.Empty });
        }

        foreach (TypeCategory item in TypeCategories)
        {
            List<string> list = Types.Where(p => p.CategoryId == item.Id).Select(p=>p.Name).ToList<string>();
            TreeViewItemSource.Add(item.Name, list);
        }
    }
}

XAML:

<TreeView Name="treeView1" ItemsSource="{Binding TreeViewItemSource}" >
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource="{Binding Path=Value}">
            <TextBlock FontWeight="Bold" Text="{Binding Path=Key}" />
            <HierarchicalDataTemplate.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding }"/>
                </DataTemplate>
            </HierarchicalDataTemplate.ItemTemplate>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

Hope this will help you.

UPDATE :

If you don't want to create a dictionary then you need to apply MultiBinding on HierarchicalDataTemplate's ItemSource.

xmlns:local="clr-namespace:assembly_Name" 
.....
<TreeView Name="treeView1" ItemsSource="{Binding TypeCategories}" Tag="{Binding Types}">
    <TreeView.Resources>
        <local:CategoryItemsConverter x:Key="CategoryItemsConverter"/>
    </TreeView.Resources>
    <TreeView.ItemTemplate>
        <HierarchicalDataTemplate >
            <HierarchicalDataTemplate.ItemsSource>
                <MultiBinding Converter="{StaticResource CategoryItemsConverter}">
                    <Binding Path="Tag" ElementName="treeView1"/>
                    <Binding Path="ItemsSource" ElementName="treeView1"/>
                    <Binding Path="Name"/>
                </MultiBinding>
            </HierarchicalDataTemplate.ItemsSource>
            <TextBlock FontWeight="Bold" Text="{Binding Name}" />
            <HierarchicalDataTemplate.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Name}"/>
                </DataTemplate>
            </HierarchicalDataTemplate.ItemTemplate>
        </HierarchicalDataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

CategoryItemsConverter :

public class CategoryItemsConverter : IMultiValueConverter
{
    public object Convert(object[] values, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        ObservableCollection<Type> typesList = values[0] as ObservableCollection<Type>;
        ObservableCollection<TypeCategory> categoryList = values[1] as ObservableCollection<TypeCategory>;
        string currentCategory = values[2] as string;
        if (typesList != null && categoryList != null && !string.IsNullOrEmpty(currentCategory))
        {
            int? categoryId = categoryList.Where(p => p.Name == currentCategory).Select(p=>p.Id).FirstOrDefault();
            if (categoryId.HasValue)
            {
                var a = typesList.Where(p => p.CategoryId == categoryId).ToList<Type>();
                if (a.Any())
                {
                    return a;
                }
            }
        }
        return null;
    }

    public object[] ConvertBack(object value, System.Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
Amol Bavannavar
  • 2,062
  • 2
  • 15
  • 36
  • This is what I have also been thinking of doing, but was just wondering if it would be possible to solve using multibinding or some other solution, without creating the extra list ? This is only due to my lack of knowledge regarding limitations with bindings and XAML. – dennis_ler Jan 16 '15 at 12:31