Programmatically selecting items does not work in sync with manually selecting

4 posts, 0 answers
  1. Peter
    Peter avatar
    8 posts
    Member since:
    Feb 2013

    Posted 06 Sep 2013 Link to this post

    Hello,

    I have an issue with selecting items in a RadListBox.
    I have initially a selected item (programmatically), when i want to extend that selection manually (shift-key) i get completely different items selected. If I could get a work around for this problem, it would be great.

    It seems to me that the UI-selection never gets cleared (which i clearly do in code) and when i extend the selection it uses the 'non-cleared' selected item instead of the real selected item.

    One example case where it goes wrong (using the supplied code below):
    1. Select item 15
    2. Press button 'First item'
    3. Extend the selection to item 3 by holding the shift-button and clicking on item 3
    4. result: instead of selecting items 1-3, you will have items 3-15 selected

    <UserControl x:Class="SelectedItemsRadListBox.MainPage"
        xmlns:SelectedItemsRadListBox="clr-namespace:SelectedItemsRadListBox" mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400">
     
        <UserControl.Resources>
            <SelectedItemsRadListBox:ViewModel
                x:Key="ViewModel" />
            <DataTemplate
                x:Key="template"
                DataType="SelectedItemsRadListBox:TestObject">
                <Grid>
                    <Border
                        BorderThickness="0,0,1,0"
                        BorderBrush="Black"
                        Padding="5,0,5,0"
                        VerticalAlignment="Center"
                        HorizontalAlignment="Right">
                        <TextBlock
                            FontSize="10"
                            Text="{Binding Path=Index}" />
                    </Border>
                </Grid>
            </DataTemplate>
        </UserControl.Resources>
         
        <Grid
            DataContext="{StaticResource ViewModel}"
            x:Name="LayoutRoot"
            Background="White">
            <Grid.ColumnDefinitions>
                <ColumnDefinition
                    Width="*" />
                <ColumnDefinition
                    Width="*" />
                <ColumnDefinition
                    Width="*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition
                    Height="124*" />
                <RowDefinition
                    Height="176*" />
            </Grid.RowDefinitions>
     
            <telerik:RadButton
                Content="First item"
                Command="{Binding Path=First}" />
            <telerik:RadButton
                Content="Middle item"
                Grid.Column="1"
                Command="{Binding Path=Middle}" />
            <telerik:RadButton
                Content="Last item"
                Grid.Column="2"
                Command="{Binding Path=Last}" />
     
            <telerik:RadListBox
                Grid.Row="1"
                Grid.ColumnSpan="3"
                Margin="5,10,5,0"
                ItemsSource="{Binding Path=TestObjects}"
                SelectionMode="Extended"
                ItemTemplate="{StaticResource template}">
                <i:Interaction.Behaviors>
                    <SelectedItemsRadListBox:SelectionRadListBoxBehavior
                        SelectedItems="{Binding Path=SelectedTestObjects, Mode=TwoWay}" />
                </i:Interaction.Behaviors>
                 
            </telerik:RadListBox>
     
        </Grid>
    </UserControl>

    using System;
    using System.Collections;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Linq;
    using System.Windows;
    using System.Windows.Interactivity;
    using Telerik.Windows.Controls;
     
    namespace SelectedItemsRadListBox
    {
        public class SelectionRadListBoxBehavior : Behavior<RadListBox>
        {
            #region SelectedItems (ObservableCollection<TestObject>)
     
            public static readonly DependencyProperty SelectedItemsProperty =
                DependencyProperty.Register("SelectedItems", typeof(ObservableCollection<TestObject>),
                                            typeof(SelectionRadListBoxBehavior),
                                            new PropertyMetadata(default(ObservableCollection<TestObject>),
                                                                 OnSelectedItemsPropertyChanged));
     
            private static void OnSelectedItemsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                var selectionRadListBoxBehavior = d as SelectionRadListBoxBehavior;
                if (selectionRadListBoxBehavior == null) return;
     
                var oldCollection = e.OldValue as ObservableCollection<TestObject>;
                if (oldCollection != null)
                    oldCollection.CollectionChanged -= selectionRadListBoxBehavior.SelectedItemsCollectionChanged;
     
                var newCollection = e.NewValue as ObservableCollection<TestObject>;
                if (newCollection != null)
                    newCollection.CollectionChanged += selectionRadListBoxBehavior.SelectedItemsCollectionChanged;
            }
     
            private bool _isCollectionUpdateDisabled;
            private void SelectedItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                if (_isCollectionUpdateDisabled)
                    return;
     
                try
                {
                    _isListBoxUpdateDisabled = true;
                    switch (e.Action)
                    {
                        case NotifyCollectionChangedAction.Add:
                        case NotifyCollectionChangedAction.Remove:
                            var newSelectedItems = (IList)sender;
                            AssociatedObject.SelectedItems.Clear();
                            AssociatedObject.SelectItems(newSelectedItems);
                            if (newSelectedItems.Count > 0)
                                AssociatedObject.ScrollIntoView(AssociatedObject.Items.IndexOf(newSelectedItems[0]));
                            break;
                        case NotifyCollectionChangedAction.Replace:
                            break;
                        case NotifyCollectionChangedAction.Reset:
                            AssociatedObject.SelectedItems.Clear();
                            break;
                        default:
                            throw new ArgumentOutOfRangeException();
                    }
                }
                finally
                {
                    _isListBoxUpdateDisabled = false;
                }
            }
     
            public ObservableCollection<TestObject> SelectedItems
            {
                get { return (ObservableCollection<TestObject>)GetValue(SelectedItemsProperty); }
                set { SetValue(SelectedItemsProperty, value); }
            }
     
            #endregion
     
            private bool _isListBoxUpdateDisabled;
            private void AssociatedObjectSelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                if (_isListBoxUpdateDisabled)
                    return;
                try
                {
                    _isCollectionUpdateDisabled = true;
     
                    SelectedItems.Clear();
                    var selectedItems = AssociatedObject.SelectedItems.OfType<TestObject>();
                    foreach (var selectedItem in selectedItems)
                        SelectedItems.Add(selectedItem);
                }
                finally
                {
                    _isCollectionUpdateDisabled = false;
                }
            }
     
            #region Overrides of Behavior
     
            protected override void OnAttached()
            {
                base.OnAttached();
     
                if (SelectedItems == null) SelectedItems = new ObservableCollection<TestObject>();
                AssociatedObject.SelectionChanged += AssociatedObjectSelectionChanged;
            }
     
     
            protected override void OnDetaching()
            {
                AssociatedObject.SelectionChanged -= AssociatedObjectSelectionChanged;
     
                base.OnDetaching();
            }
     
            #endregion
        }
    }

    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Windows.Input;
    using Telerik.Windows.Controls;
     
    namespace SelectedItemsRadListBox
    {
        public class ViewModel : ViewModelBase
        {
            #region property SelectedTestObjects
     
            private readonly ObservableCollection<TestObject> _selectedTestObjects =
                new ObservableCollection<TestObject>();
     
            public ObservableCollection<TestObject> SelectedTestObjects
            {
                get { return _selectedTestObjects; }
            }
     
            #endregion property SelectedTestObjects
     
     
            #region property TestObjects
     
            private readonly ObservableCollection<TestObject> _testObjects =
                new ObservableCollection<TestObject>();
     
            public ObservableCollection<TestObject> TestObjects
            {
                get { return _testObjects; }
            }
     
            #endregion property TestObjects
     
            #region Commands
     
            public ICommand First { get; set; }
            public ICommand Middle { get; set; }
            public ICommand Last { get; set; }
     
            private void InitCommands()
            {
                First = new DelegateCommand(o => OnFirst());
                Middle = new DelegateCommand(o => OnMiddle());
                Last = new DelegateCommand(o => OnLast());
            }
     
            #endregion
     
            public ViewModel()
            {
                InitCommands();
     
                for (int i = 0; i < 20; i++)
                {
                    TestObjects.Add(new TestObject(i));
                }
            }
     
            #region Command handlers
     
            private void OnFirst()
            {
                SelectedTestObjects.Clear();
                SelectedTestObjects.Add(TestObjects.First());
            }
     
            private void OnMiddle()
            {
                SelectedTestObjects.Clear();
                SelectedTestObjects.Add(TestObjects[TestObjects.Count / 2]);
            }
     
            private void OnLast()
            {
                SelectedTestObjects.Clear();
                SelectedTestObjects.Add(TestObjects.Last());
            }
     
            #endregion
        }
    }

    namespace SelectedItemsRadListBox
    {
        public class TestObject
        {
            private readonly int _index;
     
            public TestObject(int index)
            {
                _index = index;
            }
     
            public int Index { get { return _index; } }
        }
    }
  2. Polya
    Admin
    Polya avatar
    200 posts

    Posted 11 Sep 2013 Link to this post

    Hi Peter,

    Thank you for contacting us and pointing this problem. It is now logged in our PITS, you can track its progress here.

    The problem is that when RadListBox SelectedItem is changed the behavior (extended, multiple)  the Anchor of the selection is not changed. As a workaround I am sending you a sample project using your code that has a modified ExtendedBehavior class, called CustomExtendedBehavior. In the GetItemsForSelection method I included the following code:
    if (itemsForSelection.Count == 1)
    {
        selectionState.Anchor = itemsForSelection[0];
    }

    With this code I am setting the Anchor to the specified ( first, middle, last ) item. Modify this in a way that suits your needs. Also I removed the SelectionRadListBoxBehavior as setting the SelectionMode="Extended" triggers the same functionality. In the ViewModel I included the SelectedObject property that I bind the RadListBox SelectedItem to.

    Hopefully this helps. After we fix this issue you will no longer need the CustomExtendedBehavior.

    I've updated your Telerik Points as a small sign of our appreciation for your efforts. 

    Regards,
    Polya
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for SILVERLIGHT.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
  3. DevCraft banner
  4. Peter
    Peter avatar
    8 posts
    Member since:
    Feb 2013

    Posted 11 Sep 2013 Link to this post

    Hi Polya,

    Thank you for the answer, but we are working with telerik version 2012.1.215.1050.
    Is there a work around for the problem for this version?

    Regards,
    Peter
  5. Polya
    Admin
    Polya avatar
    200 posts

    Posted 16 Sep 2013 Link to this post

    Hi Peter,

    Unfortunately version 2012.1.215.1050 of Telerik controls is too old for this kind of workaround.
    The solution I proposed is valid with the newer versions, so you may consider upgrading.

    We're sorry for any inconvenience caused.

    Regards,
    Polya
    Telerik
    TRY TELERIK'S NEWEST PRODUCT - EQATEC APPLICATION ANALYTICS for SILVERLIGHT.
    Learn what features your users use (or don't use) in your application. Know your audience. Target it better. Develop wisely.
    Sign up for Free application insights >>
Back to Top