0

I am trying so set up a TreeView for a Group/User hierarchy, where a group can have users and subgroups, and subgroups also subgroups and users, and so on. When I add/remove a user or group from a collection and update the view with myTreeView.Items.Refresh(); all expanded TreeViewItems get closed. This is inconvenient for the user, so i am trying to expand all TreeViewItems which were expanded before. myTreeView.SelectedItem; doesn't seem to work, it only returns a Group or User Element no TreeViewItem Element. Now, I found something here WPF DataBound treeview expand / collapse that I tried, but the compiler is telling me this now

BindingExpression path error: 'IsNodeExpanded' property not found on 'object' ''User'

A User can't be expanded, so implementing this Field in the User class wouldn't make sense. What am I doing wrong? Is this even the right approach?

I have following setup for my TreeView

<TreeView Grid.Column="0" Name="myTreeView" SelectedItemChanged="myTreeView_SelectedItemChanged" MouseDoubleClick="myTreeView_MouseDoubleClick">
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type datatypes:Group}" ItemsSource="{Binding Items, UpdateSourceTrigger=PropertyChanged}">
                <TextBlock Text="{Binding Name}" FontWeight="Bold"/>
            </HierarchicalDataTemplate>
            <DataTemplate DataType="{x:Type datatypes:User}">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding LicenceUser}"/>
                </StackPanel>
            </DataTemplate>
            <Style TargetType="TreeViewItem">
                <Setter Property="IsExpanded" Value="{Binding IsNodeExpanded, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
            </Style>
        </TreeView.Resources>
    </TreeView>

For better visibility I only copy the interfaces for my classes here.

Here the interface for my Group class

interface IGroup {
    int ID { get; set; }
    string Name { get; set; }
    string Gruppe { get; set; }
    string Path { get; set; }
    Users Users { get; set; }
    ObservableCollection<object> Items { get; }
    bool IsNodeExpanded { get; set; }
    Groups SubGroups { get; set; }
}

the Items Collection in the Group class looks like this

public ObservableCollection<object> Items {
        get {
            ObservableCollection<object> childItems = new ObservableCollection<object>();
            foreach (Group item in SubGroups) {
                childItems.Add(item);
            }
            foreach (User item in Users) {
                childItems.Add(item);
            }
            return childItems;
        }
    }

and the interface for my User class

interface IUser {
    string UserID { get; set; }
    string LicenceUser { get; set; }
    string MailAddress { get; set; }
    string ComputerName { get; set; }
    string HardDriveID { get; set; }
    string Group { get; set; }
    string Path { get; set; }
}

Thanks in advance for your help.

Community
  • 1
  • 1
Istalantar
  • 3
  • 1
  • 5

1 Answers1

0

The setter for IsExpanded applies to all TreeViewItems whether they're Users or Groups. It shouldn't stop you from compiling; it'll just give you a bunch of binding errors in the debug output during runtime.

If that's not acceptable, the quickest solution for your case is to make a converter that distinguishes between Users and Groups and returns false for the former (e.g. IsExpanded="{Binding Path=., Converter={StaticResource ItemToBooleanConverter}}")

public class ItemToBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is User)
            return false;
        return ((Group)value).IsNodeExpanded;
    }

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

EDIT: This doesn't seem to work for two-way binding. What I did in a similar situation was add ITypeProvider with one Type property so that I could make the distinction between types in XAML. A DataTrigger can set the IsExpanded binding only for a particular data type. Adds mostly useless bloat to your classes, but it helps you avoid the binding errors.

Brandon Hood
  • 327
  • 2
  • 12