Question

OriTester1 on Thu, 12 Jan 2012 10:49:31


Hi,

I have a multiSelect ListBox and I am trying to set the IsSelected property of the list items to be 'true' in XAML, so that the items appear selected as they are added automatically.  However, as items are added, they are not shown as selected.  Conversely, I can set the HorizontalContentAlignment to 'Right' and this does work - they appear right-aligned as expected.


This simple test app reproduces the problem:

XAML

<ListBox x:Name="lbMain" SelectionMode="Multiple">  
    <ListBox.ItemContainerStyle> 
        <Style TargetType="ListBoxItem">  
            <Setter Property="IsSelected" Value="True" />      <!-- This HAS NO EFFECT --> 
            <Setter Property="HorizontalContentAlignment" Value="Right" />       <!-- This WORKS! --> 
        </Style> 
    </ListBox.ItemContainerStyle> 
</ListBox> 


C#

private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)  
{  
    // These items are added as right-aligned, but NOT selected  
 
    lbMain.Items.Add("The Cave of Time");  
    lbMain.Items.Add("Journey Under the Sea");  
    lbMain.Items.Add("By Ballooon to the Sahara");  
    lbMain.Items.Add("Space and Beyond");  


1. Why does the HorizontalContentAlignment value work while the IsSelected property value is ignored?
2. How can I add selected items WITHOUT explicitly creating ListBoxItem objects (my actual application binds the list items to a custom collection in my ViewModel).


Sponsored



Replies

Benjamin Roux [MSFT] on Thu, 12 Jan 2012 21:25:28


IsSelected is for single selection.
If you want to select all by default you can call the SelectAll method.
If you want to add a selected item in the Listbox I'm not sure if you can do it. Maybe by adding the item in the SelectedItems list.

OriTester1 on Fri, 13 Jan 2012 10:30:03


Thanks for the reply.  In code, you can indeed add items to the SelectedItems property:

c#
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)  
        {  
            lbMain.Items.Add("The Cave of Time");  
            lbMain.Items.Add("Journey Under the Sea");  
            lbMain.Items.Add("By Ballooon to the Sahara");  
            lbMain.Items.Add("Space and Beyond");  
 
            lbMain.SelectedItems.Add(lbMain.Items[0]);  
            lbMain.SelectedItems.Add(lbMain.Items[1]);  
            lbMain.SelectedItems.Add(lbMain.Items[2]);  
            lbMain.SelectedItems.Add(lbMain.Items[3]);  
        } 

And this works as expected, but my actual application is using MVVM and I would prefer to use bindings if possible.  The SelectedItems property is not accessible via XAML, so I'm thinking the only way to do this will be to write code-behind (not ideal, but doable)?

Benjamin Roux [MSFT] on Fri, 13 Jan 2012 15:25:07


Since SelectedItems is in read-only (so you can't bind anything to it), the workaround is to create a behavior with a Dependency Properties named SelectedItems (you will bind to this property). The behavior will do the bridge between your ViewModel and the SelectedItems of the ListBox.

OriTester1 on Tue, 17 Jan 2012 17:12:58


Thank you for the suggestion.  I'm new to Windows Phone 7 and I'm not sure what you mean exactly.

Could you please elaborate in more detail where the dependency property 'SelectedItems' should go?  In my custom Behaviour class?  What would the XAML then look like?

OriTester1 on Wed, 18 Jan 2012 15:42:05


Success.  I managed to get this working by creating a 'Behaviour' class called ListBoxMultipleBehaviour containing a single custom SelectedItems Dependency Property.  This class can then be referenced in XAML to attach this custom property to any ListBox control.  So the ListBox control is given an extra property called ListBoxMultipleBehaviour.SelectedItems and most importantly, this custom property can be bound to the ViewModel, the same way any other property can.

So I bind the ListBoxMultipleBehaviour.SelectedItems property in XAML to my ViewModel's SelectedItems property and I'm then able to do the necessary workaround within the DependencyPropertyChanged callback to physically add the elements to the ListBox's ACTUAL SelectedItems.

Source code below in case anyone is interested.

ListBoxMultipleBehaviour.cs
public static class ListBoxMultipleBehaviour  
{  
    public static List<string> GetSelectedItems(ListBox element)  
    {  
        if (element != null)  
            return element.GetValue(SelectedItemsProperty) as List<string>;  
        return null;  
    }  
 
    public static void SetSelectedItems(ListBox element, List<string> value)  
    {  
        if (element != null)  
            element.SetValue(SelectedItemsProperty, value);  
    }  
 
    public static readonly DependencyProperty SelectedItemsProperty =  
        DependencyProperty.RegisterAttached("SelectedItems",  
        typeof(List<string>),  
        typeof(ListBoxMultipleBehaviour),  
        new PropertyMetadata(null, OnSelectedItemsPropertyChanged));  
 
    private static void OnSelectedItemsPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)  
    {  
        var lb = obj as ListBox;  
        if (lb != null)  
        {  
            lb.SelectedItems.Clear();  
 
            foreach (string l in (List<string>)e.NewValue)  
            {  
                lb.SelectedItems.Add(l);  
            }  
        }  
    }  

MainViewModel.cs
public class MainViewModel  
{  
    private List<string> _strItems;  
 
    public MainViewModel()  
    {  
        _strItems = new List<string>();  
        _strItems.Add("The Cave of Time");  
        _strItems.Add("Journey Under the Sea");  
        _strItems.Add("By Ballooon to the Sahara");  
        _strItems.Add("Space and Beyond");  
    }  
 
    public List<string> Items  
    {  
        get { return _strItems; }  
    }  
 
    public List<string> SelectedItems  
    {  
        get { return _strItems; }  
    }  

MainPage.xaml
<phone:PhoneApplicationPage     
    ...     
    xmlns:local="clr-namespace:TestProject"    
    ...>     
    
    ...     
    <ListBox x:Name="lbMain" SelectionMode="Multiple"    
        ItemsSource="{Binding Path=Items}"    
        local:ListBoxMultipleBehaviour.SelectedItems="{Binding Path=SelectedItems}">     
    ...     
</phone:PhoneApplicationPage>   

This causes all the items to be selected automatically.  Alternatively, the SelectedItems property in the ViewModel can be modified to return only the items you wish to be selected.

Just change 'TestProject' to whichever namespace your project has.

Thanks to Benjamin for setting me on the right path and to this guy for seeing me through:
http://www.eugenedotnet.com/2011/04/binding-text-containing-tags-to-textblock-inlines-using-attached-property-in-silverlight-for-windows-phone-7/

Sid_ucer on Mon, 03 Dec 2012 11:38:33


Just what I was looking for.

Works like a charm with a few modifications in case you wanted to bind n items as selected items.

Thanks a lot!

Lightray_DVD on Wed, 24 Apr 2013 15:31:38


Hi,

I tried your solution on VS2010-WP7.1.

I defined a second list into viewmodel in order to have the SelectedItems list but the "OnSelectedItemsPropertyChanged" method is called at page loading only.

I think that the problem is into DependencyProperty definition because I tried a solution with AttachedCommandBehavior with the same result.

Could you help me?

Thanks