使用下拉列表在选项卡标题面板中排列选项卡项

时间:2016-06-07 07:11:11

标签: wpf header panel tabcontrol controltemplate

我的要求是使用最大宽度为180像素的标签项目的标签控件,如果标签不适合窗口,则将标签项目大小缩小到最多60像素。如果选项卡不适合窗口大小,还要显示带有选项卡标题的下拉列表。根据我有限的知识,我觉得我需要创建一个扩展面板的自定义控件,比如SqueezeTabPanel:Panel并覆盖 MeasureOverride和ArrangeOverride方法根据窗口大小计算每个tabitems的含义。

但我不确定如何在此基础上添加下拉列表的要求。截至目前,我已经为挤压面板创建了一个控件模板

<Style TargetType="TabControl" x:Key="SqueezeTabPanel">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabControl}">
                <Grid KeyboardNavigation.TabNavigation="Local"  SnapsToDevicePixels="true"
                      ClipToBounds="true">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition x:Name="ColumnDefinition0"/>
                        <ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition x:Name="RowDefinition0" Height="Auto"/>
                        <RowDefinition x:Name="RowDefinition1" Height="*"/>
                    </Grid.RowDefinitions>
                    <customControl:SqueezeTabPanel
                    x:Name="HeaderPanel"  Panel.ZIndex ="1" KeyboardNavigation.TabIndex="1"  Grid.Column="0"
                    Grid.Row="0" Margin="8,0,4,-1" IsItemsHost="true" Background="Transparent"/>
                    <Border x:Name="ContentPanel"
                        Background="{StaticResource PrimaryTextBoxColor}"
                        BorderThickness= "1" CornerRadius="2"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        KeyboardNavigation.TabNavigation="Local"
                        KeyboardNavigation.DirectionalNavigation="Contained"
                        KeyboardNavigation.TabIndex="2"
                        Grid.Column="0"
                        Grid.Row="1">
                        <ContentPresenter
                        x:Name="PART_SelectedContentHost"
                        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                        Margin="4"
                        ContentSource="SelectedContent"/>
                    </Border>

                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>


<Style TargetType="{x:Type TabItem}" >
    <Setter Property="FontSize" Value="{StaticResource SecondarySmallText}"/>
    <Setter Property="FontFamily" Value="Segoe UI"/>
    <Setter Property="HorizontalContentAlignment" Value="Left"/>
    <Setter Property="HorizontalAlignment" Value="Left"/>
    <Setter Property="Width" Value="180"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabItem}">
                <Grid >
                    <Grid.ToolTip >
                        <ToolTip Visibility="{TemplateBinding IsSelected,Converter={StaticResource BooleanToVisibilityConverter}}">
                            <TextBlock Text="{TemplateBinding Header}" x:Name ="TabToolTip"/>
                        </ToolTip>

                    </Grid.ToolTip>
                    <Border  Name="Border" Margin="0,0,-4,4"  Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" 
                          CornerRadius="0,5,0,0" Height="24">
                      <ContentPresenter x:Name="ContentSite"  VerticalAlignment="Center"   
                             ContentSource="Header"   Margin="12,2,12,2"   RecognizesAccessKey="True" Height="20"/>
                    </Border>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="Panel.ZIndex" Value="100" />
                        <Setter TargetName="Border" Property="Background" Value="{StaticResource SelectedTabItemBackground}" />
                        <Setter TargetName="Border" Property="BorderThickness" Value="1" />
                        <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PrimaryBorderBrush}" />
                        <Setter Property="Foreground" Value="{StaticResource PrimaryTextColor}" />
                    </Trigger>
                    <Trigger Property="IsSelected" Value="False">
                        <Setter TargetName="Border" Property="Background" Value="{StaticResource PrimaryBackground}" />
                        <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource DisabledTextColor}"/>
                        <Setter TargetName="Border" Property="BorderThickness" Value="1" />
                        <Setter Property="Foreground" Value="{StaticResource DisabledTextColor}" />
                    </Trigger>
                </ControlTemplate.Triggers>
          </ControlTemplate>
     </Setter.Value>
    </Setter>
</Style>

我对SqueezeTabPanel的自定义控件是

public class SqueezeTabPanel : Panel
{

    private double _rowHeight;
    private double _scaleFactor;

    // Ensure tabbing works correctly
    static SqueezeTabPanel()
    {
        KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(SqueezeTabPanel), new FrameworkPropertyMetadata(KeyboardNavigationMode.Once));
        KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata(typeof(SqueezeTabPanel), new FrameworkPropertyMetadata(KeyboardNavigationMode.Cycle));
    }

    // This Panel lays its children out horizontally.
    // If all children cannot fit in the allocated space,
    // the available space is divided proportionally between them.
    protected override Size MeasureOverride(Size availableSize)
    {
        // See how much room the children want
        double minwidthrequired = 60;
        double width = 0.0;
        this._rowHeight = 0.0;
        foreach (UIElement element in this.Children)
        {
            element.Measure(availableSize);
            Size size = this.GetDesiredSizeLessMargin(element);
            this._rowHeight = Math.Max(this._rowHeight, size.Height);
            width += size.Width;
        }

        // If not enough room, scale the
        // children to the available width
        if (width > availableSize.Width)
        {
            this._scaleFactor = availableSize.Width / width;
            width = 0.0;
            foreach (UIElement element in this.Children)
            {
                double itemWidth = element.DesiredSize.Width * this._scaleFactor;
                if (itemWidth>=60)
                    element.Measure(new Size(itemWidth, availableSize.Height));
                else
                    element.Measure(new Size(minwidthrequired, availableSize.Height));
                width += element.DesiredSize.Width;
            }

        }
         else
            this._scaleFactor = 1.0;

        return new Size(width, this._rowHeight);
    }

    // Perform arranging of children based on the final size
    protected override Size ArrangeOverride(Size arrangeSize)
    {
        Point point = new Point();
        foreach (UIElement element in this.Children)
        {
            Size size1 = element.DesiredSize;
            Size size2 = this.GetDesiredSizeLessMargin(element);
            Thickness margin = (Thickness)element.GetValue(FrameworkElement.MarginProperty);
            double width = size2.Width;
            if (element.DesiredSize.Width != size2.Width)
                width = arrangeSize.Width - point.X; 
            element.Arrange(new Rect(
                point,
                new Size(Math.Min(width, size2.Width), this._rowHeight)));
            double leftRightMargin = Math.Max(0.0, -(margin.Left + margin.Right));
            point.X += size1.Width + (leftRightMargin * this._scaleFactor);
        }

        return arrangeSize;
    }

    // Return element's size
    // after subtracting margin
    private Size GetDesiredSizeLessMargin(UIElement element)
    {
        Thickness margin = (Thickness)element.GetValue(FrameworkElement.MarginProperty);
        Size size = new Size();
        size.Height = Math.Max(0.0, element.DesiredSize.Height - (margin.Top + margin.Bottom));
        size.Width = Math.Max(0.0, element.DesiredSize.Width - (margin.Left + margin.Right));
        return size;
    }
} 

我不确定我的方法是否正确。请给出正确的方向帮助。提前致谢

0 个答案:

没有答案