水平手风琴控制?

时间:2016-11-16 13:16:54

标签: wpf xaml accordion horizontal-accordion

我想要一个控件,其行为如下:

  • 像网格一样行事
  • 每个子控件都嵌入在一个水平Expander中(其标题绑定到控件的Tag属性)
  • 每个Expander都有自己的ColumnDefinition
  • 一次只能扩展其中一个扩展程序
  • 非扩展扩展器' ColumnDefinition的宽度设置为Auto
  • 扩展的Expander的一个是*(星级)

它必须使用这些精确控件(网格/扩展器),而不是一些自定义控件,因此我的应用程序的样式可以自动应用于它们。

我似乎无法找到已经制作的东西,似乎没有内置的解决方案(如果只有#34;填充" StackPanel ......)并且我能来的唯一解决方案最好是制作我自己的Grid实现,这似乎......令人生畏。

是否有找到或实施此类控制的解决方案?

这就是我现在所拥有的。它没有处理"单扩展"也不是填充物。我不知道StackPanel或Expander是否应该为此负责。

<ItemsControl>
    <ItemsControl.Resources>
        <DataTemplate x:Key="verticalHeader">
            <ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type Expander}}, Path=Header}" />
        </DataTemplate>
        <Style TargetType="{x:Type Expander}"
               BasedOn="{StaticResource {x:Type Expander}}">
            <Setter Property="HeaderTemplate"
                    Value="{StaticResource verticalHeader}" />
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="HorizontalAlignment" Value="Stretch"/>
            <Setter Property="ExpandDirection"
                    Value="Right" />
        </Style>
    </ItemsControl.Resources>
    <ItemsControl.Template>
        <ControlTemplate>
            <!-- Damn you, StackPanel! -->
            <StackPanel Orientation="Horizontal" IsItemsHost="True"/>
        </ControlTemplate>
    </ItemsControl.Template>
    <Expander Header="Exp1">
        <TextBlock Text="111111111" Background="Red"/>
    </Expander>
    <Expander Header="Exp2">
        <TextBlock Text="222222222" Background="Blue"/>
    </Expander>
    <Expander Header="Exp3">
        <TextBlock Text="333333333" Background="Green"/>
    </Expander>
</ItemsControl>

1 个答案:

答案 0 :(得分:1)

我的第一个想法是用行为执行此类操作。这是您可以添加到现有XAML控件的一些功能,可以为您提供一些额外的自定义。

我只看了一些没有使用ItemsSource的东西,因为我使用的是Grid with Columns等。但是在一个普通的网格中,你可以添加一个倾听它的行为&#39 ; s孩子们的扩展和倒塌事件是这样的:

public class ExpanderBehavior : Behavior<Grid>
{
    private List<Expander> childExpanders = new List<Expander>();

    protected override void OnAttached()
    {
        //since we are accessing it's children, we have to wait until initialise is complete for it's children to be added
        AssociatedObject.Initialized += (gridOvject, e) =>
        {
            foreach (Expander expander in AssociatedObject.Children)
            {
                //store this so we can quickly contract other expanders (though we could just access Children again)
                childExpanders.Add(expander);

                //track expanded events
                expander.Expanded += (expanderObject, e2) =>
                {
                    //contract all other expanders
                    foreach (Expander otherExpander in childExpanders)
                    {
                        if (expander != otherExpander && otherExpander.IsExpanded)
                        {
                            otherExpander.IsExpanded = false;
                        }
                    }

                    //set width to star for the correct column
                    int index = Grid.GetColum(expanderObject as Expander);

                    AssociatedObject.ColumnDefinitions[index].Width = new GridLength(1, GridUnitType.Star);
                };

                //track Collapsed events
                expander.Collapsed += (o2, e2) =>
                {
                    //reset all to auto
                    foreach (ColumnDefinition colDef in AssociatedObject.ColumnDefinitions)
                    {
                        colDef.Width = GridLength.Auto;
                    }
                };
            }
        };
    }
}

像这样使用它,请注意您必须添加System.Windows.Interactivity作为项目的参考:

<Window ...
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 
        xmlns:local="...">
    <Window.Resources>
        <DataTemplate x:Key="verticalHeader">
            <ItemsControl ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type Expander}}, Path=Header}" />
        </DataTemplate>
        <Style TargetType="{x:Type Expander}"
               BasedOn="{StaticResource {x:Type Expander}}">
            <Setter Property="HeaderTemplate"
                    Value="{StaticResource verticalHeader}" />
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="HorizontalAlignment" Value="Stretch"/>
            <Setter Property="ExpandDirection"
                    Value="Right" />
        </Style>

        <local:ExpanderBehavior x:Key="ExpanderBehavor"/>
    </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>

        <i:Interaction.Behaviors>
            <local:ExpanderBehavior/>
        </i:Interaction.Behaviors>

        <Expander Header="Exp1">
            <TextBlock Text="111111111" Background="Red"/>
        </Expander>
        <Expander Header="Exp2" Grid.Column="1">
            <TextBlock Text="222222222" Background="Blue"/>
        </Expander>
        <Expander Header="Exp3" Grid.Column="2">
            <TextBlock Text="333333333" Background="Green"/>
        </Expander>
    </Grid>
</Window>

最终结果:

enter image description here

编辑:使用ItemsControl - 将其添加到托管项目的网格中,并添加一点来管理列映射

public class ItemsSourceExpanderBehavior : Behavior<Grid>
{
    private List<Expander> childExpanders = new List<Expander>();

    protected override void OnAttached()
    {
        AssociatedObject.Initialized += (gridOvject, e) =>
        {
            //since we are accessing it's children, we have to wait until initialise is complete for it's children to be added
            for (int i = 0; i < AssociatedObject.Children.Count; i++)
            {
                Expander expander = AssociatedObject.Children[i] as Expander;

                //sort out the grid columns
                AssociatedObject.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
                Grid.SetColumn(expander, i);

                childExpanders.Add(expander);

                //track expanded events
                expander.Expanded += (expanderObject, e2) =>
                {
                    foreach (Expander otherExpander in childExpanders)
                    {
                        if (expander != otherExpander && otherExpander.IsExpanded)
                        {
                            otherExpander.IsExpanded = false;
                        }
                    }

                    //set width to auto
                    int index = AssociatedObject.Children.IndexOf(expanderObject as Expander);

                    AssociatedObject.ColumnDefinitions[index].Width = new GridLength(1, GridUnitType.Star);
                };

                //track Collapsed events
                expander.Collapsed += (o2, e2) =>
                {
                    foreach (ColumnDefinition colDef in AssociatedObject.ColumnDefinitions)
                    {
                        colDef.Width = GridLength.Auto;
                    }
                };
            }
        };
    }
}

用于:

<ItemsControl>
    <ItemsControl.Template>
        <ControlTemplate>
            <Grid IsItemsHost="True">
                <i:Interaction.Behaviors>
                    <local:ItemsSourceExpanderBehavior/>
                </i:Interaction.Behaviors>
            </Grid>
        </ControlTemplate>
    </ItemsControl.Template>
    <Expander Header="Exp1">
        <TextBlock Text="111111111" Background="Red"/>
    </Expander>
    <Expander Header="Exp2">
        <TextBlock Text="222222222" Background="Blue"/>
    </Expander>
    <Expander Header="Exp3">
        <TextBlock Text="333333333" Background="Green"/>
    </Expander>
</ItemsControl>

注意,如果您对ItemsSource有任何更改,您必须添加一些逻辑来管理新的/删除的子项!