WPF仅在可用空间中展开RadPanelBarItem

时间:2012-06-04 14:45:06

标签: wpf radpanelbar

我有一个RadPanelBar,每个RadPanelItem都有一个实体列表(每个Item中的不同列表)。 List中的每个项目都显示为GroupBox。对于大量项目,必须滚动RadPanelBar,以便其他RadPanelBarItem可见。我希望滚动条出现在每个RadPanelBarItem中,以便所有RadPanelBarItems同时在屏幕上可见,如果项目的内容太长,用户只需在每个RadPanelBarItem内滚动。

我正在使用每个RadPanelBarItem的ItemsSource属性并设置其ItemTemplate以显示GroupBox。

有没有一种好方法可以做到这一点,所以一切(高度等)都保持动态?

谢谢!

1 个答案:

答案 0 :(得分:1)

似乎没有简单的方法可以做到这一点。当我问一个类似的问题时,我得到了Telerik的以下回复:

  

如果我的案例正确,你有几个选择:

     

1)设置PanelBarItem的大小。这样你就可以限制它们的大小。如果   你将项目总和大小与PanelBar的大小相匹配   消除剪报。

     

2)按顺序自定义PanelBar和PanelBarItem控件模板   支持自动比例尺寸调整。在这种情况下你应该   从PanelBar控件模板中删除ScrollViewer并添加一个   ScrollViewer在顶级PanelBarItem控件模板中(周围   ItemsPresenter)。您还应将RadPanelBar ItemsPanel更改为   适当的小组。大概。它将是一个自定义面板   为了垂直测量相同尺寸的物品。

我尝试过自定义Panel并修改控件模板。我有它工作,但它是相当多的代码,但在这里:

<强> DistributedHeightPanel.cs

这是自定义面板,用于布局并分配可用高度。

/// <summary>
/// Panel that distributes the available height amongst it's children (like a vertical StackPanel but the children are not allowed to be placed "outside" the parent's visual area).
/// </summary>
public class DistributedHeightPanel : Panel
{
    /// <summary>
    /// If set to a positive number, no child will get less height than specified.
    /// </summary>
    public double ItemsMinHeight
    {
        get { return (double)GetValue(ItemsMinHeightProperty); }
        set { SetValue(ItemsMinHeightProperty, value); }
    }

    public static readonly DependencyProperty ItemsMinHeightProperty =
        DependencyProperty.Register("ItemsMinHeight", typeof(double), typeof(DistributedHeightPanel), new UIPropertyMetadata(0.0));


    public DistributedHeightPanel()
        : base()
    {
    }

    protected override Size MeasureOverride(Size availableSize)
    {
        List<double> heights = new List<double>();
        //Find out how much height each child desire if it was the only child
        foreach (UIElement child in InternalChildren)
        {
            child.Measure(availableSize);
            heights.Add(child.DesiredSize.Height);
        }
        //Calculate ratio
        double ratio = GetRatio(availableSize.Height, heights);
        //Do the "real" Measure
        foreach (UIElement child in InternalChildren)
        {
            double actualHeight = child.DesiredSize.Height;
            if (ratio < 1)
            {
                //If ratio < 1 then the child can't have all the space it wants, calculate the new height
                actualHeight = child.DesiredSize.Height * ratio;
            }
            if (ItemsMinHeight > 0 && actualHeight < ItemsMinHeight)
            {
                //If ItemsMinHeight is set and the child is to small, then set the childs height to ItemsMinHeight
                actualHeight = ItemsMinHeight;
            }
            child.Measure(new Size(availableSize.Width, actualHeight));
        }
        return availableSize;
    }

    /// <summary>
    /// Calculates the ratio for fitting all heights in <paramref name="heightsToDistribute"/> in the total available height (as supplied in <paramref name="availableHeight"/>)
    /// </summary>
    private double GetRatio(double availableHeight, List<double> heightsToDistribute)
    {
        //Copy the heights list
        List<double> heights = new List<double>(heightsToDistribute);
        double desiredTotalHeight = heights.Sum();
        //If no height is desired then return 1
        if (desiredTotalHeight <= 0)
            return 1;
        //Calculate ratio
        double ratio = availableHeight / desiredTotalHeight;
        //We only want to compress so if ratio is higher than 1 return 1
        if (ratio > 1)
        {
            return 1;
        }
        //Check if heights become too small when the ratio is used
        int tooSmallCount = heights.Count(d => d * ratio < ItemsMinHeight);
        //If no or all all heights are too small: return the calculated ratio
        if (tooSmallCount == 0 || tooSmallCount == heights.Count)
        {
            return ratio;
        }
        else
        {
            //Remove the items which becomes too small and get a ratio without them (they will get ItemsMinHeight)
            heights.RemoveAll(d => d * ratio < ItemsMinHeight);
            return GetRatio(availableHeight - ItemsMinHeight * tooSmallCount, heights);
        }
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        //Arrange all children like a vertical StackPanel
        double y = 0;
        foreach (UIElement child in InternalChildren)
        {
            //child.DesiredSize.Height contains the correct value since it was calculated in MeasureOverride
            child.Arrange(new Rect(0, y, finalSize.Width, child.DesiredSize.Height));
            y += child.DesiredSize.Height;
        }
        return finalSize;
    }
}

<强> MainWindow.xaml

将控件模板包含为名为DistributedHeightRadPanelBarStyle的样式和用于测试的RadPanelBar。

<Window x:Class="WpfApplication9.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication9"
    Title="MainWindow" Height="350" Width="525" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation">
<Window.Resources>
    <Style x:Key="DistributedHeightRadPanelBarStyle" TargetType="{x:Type telerik:RadPanelBar}">
        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <local:DistributedHeightPanel ItemsMinHeight="22" /> <!-- 22 is fine for collapsed headers -->
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type telerik:RadPanelBar}">
                    <Grid>
                        <telerik:LayoutTransformControl x:Name="transformationRoot" IsTabStop="False">
                            <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
                                <!-- <ScrollViewer x:Name="ScrollViewer" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" HorizontalScrollBarVisibility="Auto" IsTabStop="False" Padding="{TemplateBinding Padding}" VerticalScrollBarVisibility="Auto" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">-->
                                <telerik:StyleManager.Theme>
                                    <telerik:Office_BlackTheme/>
                                </telerik:StyleManager.Theme>
                                <ItemsPresenter/>
                                <!--</ScrollViewer>-->
                            </Border>
                        </telerik:LayoutTransformControl>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="Orientation" Value="Horizontal">
                            <Setter Property="LayoutTransform" TargetName="transformationRoot">
                                <Setter.Value>
                                    <RotateTransform Angle="-90"/>
                                </Setter.Value>
                            </Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Setter Property="Orientation" Value="Vertical"/>
    </Style>
</Window.Resources>
<Grid>
    <telerik:RadPanelBar Style="{StaticResource ResourceKey=DistributedHeightRadPanelBarStyle}" VerticalAlignment="Top" ExpandMode="Multiple" HorizontalAlignment="Stretch">
        <telerik:RadPanelBarItem DropPosition="Inside" Header="A - Colors" IsExpanded="True">
            <ScrollViewer VerticalScrollBarVisibility="Auto">
                <StackPanel>
                    <TextBlock Height="100" Background="AliceBlue" Text="I'm AliceBlue" />
                    <TextBlock Height="100" Background="AntiqueWhite" Text="I'm AntiqueWhite" />
                </StackPanel>
            </ScrollViewer>
        </telerik:RadPanelBarItem>
        <telerik:RadPanelBarItem DropPosition="Inside" Header="B - Colors" IsExpanded="True">
            <ScrollViewer VerticalScrollBarVisibility="Auto">
                <StackPanel>
                    <TextBlock Height="100" Background="Beige" Text="I'm Beige" />
                    <TextBlock Height="100" Background="Bisque" Text="I'm Bisque" />
                </StackPanel>
            </ScrollViewer>
        </telerik:RadPanelBarItem>
        <telerik:RadPanelBarItem DropPosition="Inside" Header="C - Colors">
            <ScrollViewer VerticalScrollBarVisibility="Auto">
                <StackPanel>
                    <TextBlock Height="100" Background="CadetBlue" Text="I'm CadetBlue" />
                    <TextBlock Height="100" Background="Chartreuse" Text="I'm Chartreuse" />
                </StackPanel>
            </ScrollViewer>
        </telerik:RadPanelBarItem>
    </telerik:RadPanelBar>
</Grid>

也许这个解决方案对你来说太晚了,但希望有人会发现它很有用。