Binding ViewModel to TreeViewItem's IsExpanded

10 posts, 0 answers
  1. Raj
    Raj avatar
    17 posts
    Member since:
    Feb 2009

    Posted 18 Mar 2009 Link to this post

    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?
  2. Tihomir Petkov
    Admin
    Tihomir Petkov avatar
    576 posts

    Posted 19 Mar 2009 Link to this post

    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.
  3. DevCraft banner
  4. Raj
    Raj avatar
    17 posts
    Member since:
    Feb 2009

    Posted 20 Mar 2009 Link to this post

    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.
  5. Tihomir Petkov
    Admin
    Tihomir Petkov avatar
    576 posts

    Posted 23 Mar 2009 Link to this post

    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.
  6. JC
    JC avatar
    32 posts
    Member since:
    Sep 2010

    Posted 06 Oct 2010 Link to this post

    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
  7. Kiril Stanoev
    Admin
    Kiril Stanoev avatar
    1511 posts

    Posted 06 Oct 2010 Link to this post

    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
  8. JC
    JC avatar
    32 posts
    Member since:
    Sep 2010

    Posted 07 Oct 2010 Link to this post

    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

  9. JC
    JC avatar
    32 posts
    Member since:
    Sep 2010

    Posted 11 Oct 2010 Link to this post

    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+

  10. JC
    JC avatar
    32 posts
    Member since:
    Sep 2010

    Posted 13 Oct 2010 Link to this post

    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 ...
  11. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 13 Oct 2010 Link to this post

    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
Back to Top
DevCraft banner