SelectionBoxItemTemplate is sometimes applied too late

5 posts, 1 answers
  1. hwsoderlund
    hwsoderlund avatar
    419 posts
    Member since:
    Aug 2006

    Posted 05 Jun 2009 Link to this post

    Sometimes, and I'm not exactly sure when, the SelectionBoxItemTemplate is not applied until the combobox is opened, even though an item is selected. See the code below.

     
    <UserControl x:Class="TelerikTestProject.SilverlightControl4" 
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                 xmlns:telerikbase="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls" 
                 xmlns:telerikinput="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Input" 
                 xmlns:teleriknav="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Navigation" 
                 xmlns:local="clr-namespace:TelerikTestProject" 
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
                 Width="400" 
                 Height="300"
        <Grid x:Name="LayoutRoot" 
              Background="White"
     
            <Grid.Resources> 
                <telerikbase:ContainerBindingCollection x:Name="UserItemBindings"
                    <telerikbase:ContainerBinding PropertyName="IsSelected" 
                                                  Binding="{Binding IsSelected, Mode=TwoWay}" /> 
                </telerikbase:ContainerBindingCollection> 
     
                <DataTemplate x:Key="UserItemTemplate" 
                              telerikbase:ContainerBinding.ContainerBindings="{StaticResource UserItemBindings}"
                    <TextBlock Text="{Binding FirstName}"></TextBlock> 
                </DataTemplate> 
     
                <DataTemplate x:Key="UserItemTemplate_SelectionBox"
                    <TextBlock Text="{Binding FirstName}"></TextBlock> 
                </DataTemplate> 
     
            </Grid.Resources> 
     
            <telerikinput:RadComboBox x:Name="RCBUsers" 
                                      ItemsSource="{Binding Users}" 
                                      VerticalAlignment="Top" 
                                      HorizontalAlignment="Left" 
                                      ItemTemplate="{StaticResource UserItemTemplate}" 
                                      SelectionBoxItemTemplate="{StaticResource UserItemTemplate_SelectionBox}"
            </telerikinput:RadComboBox> 
     
        </Grid> 
    </UserControl> 
     

    using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Net; 
    using System.Windows; 
    using System.Windows.Controls; 
    using System.Windows.Documents; 
    using System.Windows.Input; 
    using System.Windows.Media; 
    using System.Windows.Media.Animation; 
    using System.Windows.Shapes; 
    using Telerik.Windows.Controls; 
    using System.Collections.ObjectModel; 
     
    namespace TelerikTestProject 
        public partial class SilverlightControl4 : UserControl 
        { 
            public SilverlightControl4() 
            { 
                InitializeComponent(); 
     
                var users = UserInfo2.Get10(); 
                users[3].IsSelected = true
     
                var container = new UserContainer() { Users = users }; 
     
                this.DataContext = container; 
            } 
        } 
     
        public class UserContainer 
        { 
            public ObservableCollection<UserInfo2> Users { getset; } 
        } 
     
        public class UserInfo2 
        { 
            public string FirstName { getset; } 
            public bool IsSelected { getset; } 
     
            public UserInfo2() 
            { 
            } 
     
            public static ObservableCollection<UserInfo2> Get10() 
            { 
                ObservableCollection<UserInfo2> users = new ObservableCollection<UserInfo2>(); 
     
                for (int i = 0; i < 100; i++) 
                { 
                    users.Add(new UserInfo2() 
                    { 
                        FirstName = String.Format("FirstName {0}", i), 
                    }); 
                } 
     
                return users; 
            } 
        } 
     



  2. Answer
    Valeri Hristov
    Admin
    Valeri Hristov avatar
    2252 posts

    Posted 08 Jun 2009 Link to this post

    Hi Henrik,

    The problem is that the RadComboBoxItem containers are generated after the combo box dropdown is opened for the first time. If the containers are not generated, the container bindings are not applied and the combo box does not "know" which data item is selected. The correct way to initially select an item is through one of the following properties: SelectedItem, SelectedIndex, SelectedValue.

    Regards,
    Valeri Hristov
    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. hwsoderlund
    hwsoderlund avatar
    419 posts
    Member since:
    Aug 2006

    Posted 12 Jun 2009 Link to this post

    Ok, I see the problem. Comboboxes in silverlight are a real pain in the butt, aren't they? Anyway, I thought I'd share with you a decent solution to the problem. It involves a converter that uses reflection, so it's not very performant with a large number of items, but it works ok when you bind often against collections of items where the items have a boolean property that is true for the selected item and false for the rest. Here's an example:

    <UserControl x:Class="TelerikTestProject.SilverlightControl4" 
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                 xmlns:telerikbase="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls" 
                 xmlns:telerikinput="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Input" 
                 xmlns:teleriknav="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Navigation" 
                 xmlns:local="clr-namespace:TelerikTestProject" 
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
                 Width="400" 
                 Height="300"
        <Grid x:Name="LayoutRoot" 
              Background="White"
     
            <Grid.Resources> 
     
                <local:SelectedItemConverter x:Key="SelectedItemConverter"></local:SelectedItemConverter> 
                 
                <telerikbase:ContainerBindingCollection x:Name="UserItemBindings"
                    <telerikbase:ContainerBinding PropertyName="IsSelected" 
                                                  Binding="{Binding IsSelected, Mode=TwoWay}" /> 
                </telerikbase:ContainerBindingCollection> 
     
                <DataTemplate x:Key="UserItemTemplate" 
                              telerikbase:ContainerBinding.ContainerBindings="{StaticResource UserItemBindings}"
                    <TextBlock Text="{Binding FirstName}"></TextBlock> 
                </DataTemplate> 
     
                <DataTemplate x:Key="UserItemTemplate_SelectionBox"
                    <TextBlock Text="{Binding FirstName}"></TextBlock> 
                </DataTemplate> 
     
            </Grid.Resources> 
     
            <telerikinput:RadComboBox x:Name="RCBUsers" 
                                      ItemsSource="{Binding Users}" 
                                      SelectedItem="{Binding Users, Converter={StaticResource SelectedItemConverter}, ConverterParameter='IsSelected'}" 
                                      VerticalAlignment="Top" 
                                      HorizontalAlignment="Left" 
                                      ItemTemplate="{StaticResource UserItemTemplate}" 
                                      SelectionBoxItemTemplate="{StaticResource UserItemTemplate_SelectionBox}"
            </telerikinput:RadComboBox> 
     
        </Grid> 
    </UserControl> 
     

    And the code:
    using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Net; 
    using System.Windows; 
    using System.Windows.Controls; 
    using System.Windows.Documents; 
    using System.Windows.Input; 
    using System.Windows.Media; 
    using System.Windows.Media.Animation; 
    using System.Windows.Shapes; 
    using Telerik.Windows.Controls; 
    using System.Collections.ObjectModel; 
    using System.Collections; 
    using System.Windows.Data; 
    using System.Globalization; 
     
    namespace TelerikTestProject 
        public partial class SilverlightControl4 : UserControl 
        { 
            public SilverlightControl4() 
            { 
                InitializeComponent(); 
     
                var users = UserInfo2.GetMany(); 
                users[98].IsSelected = true
     
                var container = new UserContainer() { Users = users }; 
     
                this.DataContext = container; 
            } 
        } 
     
        public class UserContainer 
        { 
            public ObservableCollection<UserInfo2> Users { getset; } 
        } 
     
        public class UserInfo2 
        { 
            public string FirstName { getset; } 
     
            public bool IsSelected { getset; } 
     
            public UserInfo2() 
            { 
            } 
     
            public static ObservableCollection<UserInfo2> GetMany() 
            { 
                ObservableCollection<UserInfo2> users = new ObservableCollection<UserInfo2>(); 
     
                for (int i = 0; i < 100; i++) 
                { 
                    users.Add(new UserInfo2() 
                    { 
                        FirstName = String.Format("FirstName {0}", i), 
                    }); 
                } 
     
                return users; 
            } 
        } 
     
        public class SelectedItemConverter : IValueConverter 
        { 
            #region IValueConverter Members 
     
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
            { 
                var propName = parameter.ToString(); 
     
                if (value is IEnumerable) 
                { 
                    var selectableItems = (from object val in (value as IEnumerable).AsQueryable() select val).Cast<object>().ToList(); 
     
                    foreach (object obj in selectableItems) 
                    { 
                        var pi = obj.GetType().GetProperty(propName); 
                        var isSelected = (bool)pi.GetValue(obj, null); 
     
                        if (isSelected) 
                            return obj; 
                    } 
                } 
     
                return null
            } 
     
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
            { 
                throw new NotImplementedException(); 
            } 
            #endregion 
        } 
     


  5. Valeri Hristov
    Admin
    Valeri Hristov avatar
    2252 posts

    Posted 12 Jun 2009 Link to this post

    Hello Henrik,

    I guess that you could simply implement an interface ISelectable in each data item, that will contain a single property IsSelected, then instead of using Reflection, you could cast the items to the interface and directly check the IsSelected property. But in this case you will lose the flexibility of the converter parameter.

    Other option would be, if your data source collections are generic, to use the classes in the System.Linq.Expressions namespace to build a dynamic Linq expression, that will be compiled into a typed lambda, that will be executed against each data item. This would provide great performance increase while keeping the flexibility. Unfortunately this is pretty advanced stuff and it will take me some time to provide an example.

    Sincerely yours,
    Valeri Hristov
    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.
  6. hwsoderlund
    hwsoderlund avatar
    419 posts
    Member since:
    Aug 2006

    Posted 12 Jun 2009 Link to this post

    Using an interface is what occured to me first, but the problem is that I'm binding against server-side entities that are duplicated on the client using "add service reference", so I would then have to use partial classes to implement the interface for all these entities (and there are lots of them).

    Doing it with a Linq expression sounds interesting though. We have a guy who knows a lot about pre-compiling expressions. I'll talk to him and see if he can help me.

    Thanks,
    /Henrik
Back to Top
DevCraft banner