This is a migrated thread and some comments may be shown as answers.

Binding ViewModel to TreeViewItem's IsExpanded

9 Answers 810 Views
TreeView
This is a migrated thread and some comments may be shown as answers.
Raj
Top achievements
Rank 1
Raj asked on 18 Mar 2009, 06:01 PM
I have the follwing code which works fine...

<core:HierarchicalDataTemplate x:Key="hdt" ItemsSource="{Binding ChildItems}"  >
                                <StackPanel Orientation="Horizontal">
                                    <Image Source="{Binding ImagePath}" />
                                    <TextBlock Text="{Binding ItemName}" Margin="5,0,0,0" />
                                 </StackPanel>
</core:HierarchicalDataTemplate>
...
<telerik:RadTreeView Grid.Row="1" x:Name="TreeView" 
                            ItemsSource="{Binding Path=Items}" 
                            ItemTemplate="{StaticResource hdt}"
                            IsEditable="True" >
                            <telerik:RadTreeView.ItemContainerStyle>
                                <Style TargetType="telerik:RadTreeViewItem" x:Key="TreeViewItemStyle">
                                    <Setter Property="IsExpanded" Value="true"></Setter>
                                </Style>
                            </telerik:RadTreeView.ItemContainerStyle>
</telerik:RadTreeView>


However, if I change the IsExpanded property to bind to my ViewModel, it fails - this will actually crash the browser....
<Setter Property="IsExpanded" Value="{Binding Path=IsExpanded}"></Setter>

If I define as a static resource I get "An unhandled exception occurred in iexplore.exe [8080]"...

<Style TargetType="telerik:RadTreeViewItem" x:Key="TreeViewItemStyle">
         <Setter Property="IsExpanded" Value="{Binding Path=IsExpanded}"></Setter>
</Style>
...
<telerik:RadTreeView Grid.Row="1" x:Name="TreeView" 
                            ItemsSource="{Binding Path=Items}" 
                            ItemTemplate="{StaticResource hdt}"
    ItemContainerStyle="{StaticResource TreeViewItemStyle}"
                            IsEditable="True" >
</telerik:RadTreeView>

Any ideas how I can resolve this?

9 Answers, 1 is accepted

Sort by
0
Tihomir Petkov
Telerik team
answered on 19 Mar 2009, 08:41 AM
Hello Raj,

Can you please try your binding without the 'Path=' part:

<Setter Property="IsExpanded" Value="{Binding IsExpanded}"></Setter>

The binding seems to work fine when I tested your scenario. If the problem persists, would you please send me a small project which demonstrates your issue, so that I can investigate it further?

All the best,
Tihomir Petkov
the Telerik team


Instantly find answers to your questions on the new Telerik Support Portal.
Check out the tips for optimizing your support resource searches.
0
Raj
Top achievements
Rank 1
answered on 20 Mar 2009, 04:51 PM
Hi Tihomir - thanks for your input. I was wondering if my issue might have something to do with embedding the treeview into a custom control. So my generic.xaml looks similar to...

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:telerik="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Navigation"
xmlns:core="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls">
...
   <Style TargetType="local:Mycontrol">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="local:MyControl">
                     <Grid x:Name="LayoutRoot" Background="White">
                        <Grid.Resources>
                            <core:HierarchicalDataTemplate x:Key="hdt" ItemsSource="{Binding ChildItems}"  >
                                <StackPanel Orientation="Horizontal">
                                    <Image Source="{Binding ImagePath}" />
                                    <TextBlock Text="{Binding ItemName}" Margin="5,0,0,0" />
                                </StackPanel>
                            </core:HierarchicalDataTemplate>
                            <Style TargetType="telerik:RadTreeViewItem" x:Key="TreeViewItemStyle">
                                <Setter Property="IsExpanded" Value="{Binding IsExpanded}"></Setter>
                            </Style>
...
<telerik:RadTreeView Grid.Row="1" x:Name="TreeView" 
                            ItemsSource="{Binding Path=Items}" 
                            ItemTemplate="{StaticResource hdt}"
    ItemContainerStyle="{StaticResource TreeViewItemStyle}"
                            IsEditable="True" >
</telerik:RadTreeView>

I'll put some code together that I can submit to you.
0
Tihomir Petkov
Telerik team
answered on 23 Mar 2009, 07:58 AM
Hi Raj,

ControlTemplates use a naming scope different from the one of your application and that is why you cannot reference resources from your ControlTemplate the way you are trying. So, you have to move the styles you want to reference in your application out of any ControlTemplates.

Let me know if you have further questions.

All the best,
Tihomir Petkov
the Telerik team

Check out Telerik Trainer , the state of the art learning tool for Telerik products.
0
JC
Top achievements
Rank 1
answered on 06 Oct 2010, 11:01 AM
Hello !

Sorry to use this old post but I'm in a similar problem !

I try to bind IsExpanded with IsSelected : 

<Style TargetType="tlk:RadTreeViewItem">
  <Setter Property="IsExpanded" Value="{Binding IsSelected, Mode=OneWay}" />
</Style>

But at runtine, throw a exception that indicate the property is readonly !! ... why ??? 

{System.NotSupportedException: Unable to set read-only property ''.
   à MS.Internal.XamlMemberInfo.SetValue(Object target, Object value)
   à MS.Internal.XamlManagedRuntimeRPInvokes.SetValue(XamlTypeToken inType, XamlQualifiedObject& inObj, XamlPropertyToken inProperty, XamlQualifiedObject& inValue)}

Have you an idea ?
I use the version 2010.2.812.1040
Thanks
0
Kiril Stanoev
Telerik team
answered on 06 Oct 2010, 03:59 PM
Hi JC,

Binding in the Setter of an ItemContainerStyle is not allowed in Silverlight but only in WPF. That is why we have the ContainerBindings. If I've understood your scenario correctly, you want whenever you expand an item, this item to be selected automatically. If this is the case, I've prepared a small project demonstrating this functionality in Silverlight. Have a look at it and let me know if it answers your question. If not, could you please share more details on the scenario you are trying to achieve. I'd be glad to further assist you.

Regards,
Kiril Stanoev
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
0
JC
Top achievements
Rank 1
answered on 07 Oct 2010, 03:45 PM
Ok, 

I understand we can't bind in setter style ... it's a pity ... but anyway, it shouldn't work ...

In fact, my initiale need is view the selected item event if the menu is collapsed so I search a way to expand it
But when I set SelectedItem, i don't know it path so I can't use method ExpandItemByPath.

Have ou another method ?

Thanks

0
JC
Top achievements
Rank 1
answered on 11 Oct 2010, 08:22 AM
Hello, finally I find this way :

public void SelectedItemInternal(object toSelect)
{
  this.Menu.SelectionChanged -= Menu_SelectionChanged;
 
  if (this.Menu != null && this.Menu.SelectedItem != toSelect)
  {
    // Set the selectedItem
    this.Menu.SelectedItem = toSelect;
    this.Menu.CollapseAll();
    AnimationManager.IsGlobalAnimationEnabled = false;
    // Expand menu to selectedItem
    ExpandToObject(this.Menu, toSelect);
    AnimationManager.IsGlobalAnimationEnabled = true;
  }
 
  this.Menu.SelectionChanged += Menu_SelectionChanged;
}
 
private bool ExpandToObject(ItemsControl control, object toFind)
{
  bool retval = false;
  for (int i = 0; i < control.Items.Count; i++)
  {
    // Foreach item find container
    var visualItem = control.ItemContainerGenerator.ContainerFromIndex(i) as RadTreeViewItem;
    if (visualItem != null)
    {
      if (!visualItem.IsExpanded)
      {
        // Expand causes creation of children items
        // if not, ContainerFromIndex will be null
        visualItem.IsExpanded = true;
        visualItem.UpdateLayout();
      }
 
      if (visualItem.DataContext == toFind)
      {
        // Verify DataContext of item
        retval = true;
        visualItem.IsExpanded = false;
      }
 
      if (!retval)
      {
        // Recurcivity to children
        if (visualItem.Items.Count > 0)
          retval = ExpandToObject(visualItem, toFind);
      }
 
      if (!retval)
        // If the branch no contain item, collapse it
        visualItem.IsExpanded = false;
      else
        break;
    }
  }
  return retval;
}

I forgot to say that I use a HierarchicalDataTemplate.
Have you a better solution ?

A+

0
JC
Top achievements
Rank 1
answered on 13 Oct 2010, 08:49 AM
The final shot with synchonous blocking, and multi generators handler : 

public static class TreeViewHelper
{
  private static Dictionary<ItemContainerGenerator, AutoResetEvent> _waiters = new Dictionary<ItemContainerGenerator, AutoResetEvent>();
 
  public static void SelectedAndExpand(this RadTreeView thisTreeView, object toSelect)
  {
    // Set the selectedItem, collapse all and desactivate animations
    thisTreeView.SelectedItem = toSelect;
    thisTreeView.CollapseAll();
    AnimationManager.IsGlobalAnimationEnabled = false;
 
    // Lauch background worker to not stop the UI thread when waiting for the ItemContainerGenerator
    var worker = new BackgroundWorker() { WorkerSupportsCancellation = false, WorkerReportsProgress = false };
    worker.DoWork += delegate
    {
      thisTreeView.Dispatcher.BeginInvoke(() => ExpandToObject(thisTreeView, toSelect));
    };
    worker.RunWorkerAsync();
    worker.RunWorkerCompleted += delegate
    {
      AnimationManager.IsGlobalAnimationEnabled = true;
    };
  }
 
  private static void CheckContainerGeneratorBuzy(this ItemContainerGenerator generator)
  {
    if (generator != null && generator.Status != GeneratorStatus.ContainersGenerated)
    {
      generator.StatusChanged -= ItemContainerGeneratorChanged;
      generator.StatusChanged += ItemContainerGeneratorChanged;
 
      if (!_waiters.ContainsKey(generator))
        _waiters.Add(generator, new AutoResetEvent(false));
 
      _waiters[generator].WaitOne();
    }
  }
 
  private static void ItemContainerGeneratorChanged(object sender, System.EventArgs e)
  {
    var generator = sender as ItemContainerGenerator;
    if (generator != null && generator.Status == GeneratorStatus.ContainersGenerated)
    {
      generator.StatusChanged -= ItemContainerGeneratorChanged;
      _waiters[generator].Set();
    }
  }
 
  private static bool ExpandToObject(ItemsControl control, object toFind)
  {
    bool retval = false;
 
    for (int i = 0; i < control.Items.Count; i++)
    {
      // Wait for the ContainersGenerated
      control.ItemContainerGenerator.CheckContainerGeneratorBuzy();
      // Foreach item find container
      var visualItem = control.ItemContainerGenerator.ContainerFromIndex(i) as RadTreeViewItem;
      if (visualItem != null)
      {
        if (!visualItem.IsExpanded)
        {
          // Expand causes creation of children items
          // if not ContainerFromIndex will be null
          visualItem.IsExpanded = true;
          visualItem.UpdateLayout();
        }
 
        if (visualItem.DataContext == toFind)
        {
          // Verify DataContext of item
          retval = true;
          visualItem.IsExpanded = false;
        }
 
        if (!retval)
        {
          // Recurcivity to children
          if (visualItem.Items.Count > 0)
            retval = ExpandToObject(visualItem, toFind);
        }
 
        if (!retval)
          // If the branch no contain item, collapse it
          visualItem.IsExpanded = false;
        else
          break;
      }
    }
    return retval;
  }
}

Hope this code help anyone ...
0
Petar Mladenov
Telerik team
answered on 13 Oct 2010, 09:06 AM
Hello JC,

First of all , accept our apologies for the late response. 
I am sending you a possible solution to this issue which uses the the method RadTreeView.ExpandItemByPath()  and finds the full path to the selected item recursively.

Please take a look at the attached file and tell me if it satisfies your needs. Feel free to ask if you need further assistance.

Sincerely yours,
Petar Mladenov
the Telerik team
Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Public Issue Tracking system and vote to affect the priority of the items
Tags
TreeView
Asked by
Raj
Top achievements
Rank 1
Answers by
Tihomir Petkov
Telerik team
Raj
Top achievements
Rank 1
JC
Top achievements
Rank 1
Kiril Stanoev
Telerik team
Petar Mladenov
Telerik team
Share this question
or