1

I have a RadPanelBar with each RadPanelItem having a list of entities(Different list in each Item). Each item in the List is shown as a GroupBox. With a large number of items the RadPanelBar has to be scrolled in order for the other RadPanelBarItems to be visible. I want it such that the scrollbar appears within each RadPanelBarItem so that all the RadPanelBarItems will be visible on the screen at the same time and if the contents of an item are too long, the user has to scroll only within each RadPanelBarItem.

I'm using the ItemsSource property of each RadPanelBarItem and setting its ItemTemplate to display the GroupBoxes.

Is there a good way to do this, so that everything(Height and such) is kept dynamic?

Thanks!

4

1 回答 1

2

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

如果我的情况正确,您有几种选择:

1) 设置 PanelBarItem 的大小。这样,您将限制它们的大小。如果您将项目总和大小与 PanelBar 的大小相匹配,则应消除剪报。

2) 自定义 PanelBar 和 PanelBarItem 控件模板,以支持自动按比例调整大小。在这种情况下,您应该从 PanelBar 控件模板中删除 ScrollViewer,并在顶级 PanelBarItem 控件模板中添加一个 ScrollViewer(在 ItemsPresenter 周围)。此外,您应该将 RadPanelBar ItemsPanel 更改为适当的面板。大概。它将是一个自定义面板,以便垂直测量大小相等的项目。

我已经尝试做一个自定义面板并修改控制模板。我已经让它工作了,但是代码很多,但是这里有:

分布式高度面板.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;
    }
}

主窗口.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>

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

于 2012-07-11T16:18:16.440 回答