WPF GroupBox标头自定义

时间:2010-11-20 22:04:55

标签: wpf groupbox opacitymask

我已经编辑了标准的GroupBox模板,因为我想自定义它。除了其他自定义,我希望GroupBox标题在中心而不是左或右水平对齐。 Header的对齐不是问题,但真正的问题是为Border控件定义的OpacityMask。不透明蒙版设置组框标题后面的透明空间,其中未绘制边框。当我将标题设置为中心时,我无法弄清楚如何将透明空格/间隙放在groupbox标题后面。

以下是我的XAML的样子:(请导航到以“Border.OpacityMask”开头的部分,该部分设置标题周围边框的透明间隙)

<ControlTemplate x:Key="GroupBoxControlTemplate1" TargetType="{x:Type GroupBox}">
<Grid SnapsToDevicePixels="True">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="6"/>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="6"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="6"/>
    </Grid.RowDefinitions>

    <Border Background="{TemplateBinding Background}" BorderBrush="Transparent" 
     BorderThickness="{TemplateBinding BorderThickness}" 
     CornerRadius="4" Grid.Column="1    " Grid.ColumnSpan="4" 
     Grid.Row="1" Grid.RowSpan="3" HorizontalAlignment="Stretch"/>

    <Border x:Name="Header" Grid.Column="2" Grid.RowSpan="2" HorizontalAlignment="Left" 
        Padding="3,1,3,0" VerticalAlignment="Stretch">
        <Border.Effect>
            <DropShadowEffect BlurRadius="10" Direction="334"/>
        </Border.Effect>
        <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
         Content="{TemplateBinding Header}" 
         ContentSource="Header" 
         ContentStringFormat="{TemplateBinding HeaderStringFormat}" 
         ContentTemplate="{TemplateBinding HeaderTemplate}" 
         RecognizesAccessKey="True" Height="Auto" 
         VerticalAlignment="Center"
         HorizontalAlignment="Center"
         OpacityMask="#FF3844BD" Margin="0,1,0,0">
        </ContentPresenter>
    </Border>

    <ContentPresenter Margin="{TemplateBinding Padding}" 
        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
        Content="{TemplateBinding Content}" 
        ContentStringFormat="{TemplateBinding ContentStringFormat}" 
        ContentTemplate="{TemplateBinding ContentTemplate}" 
        Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="2"/>
    <Border BorderBrush="White" BorderThickness="{TemplateBinding BorderThickness}" 
        CornerRadius="4" Grid.ColumnSpan="3" Grid.Row="1" Grid.RowSpan="3" RenderTransformOrigin="0.5,0.5" Margin="0">
        <Border.OpacityMask>
            <MultiBinding ConverterParameter="7" UpdateSourceTrigger="Default">
                <MultiBinding.Converter>
                    <BorderGapMaskConverter/>
                </MultiBinding.Converter>
                <Binding Path="ActualWidth" ElementName="Header"/>
                <Binding Path="ActualWidth" RelativeSource="{RelativeSource Self}"/>
                <Binding Path="ActualHeight" RelativeSource="{RelativeSource Self}"/>
            </MultiBinding>
        </Border.OpacityMask>
        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="4">
            <Border BorderBrush="White" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="4"/>
        </Border>
    </Border>
</Grid>

非常感谢您的帮助。

-Wajahat

1 个答案:

答案 0 :(得分:6)

前段时间我不得不做类似的事情,我想创建一个带有两个标题的GroupBox(一个在左边,一个在右边)。我只是使用Reflector来获取BorderGapMaskConverter的代码,并修改它以创建我自己的转换器。你可以在这里做同样的事情。


编辑:我修改了我的转换器,使其适用于居中的标题。

这是ControlTemplate

<ControlTemplate TargetType="{x:Type GroupBox}">
    <Grid SnapsToDevicePixels="true">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="6"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="6"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="6"/>
        </Grid.RowDefinitions>
        <Border CornerRadius="4"
            Grid.Row="1"
            Grid.RowSpan="3"
            Grid.Column="0"
            Grid.ColumnSpan="5"
            BorderThickness="{TemplateBinding BorderThickness}"
            BorderBrush="Transparent"
            Background="{TemplateBinding Background}"/>
        <Border x:Name="Header"
            Padding="3,1,3,0"
            Grid.Row="0"
            Grid.RowSpan="2"
            Grid.Column="2">
            <ContentPresenter ContentSource="Header" 
                          RecognizesAccessKey="True" 
                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
        </Border>
        <ContentPresenter Grid.Row="2"
                      Grid.Column="1"
                      Grid.ColumnSpan="3"
                      Margin="{TemplateBinding Padding}"
                      SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
        <Border CornerRadius="4"
            Grid.Row="1"
            Grid.RowSpan="3"
            Grid.ColumnSpan="5"
            BorderThickness="{TemplateBinding BorderThickness}"
            BorderBrush="White">
            <Border.OpacityMask>
                <MultiBinding Converter="{StaticResource CenterBorderGapMaskConverter}">
                    <Binding ElementName="Header"
                         Path="ActualWidth"/>
                    <Binding RelativeSource="{RelativeSource Self}"
                         Path="ActualWidth"/>
                    <Binding RelativeSource="{RelativeSource Self}"
                         Path="ActualHeight"/>
                </MultiBinding>
            </Border.OpacityMask>

            <Border BorderThickness="{TemplateBinding BorderThickness}"
                BorderBrush="{TemplateBinding BorderBrush}"
                CornerRadius="3">
                <Border BorderThickness="{TemplateBinding BorderThickness}"
                    BorderBrush="White"
                    CornerRadius="2"/>
            </Border>
        </Border>
    </Grid>
</ControlTemplate>

这是转换器:

class CenterBorderGapMaskConverter : IMultiValueConverter
{
    // Methods
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        Type type = typeof(double);
        if (values == null
            || values.Length != 3
            || values[0] == null
            || values[1] == null
            || values[2] == null
            || !type.IsAssignableFrom(values[0].GetType())
            || !type.IsAssignableFrom(values[1].GetType())
            || !type.IsAssignableFrom(values[2].GetType()))
        {
            return DependencyProperty.UnsetValue;
        }

        double pixels = (double)values[0];
        double width = (double)values[1];
        double height = (double)values[2];
        if ((width == 0.0) || (height == 0.0))
        {
            return null;
        }
        Grid visual = new Grid();
        visual.Width = width;
        visual.Height = height;
        ColumnDefinition colDefinition1 = new ColumnDefinition();
        ColumnDefinition colDefinition2 = new ColumnDefinition();
        ColumnDefinition colDefinition3 = new ColumnDefinition();
        colDefinition1.Width = new GridLength(1.0, GridUnitType.Star);
        colDefinition2.Width = new GridLength(pixels);
        colDefinition3.Width = new GridLength(1.0, GridUnitType.Star);
        visual.ColumnDefinitions.Add(colDefinition1);
        visual.ColumnDefinitions.Add(colDefinition2);
        visual.ColumnDefinitions.Add(colDefinition3);
        RowDefinition rowDefinition1 = new RowDefinition();
        RowDefinition rowDefinition2 = new RowDefinition();
        rowDefinition1.Height = new GridLength(height / 2.0);
        rowDefinition2.Height = new GridLength(1.0, GridUnitType.Star);
        visual.RowDefinitions.Add(rowDefinition1);
        visual.RowDefinitions.Add(rowDefinition2);
        Rectangle rectangle1 = new Rectangle();
        Rectangle rectangle2 = new Rectangle();
        Rectangle rectangle3 = new Rectangle();
        rectangle1.Fill = Brushes.Black;
        rectangle2.Fill = Brushes.Black;
        rectangle3.Fill = Brushes.Black;
        Grid.SetRowSpan(rectangle1, 2);
        Grid.SetRow(rectangle1, 0);
        Grid.SetColumn(rectangle1, 0);
        Grid.SetRow(rectangle2, 1);
        Grid.SetColumn(rectangle2, 1);
        Grid.SetRowSpan(rectangle3, 2);
        Grid.SetRow(rectangle3, 0);
        Grid.SetColumn(rectangle3, 2);
        visual.Children.Add(rectangle1);
        visual.Children.Add(rectangle2);
        visual.Children.Add(rectangle3);
        return new VisualBrush(visual);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        return new object[] { Binding.DoNothing };
    }
}