Границы только для углов в wpf/xaml

В некоторых xaml я хотел бы иметь рамку, которая выходит на несколько пикселей от каждого угла. Таким образом, вдоль вершины граница будет, скажем, 5 пикселей черного цвета у левого края, затем будет прозрачной по всей остальной части верха до 5 пикселей правого края, а затем последние 5 пикселей границы у правый край будет черным. Намерение состоит в том, чтобы предоставить некоторое руководство для выбора иногда прозрачных вещей; однако в этом приложении наличие полной границы будет мешать контенту (в перцептивно-визуальном смысле). Углы не закруглены.

Что-то похожее на это:

--          --
|            |




|            |
--          --

Какой тип кисти я должен использовать для достижения этого эффекта?

Я пробовал линейный градиент, вот так:

<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
    <GradientStop Color="Black" Offset="0" />
    <GradientStop Color="Black" Offset="0.01" />
    <GradientStop Color="Transparent" Offset="0.0101" />
    <GradientStop Color="Transparent" Offset="0.9899" />
    <GradientStop Color="Black" Offset="0.99" />
    <GradientStop Color="Black" Offset="1" />
</LinearGradientBrush>

Конечно, это делает только верхний левый и правый нижний. Это может быть разумным для предполагаемого применения, но размер линии в каждом углу будет одинаковым, только если ограниченная область является квадратной (например, если ограниченная область представляет собой длинный прямоугольник, участок границы идет намного дальше вдоль одного сторона, чем другая).

Я отметил значение MappingMode "Absolute" на градиентных кистях. Это хорошо работает для верхнего левого угла, но не для других углов.

Я также попробовал RadialGradientBrush, думая, что могу получить кольцо, чтобы поразить углы, но мне не удалось ни правильно его центрировать, ни нанести удар одинаковой длины по бокам.

Это часть ItemContainerStyle в ListBox, и граница изменяется с помощью триггера для IsSelected. По этой причине я также не могу делать границы внутри границ (внутри границ и т. Д.).

Редактировать #2: я также попробовал VisualBrush. Я знал, что могу получить поведение, которое я хотел, в сетке (по крайней мере, поведение растяжения).

<VisualBrush Stretch="Fill">
    <VisualBrush.Visual>
        <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="10" MaxWidth="10" MinWidth="10" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="10" MaxWidth="10" MinWidth="10" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="10" MaxHeight="10" MinHeight="10" />
                <RowDefinition Height="*" />
                <RowDefinition Height="10" MaxHeight="10" MinHeight="10" />
            </Grid.RowDefinitions>
            <Rectangle Grid.Column="0" Grid.Row="0" Fill="Black" />
            <Rectangle Grid.Column="1" Grid.Row="0" Fill="Transparent" />
            <Rectangle Grid.Column="2" Grid.Row="0" Fill="Black" />
            <Rectangle Grid.Column="0" Grid.Row="1" Fill="Transparent" />
            <Rectangle Grid.Column="1" Grid.Row="1" Fill="Transparent" />
            <Rectangle Grid.Column="2" Grid.Row="1" Fill="Transparent" />
            <Rectangle Grid.Column="0" Grid.Row="2" Fill="Black" />
            <Rectangle Grid.Column="1" Grid.Row="2" Fill="Transparent" />
            <Rectangle Grid.Column="2" Grid.Row="2" Fill="Black" />
        </Grid>
    </VisualBrush.Visual>
</VisualBrush>

Однако это тоже не сработает. Похоже, что размер не происходит таким же образом внутри кисти. В этом случае размер сетки в VisualBrush в итоге составил 20х20, при этом средние прозрачные части не занимают места. Установка HorizontalAlignment и VerticalAlignment в Stretch также не помогла. Stretch="Fill" в VisualBrush тоже ничего не делал.

Edit # 1: более широкий контекст:

<ListBox.ItemContainerStyle>
    <Style TargetType="{x:Type ListBoxItem}">
        <Style.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
        </Style.Resources>
        <Setter Property="Margin" Value="3" />
        <Style.Triggers>
            <Trigger Property="IsSelected" Value="True">
                <Setter Property="BorderThickness" Value="5" />
                <Setter Property="Padding" Value="0" />
                <Setter Property="BorderBrush" Value="Fuchsia" />
            </Trigger>
            <Trigger Property="IsSelected" Value="False">
                <Setter Property="BorderThickness" Value="1" />
                <Setter Property="Padding" Value="4" />
                <Setter Property="BorderBrush">
                    <Setter.Value>
                        <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
                            <GradientStop Color="Black" Offset="0" />
                            <GradientStop Color="Black" Offset="0.01" />
                            <GradientStop Color="Transparent" Offset="0.0101" />
                            <GradientStop Color="Transparent" Offset="0.9899" />
                            <GradientStop Color="Black" Offset="0.99" />
                            <GradientStop Color="Black" Offset="1" />
                        </LinearGradientBrush>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>
</ListBox.ItemContainerStyle>

3 ответа

Вы могли бы использовать Path... this will draw something similar to what you're looking for:

<Path Stroke="Black" Stretch="Fill" 
      Data="M0,0 l10,0 m80,0 l10,0 m0,0 l0,10 m0,80 l0,10 m0,0 l-10,0 m-80,0 l-10,0 m0,0 l0,-10 m0,-80 l0,-10"
      Height="100" Width="100" Margin="10" />

Полный пример кода:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Path Stroke="Black" Stretch="Fill" 
              Data="M0,0 l10,0 m80,0 l10,0 m0,0 l0,10 m0,80 l0,10 m0,0 l-10,0 m-80,0 l-10,0 m0,0 l0,-10 m0,-80 l0,-10"
              Height="100" Width="100" Margin="10" />
    </Grid>
</Window>

Это забавный вопрос, так что есть еще одна возможность. Я надеюсь, что вы согласны, что это квалифицируется как отдельный ответ от моего предыдущего...

Вы можете использовать составной набор простых форм - содержащихся в сетке - для достижения желаемого эффекта. Поместите поле "Содержимое" поверх 4 черных прямоугольников, каждый черный прямоугольник должен быть расположен в соответствующем углу сетки.

Вот моя дрянная иллюстрация краски. Еще раз, красное поле указывает на ваш контент. Все, что находится за пределами этого красного поля, - это то, что пользователь увидит в качестве границы.

И реальный пример с кодом:

<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Width="300" Height="200">
    <!-- These rectangles will be the four corner "borders" -->
    <Rectangle Fill="Black" Width="50" Height="50" HorizontalAlignment="Left" VerticalAlignment="Top" />
    <Rectangle Fill="Black" Width="50" Height="50" HorizontalAlignment="Left" VerticalAlignment="Bottom" />
    <Rectangle Fill="Black" Width="50" Height="50" HorizontalAlignment="Right" VerticalAlignment="Top" />
    <Rectangle Fill="Black" Width="50" Height="50" HorizontalAlignment="Right" VerticalAlignment="Bottom" />

    <!-- Here is the content.  The "margin" property will effectively be the thickness of your corner borders. -->
    <Rectangle Fill="Red" Margin="2" />        
</Grid>

Это выглядит так:

Это имеет дополнительное преимущество масштабирования очень хорошо; границы углов всегда будут одинакового размера, независимо от размера вашего контента. Кроме того, граница может быть любой толщины, которая вам нравится, не выглядя "странно", как в предыдущем ответе с радиальной кистью.

Кисть с радиальным градиентом, вероятно, достигнет того, что вы ищете. Установите центр радиальной кисти в центр вашей коробки. Начните с прозрачного центрального цвета, постепенно переходите от центра к желаемому "цвету границы" (черному), а затем установите достаточно большой радиус, чтобы черный цвет отображался только в углах.

И убедитесь, что "градиент" очень короткий - не плавьте постепенно, а сделайте его резким.

Если вы выберете правильный размер, вы получите эффект, аналогичный тому, который (плохо) показан ниже. Красное поле представляет ваш контент. Все, что находится за пределами этой рамки, показывает, как будут выглядеть ваши углы. Увеличьте радиус "прозрачной" части, чтобы уменьшить черные углы.

В заключение; это будет хорошо выглядеть только с тонкими границами. Если у вас толстая рамка, она будет выглядеть "забавно" на "кончиках" угловой кисти.

Обновить:

Вот фактический пример с некоторым кодом:

<Border BorderThickness="1" Height="100" Width="100">
    <Border.BorderBrush>
        <RadialGradientBrush RadiusX="0.6" RadiusY="0.6">
            <GradientStop Color="Black" Offset="1"/>
            <GradientStop Color="#00000000" Offset="0.99"/>
        </RadialGradientBrush>
    </Border.BorderBrush>
    <Rectangle Fill="Red" />
</Border>

И вот как это выглядит:

Для прямоугольных форм (т. Е. Не идеальных квадратов), чтобы углы были одинакового размера, вам необходимо соответствующим образом масштабировать значения RadiusX и RadiusY. Они должны масштабироваться с соотношением ширина / высота.

Другие вопросы по тегам