Home > Blockchain >  How to change ItemsPanel in ItemsControl with DataTrigger?
How to change ItemsPanel in ItemsControl with DataTrigger?

Time:09-30

I was trying to make a UserControl that contains multiple elements, and when the button was clicked, the control changed the inner elements layout from vertical to horizontal.

I placed a layout changing ToggleButton in the ItemsControl template. I also created a style with triggers that should change the position of items by changing the ItemsPanel in ItemsControl. Additionally, triggers changes background of the ItemsControl.

<ItemsControl.Template>
  <ControlTemplate TargetType="ItemsControl">
     <Grid>
        <Grid.Style>
            <Style TargetType="Grid">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding ElementName=HideShowButton, Path=IsChecked}" Value="True">
                        <DataTrigger.Setters>
                            <Setter Property="ItemsControl.Background" Value="LightGreen"/>
                            <Setter Property="ItemsControl.ItemsPanel" Value="{DynamicResource HorizontalPanelTemplate}"/>
                        </DataTrigger.Setters>
                    </DataTrigger>

                    <DataTrigger Binding="{Binding ElementName=HideShowButton, Path=IsChecked}" Value="False">
                        <DataTrigger.Setters>
                            <Setter Property="ItemsControl.Background" Value="LightBlue"/>
                            <Setter Property="ItemsControl.ItemsPanel" Value="{DynamicResource VerticalPanelTemplate}"/>
                        </DataTrigger.Setters>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Grid.Style>

        <Grid.RowDefinitions>
            <RowDefinition x:Name="HeaderRow" Height="*"/>
            <RowDefinition x:Name="ToggleRow" Height="50"/>
        </Grid.RowDefinitions>

        <ItemsPresenter x:Name="ItemsPresenter" Grid.Row="0"/>

        <ToggleButton x:Name="HideShowButton" Grid.Row="1"
                                      Content="Change"
                                      VerticalAlignment="Center" HorizontalAlignment="Right"
                                      Margin="5"/>
     </Grid>
  </ControlTemplate>
</ItemsControl.Template>

As a result, the triggers works, the colors switch, but the arrangement of the elements always stays the same.

I tried to do it via GroupStyle as described in the article: https://social.msdn.microsoft.com/Forums/vstudio/en-US/b0ecb187-134e-4868-b56e-b67fb5ad18ff/itemscontrol-with-groupstyle-how-to-dynamically-switch-itemspanel?forum=wpf but failed, the appearance hasn't changed.

Full UserControl code

    <UserControl x:Class="HeaderControlDemo.HeaderControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <UserControl.Template>
        <ControlTemplate>
            <ItemsControl x:Name="ItemsControl" Margin="{TemplateBinding Padding}"
                          ItemsSource="{Binding Path=HeaderItems}">
                <ItemsControl.Resources>
                    <ItemsPanelTemplate x:Key="HorizontalPanelTemplate">
                        <StackPanel Orientation="Horizontal"/>
                    </ItemsPanelTemplate>

                    <ItemsPanelTemplate x:Key="VerticalPanelTemplate">
                        <StackPanel Orientation="Vertical"/>
                    </ItemsPanelTemplate>
                </ItemsControl.Resources>

                <ItemsControl.Template>
                    <ControlTemplate TargetType="ItemsControl">
                        <Grid>
                            <Grid.Style>
                                <Style TargetType="Grid">
                                    <Style.Triggers>
                                        <DataTrigger Binding="{Binding ElementName=HideShowButton, Path=IsChecked}" Value="True">
                                            <DataTrigger.Setters>
                                                <Setter Property="ItemsControl.Background" Value="LightGreen"/>
                                                <Setter Property="ItemsControl.ItemsPanel" Value="{DynamicResource HorizontalPanelTemplate}"/>
                                            </DataTrigger.Setters>
                                        </DataTrigger>

                                        <DataTrigger Binding="{Binding ElementName=HideShowButton, Path=IsChecked}" Value="False">
                                            <DataTrigger.Setters>
                                                <Setter Property="ItemsControl.Background" Value="LightBlue"/>
                                                <Setter Property="ItemsControl.ItemsPanel" Value="{DynamicResource VerticalPanelTemplate}"/>
                                            </DataTrigger.Setters>
                                        </DataTrigger>
                                    </Style.Triggers>
                                </Style>
                            </Grid.Style>

                            <Grid.RowDefinitions>
                                <RowDefinition x:Name="HeaderRow" Height="*"/>
                                <RowDefinition x:Name="ToggleRow" Height="50"/>
                            </Grid.RowDefinitions>

                            <ItemsPresenter x:Name="ItemsPresenter" Grid.Row="0"/>

                            <ToggleButton x:Name="HideShowButton" Grid.Row="1"
                                          Content="Change"
                                          VerticalAlignment="Center" HorizontalAlignment="Right"
                                          Margin="5"/>
                        </Grid>
                    </ControlTemplate>
                </ItemsControl.Template>

                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <Grid VerticalAlignment="Top" HorizontalAlignment="Left"
                              Background="Gray">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="30"/>
                                <RowDefinition Height="*"/>
                            </Grid.RowDefinitions>

                            <TextBlock Grid.Row="0" 
                                       HorizontalAlignment="Center" VerticalAlignment="Center"
                                       Text="Header"/>
                            <Border Grid.Row="1" 
                                    HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                                    Padding="5"
                                    Background="LightGray">
                                <ContentControl>
                                    <ContentControl.ContentTemplate>
                                        <DataTemplate>
                                            <TextBox DataContext="{Binding RelativeSource={RelativeSource AncestorType=ContentControl}, Path=DataContext}" 
                                                     Text="{Binding Path=PropertyValue, UpdateSourceTrigger=PropertyChanged}"
                                                     FontSize="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=FontSize}"
                                                     FontFamily="{Binding RelativeSource={RelativeSource AncestorType=UserControl}, Path=FontFamily}"
                                                     VerticalAlignment="Top"
                                                     Background="White"/>
                                        </DataTemplate>
                                    </ContentControl.ContentTemplate>
                                </ContentControl>
                            </Border>
                        </Grid>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ControlTemplate>
    </UserControl.Template>
</UserControl>

CodePudding user response:

You may use a DataTrigger to change the Orientation of the StackPanel that is used as ItemsPanel:

<ItemsControl ItemsSource="{Binding}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel>
                <StackPanel.Style>
                    <Style TargetType="StackPanel">
                        <Style.Triggers>
                            <DataTrigger
                                Binding="{Binding IsChecked, ElementName=tb}"
                                Value="True">
                                <Setter Property="Orientation" Value="Horizontal"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </StackPanel.Style>
            </StackPanel>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

<ToggleButton x:Name="tb" Content=" Horizontal "/>
  • Related