IsSelectable support

10 posts, 1 answers
  1. Thorsten
    Thorsten avatar
    26 posts
    Member since:
    Apr 2010

    Posted 30 Oct 2010 Link to this post

    Hi,

    I'm using the RadTreeView in a MVVM scenario.
    Depending on the model's IsSelectable property the corresponding item should be either selectable by the user or not.
    Since this doesn't seem to be supported by the RadTreeViewItem container itself (which would be a nice new feature ;)),
    the only way I found in this case is to listen on the container's PreviewSelected event and setting the "e.Handled" value to "true" if the item shouldn't be selectable.
    So it looks like:

    void RadTreeView_PreviewSelected(object sender, RadRoutedEventArgs e)
    {
      var item = e.GetItem<IMyModel>(); // extension helper method
     
      // check item that will be selected   
      if (item != null && !item.IsSelectable)
        e.Handled = true;


    But this results in a major drawback:
    Upon canceling selection of the new item 'X', i'm loosing the currently selected item.
    Afterwards the item 'X' has the focus rectangle and the selected item is null.
    So the question is:
    Is there a possiblity to cancel the selection of a new item without loosing the previous selection ?

    It tried to hook the PreviewSelected, PreviewUnselected, Unselected, Selected events.
    But even if set an additional flag on "PreviewSelected" which indicates that I want to revert/ignore the next unselection, I'm out of luck.
    - PreviewUnselected is called before PreviewSelected => I can't determine whether to cancel or not since i don't know the future ;)
    - Unselected gets actually called directly after PreviewSelected, but the RadTreeView's SelectedItem is still unchanged.
      Setting the "e.Handled" value to "true" won't change anything.
     
    The second question would be:
    Upon the "Unselected"-Event shouldn't the treeview's currently selected item be either the next selected item or null ?

    Thanks in advance

    Thorsten Klingert

  2. Miro Miroslavov
    Admin
    Miro Miroslavov avatar
    588 posts

    Posted 03 Nov 2010 Link to this post

    Hello Thorsten Klingert,

     You could bind the IsEnabled property of the RadTreeViewItem to the IsSelectable, thus the item will be disabled and restricted from selection.
    Please let me know if this is not an option for you.

    Best wishes,
    Miro Miroslavov
    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
  3. UI for WPF is Visual Studio 2017 Ready
  4. Thorsten
    Thorsten avatar
    26 posts
    Member since:
    Apr 2010

    Posted 03 Nov 2010 Link to this post

    Hi,

    thanks for the response, but the disabling the item isn't an option.
    I'm using hierarchical data where some layers are selectable and others not.
    Even if a parent item is not selectable their childs might be.
    Disabling the parent item does not allow any child selection.

    With kind regards

    Thorsten Klingert
  5. Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 05 Nov 2010 Link to this post

    Hi Thorsten Klingert,

    Can you please have a look at the attached example and let me know if this is close to what you had in mind?

    Thank you in advance.

    All the best,
    Tina Stancheva
    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
  6. Thorsten
    Thorsten avatar
    26 posts
    Member since:
    Apr 2010

    Posted 05 Nov 2010 Link to this post

    Hi,

    so once again, thanks for the response and the sample.

    I attached a modified version of your project to the feature request thread: http://www.telerik.com/account/support-tickets/view-ticket.aspx?threadid=363785

    From a surface look, you've exactly hit what i had in mind.

    After looking at the code I'm a bit puzzled why the re-selection of the last deselected item in this case works at all.

    Since I've done actually zero with silverlight, I attached the poor man's tracer, a listbox, to the main view.
    It turns out that on PreviewSelected, the SelectedItem of the tree view is still the one stored to the unselectedItem variable within the last PreviewUnselected call.
    So assigning the same item as selected item again shouldn't normally change anything but in this case it does.
    To make things even more curious, the tree view's selected item is NULL after the assignment of the last unselected item which clearly wasn't NULL.

    So also it seems to work as intended, i discovered two drawbacks:
    1. The cancelation results in 2 Unselected and 2 Selected-events being raised for the same, untouched item.
    2. If multiselection is enabled and lets say two valid items are selected, ctrl+click on a non-selectable item messes up the SelectedItems collection of the treeview. It now contains the same items twice.

    I think the only way to handle such a scenario without side effects is a direct support via a RadTreeViewItem property.

    With kind regards

    Thorsten Klingert

     
  7. Hristo
    Admin
    Hristo avatar
    352 posts

    Posted 08 Nov 2010 Link to this post

    Hi Thorsten,

    I can understand the frustration you are experiencing with our tree view and its selection. However there is a logical explanation to your question, and it is based on the fact that you are trying to change the selected item inside the PreviewSelected event. The tree view internally does not select the required element immediatelly. Instead it remembers which item should be selected and selects it in a later step.

    So when calling the treeView.SelectedItem = unselecteItem the code marks which item should be selected and makes the currently selected item to be Null. Unfortunately this internal logic is called just before your check for null. Then this internal logic is called for second time (due to the mouse click that made the selection change event). In a third step after the PreviewSelected event has passed the tree view changes the selected item (the third preview selected in the output below) and fires Unselected and Selected events.

    You can take a look at the following code which is a slight modification of yours:

    private void treeView_PreviewUnselected(object sender, Telerik.Windows.RadRoutedEventArgs e)
    {
        unselectedItem = e.Source as RadTreeViewItem;
        //this.ListBox1.Items.Add("preview unselected: " + GetDataItem(e.Source).Name);
        Debug.WriteLine("preview unselected: " + GetDataItem(e.Source).Name);
    }
     
    private void treeView_PreviewSelected( object sender, Telerik.Windows.RadRoutedEventArgs e )
    {
        //this.ListBox1.Items.Add("preview selected--------------Begin");
        Debug.WriteLine("preview selected--------------Begin");
        RadTreeViewItem itemContainer = e.Source as RadTreeViewItem;
        if (itemContainer == null)
        {
            this.ListBox1.Items.Add("itemContainer == null");
        }
     
        DataItem item = itemContainer.Item as DataItem;
        if (item == null)
        {
            this.ListBox1.Items.Add("item == null");
        }
     
        if (!item.isSelectable)
        //if ( !( item.Item as DataItem ).isSelectable )
        {
            e.Handled = true;
     
            //this.ListBox1.Items.Add("preview selected (cancel, item to cancel): " + GetDataItem(e.Source).Name);
            //this.ListBox1.Items.Add("preview selected (cancel, pre-revert, current selected item): " + GetDataItem(treeView.SelectedItem).Name);
            //this.ListBox1.Items.Add("preview selected (cancel, pre-revert, last unselected item): " + GetDataItem(unselectedItem).Name);
     
            Debug.WriteLine("preview selected (cancel, item to cancel): " + GetDataItem(e.Source).Name);
            Debug.WriteLine("preview selected (cancel, pre-revert, current selected item): " + GetDataItem(treeView.SelectedItem).Name);
            Debug.WriteLine("preview selected (cancel, pre-revert, last unselected item): " + GetDataItem(unselectedItem).Name);
                     
            //treeView.SelectedItem = unselectedItem;
     
            //this.ListBox1.Items.Add("preview selected (cancel, post-revert, current selected item): " + (treeView.SelectedItem == null ? "<null>" : GetDataItem(treeView.SelectedItem).Name));
            Debug.WriteLine("preview selected (cancel, post-revert, current selected item): " + (treeView.SelectedItem == null ? "<null>" : GetDataItem(treeView.SelectedItem).Name));
        }
        else
        {
            //this.ListBox1.Items.Add("preview selected Selectable item: " + item.Name);
            Debug.WriteLine("preview selected Selectable item: " + item.Name);
            this.mustStop = false;
        }
        //this.ListBox1.Items.Add("preview selected--------------End");
        Debug.WriteLine("preview selected--------------End");
    }
     
    void treeView_Unselected(object sender, Telerik.Windows.RadRoutedEventArgs e)
    {
        int i = 3;
        //this.ListBox1.Items.Add("unselected: " + GetDataItem(e.Source).Name);
        Debug.WriteLine("unselected: " + GetDataItem(e.Source).Name);
    }
     
    void treeView_Selected(object sender, Telerik.Windows.RadRoutedEventArgs e)
    {
        int i = 3;
        //this.ListBox1.Items.Add("selected: " + GetDataItem(e.Source).Name);
        Debug.WriteLine("selected: " + GetDataItem(e.Source).Name);
    }

    The code above produces the following output when "Item 0" is selected and you click on "Item 0.0":

    preview unselected: Item 0
    preview selected--------------Begin
    preview selected (cancel, item to cancel): Item 0.0
    preview selected (cancel, pre-revert, current selected item): Item 0
    preview selected (cancel, pre-revert, last unselected item): Item 0
    preview selected--------------Begin
    preview selected Selectable item: Item 0
    preview selected--------------End
    preview selected (cancel, post-revert, current selected item): <null>
    preview selected--------------End
    unselected: Item 0
    preview selected--------------Begin
    preview selected Selectable item: Item 0
    preview selected--------------End
    selected: Item 0

    Hope this info is helpful. Also there is another event you can use to implement the required functionality. Attach a handler to the SelectionChanged event that is fired after all 4 events (PreviewUnselected, Unselected, PreviewSelected, Selected). The following code below demonstrates that approach:

    private void treeView_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangedEventArgs e)
    {
        int i = 1;
        if (!this.mustReverSelection)
        {
            foreach (DataItem item in e.AddedItems)
            {
                if (item.isSelectable == false)
                {
                    this.mustReverSelection = true;
                    break;
                }
            }
        }
     
        if (this.mustReverSelection)
        {
            this.mustReverSelection = false;
     
            foreach (DataItem itemToRemove in e.AddedItems)
            {
                this.treeView.SelectedItems.Remove(itemToRemove);
            }
     
            foreach (DataItem itemToAdd in e.RemovedItems)
            {
                this.treeView.SelectedItems.Add(itemToAdd);
            }
        }
    }
    private bool mustReverSelection = false;

    Please let us know if you need more help or information about our controls.


    All the best,
    Hristo
    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. Thorsten
    Thorsten avatar
    26 posts
    Member since:
    Apr 2010

    Posted 09 Nov 2010 Link to this post

    Hi,

    thanks for the response.

    For a single selection scenario, I'm currently using a mix of both.
    bool _revertNextUnselection;
    private void Tree_PreviewSelected( object sender, RadRoutedEventArgs e )
    {
        var item = e.GetItem<IMyItem>( );
        if ( item != null && !item.IsSelectable ) // abort selection.
        {
            e.Handled = true;
            this._revertNextUnselection = this._tree.SelectedItem != null;
        }
     
    }
    private void Tree_SelectionChanged( object sender, SelectionChangedEventArgs e )
    {
        if ( this._revertNextUnselection )
        {
            this._revertNextUnselection = false;
            // revert last single unselection.
            if ( this._tree.SelectedItem == null
                    && e.AddedItems.Count == 0
                    && e.RemovedItems.Count == 1 )
                this._tree.SelectedItem = e.RemovedItems[0];
        }
    }

    Regarding multiselection:
    Is the sideeffect I mentioned below ( the duplicates within the SelectedItems collection ) considered as bug ?
  9. Hristo
    Admin
    Hristo avatar
    352 posts

    Posted 09 Nov 2010 Link to this post

    Hi Thorsten,

    I was not able to reproduce the duplicated items in SelectedItems collection. Can you provide us a step by step scenario that reproduces the issue with your project.

    Regarding your question: the answer should be yes.

    Sincerely yours,
    Hristo
    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
  10. Thorsten
    Thorsten avatar
    26 posts
    Member since:
    Apr 2010

    Posted 09 Nov 2010 Link to this post

    Hi,

    for sure, if you run the previously attached project (http://www.telerik.com/ClientsFiles/229138_289938-treeviewcontainerbindings-modified.zip), do the following:

    1. click on Item 0.0.0
    2. click on Item 0.0.1
    3. ctrl+click on Item 0.0.0
    4. ctrl+click on Item 0.0
    5. hit the dump selected items button.

    The output should now look like the attached screenshot and the Item 0.0.0 should now be twice within the SelectedItems collection.

    With kind regards

    Thorsten
  11. Answer
    Hristo
    Admin
    Hristo avatar
    352 posts

    Posted 11 Nov 2010 Link to this post

    Hi Thorsten,

    Thank you for providing us the steps to reproduce. Actually the reason this is happening is that SelectedItems collection contains DataItem object as well as RadTreeViewItem objects. This behavior is incorrect. When the tree view is data bound it should contain only business objects (DataItem(s)). I logged the bug in our public issue tracking system under the following link: http://www.telerik.com/support/pits.aspx#/public/wpf/3959


    Also there is a record in our PITS for IsSelectable property. You can vote for it here:
    http://www.telerik.com/support/pits.aspx#/public/silverlight/484

    Finally, I'm giving you 1000 telerik points for finding bug in our tree view.

    All the best,
    Hristo
    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
UI for WPF is Visual Studio 2017 Ready