Search code examples
silverlightwindows-phone-8listboxorientationitemspanel

Dynamically change ListBox orientation with Style


I defined styles for a ListBox to display items with vertical or horizontal scrolling orientation:

<Style x:Key="ListBoxVerticalStyle" TargetType="ListBox">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="BorderBrush" Value="Transparent"/>
    <Setter Property="Padding" Value="0"/>
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Vertical" />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style x:Key="ListBoxHorizontalStyle" TargetType="ListBox">
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/>
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"/>
    <Setter Property="BorderThickness" Value="0"/>
    <Setter Property="BorderBrush" Value="Transparent"/>
    <Setter Property="Padding" Value="0"/>
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal" />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
</Style>

They are working fine when used statically in xaml, e.g.

<ListBox Style="{StaticResource ListBoxHorizontalStyle}" ...

I am trying to update the orientation dynamically in C# with this code:

if (horizontal)
{
    MyListBox.Style = Resources["ListBoxHorizontalStyle"] as Style;
}
else
{
    MyListBox.Style = Resources["ListBoxVerticalStyle"] as Style;
}
MyListBox.InvalidateMeasure();
MyListBox.InvalidateArrange();

The ListBox.ScrollViewer orientation does change, however the items remain stacked in their original orientation. It's as though the ItemsPanel update doesn't get applied. Is there something I need to do to force the ListBox to completely refresh itself?


Solution

  • I don't think it's raising the PropertyChange event when you do it that way. Top of my head, I only have two solutions. One is derived your own custom ListBox and VisualStates, which is far to long to put as a solution here. The other option is pretty easy, we just need to notify that the property has changed and the easiest way I know how to do that is just bind it your ViewModel.

    For this, I just going to use the Page as the ViewModel, so your XAML is like so


    <ListBox x:Name="myListBox">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="{Binding MYO}"/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
    

    C#

    using System.ComponentModel; // INotifyPropertyChanged
    
    public partial class MainPage : PhoneApplicationPage, INotifyPropertyChanged 
    {
        // implement the INotify
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (null != handler)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    
        // Constructor
        public MainPage()
        {
            InitializeComponent();           
        }
    
        private System.Windows.Controls.Orientation _myo;
        public System.Windows.Controls.Orientation MYO
        {
            get { return _myo; }
            set { _myo = value; NotifyPropertyChanged("MYO"); }
        }
    
        private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
        {
            myListBox.DataContext = this;                          // have to set the datacontext to point to the page
            MYO = System.Windows.Controls.Orientation.Horizontal;  // set it to Horizontal
            // MYO = System.Windows.Controls.Orientation.Vertical; // set it to Vertical
        }
    }