9-срезовые изображения в WPF - PullRequest
1 голос
/ 02 июня 2009

Мне было интересно, знает ли кто-нибудь, как дублировать 9-фрагментную функциональность Flex / Flash в WPF и VB.Net. Я много раз использовал 9-фрагментное масштабирование во Flex, и это было бы большим преимуществом в WPF. Я хотел бы иметь возможность использовать изображение в качестве фона холста и растягивать его, не разрушая закругленные углы. Пожалуйста, кто-нибудь знает, как это сделать?

Ответы [ 2 ]

2 голосов
/ 04 июня 2009

Вот что я в итоге получил после некоторого труда:

Это файл SlicedImage.xaml:

    <Rectangle Grid.Row="1" Grid.Column="0" SnapsToDevicePixels="True">
        <Rectangle.Fill>
            <ImageBrush x:Name="CenterLeft" Stretch="Fill" ViewboxUnits="Absolute" AlignmentX="Left"  AlignmentY="Center" />
        </Rectangle.Fill>
    </Rectangle>
    <Rectangle Grid.Row="1" Grid.Column="1" SnapsToDevicePixels="True">
        <Rectangle.Fill>
            <ImageBrush x:Name="CenterCenter" Stretch="Fill" ViewboxUnits="Absolute" AlignmentX="Center"  AlignmentY="Center" />
        </Rectangle.Fill>
    </Rectangle>
    <Rectangle Grid.Row="1" Grid.Column="2" SnapsToDevicePixels="True">
        <Rectangle.Fill>
            <ImageBrush x:Name="CenterRight" Stretch="Fill" ViewboxUnits="Absolute" AlignmentX="Right"  AlignmentY="Center" />
        </Rectangle.Fill>
    </Rectangle>

    <Rectangle Grid.Row="2" Grid.Column="0" SnapsToDevicePixels="True">
        <Rectangle.Fill>
            <ImageBrush x:Name="BottomLeft" Stretch="Fill" ViewboxUnits="Absolute" AlignmentX="Left"  AlignmentY="Bottom" />
        </Rectangle.Fill>
    </Rectangle>
    <Rectangle Grid.Row="2" Grid.Column="1" SnapsToDevicePixels="True">
        <Rectangle.Fill>
            <ImageBrush x:Name="BottomCenter" Stretch="Fill" ViewboxUnits="Absolute" AlignmentX="Center"  AlignmentY="Bottom" />
        </Rectangle.Fill>
    </Rectangle>
    <Rectangle Grid.Row="2" Grid.Column="2" SnapsToDevicePixels="True">
        <Rectangle.Fill>
            <ImageBrush x:Name="BottomRight" Stretch="Fill" ViewboxUnits="Absolute" AlignmentX="Right"  AlignmentY="Bottom" />
        </Rectangle.Fill>
    </Rectangle>

</Grid>

</UserControl>

И SlicedImage.xaml.vb для тех, кто хочет этого в VB.Net:

Partial Public Class SlicedImage
Public imageSource As ImageSource
Public sliceTop As Double
Public sliceRight As Double
Public sliceLeft As Double
Public sliceBottom As Double

Public Sub New()

    InitializeComponent()

End Sub

Public Sub SetViewboxes()
    Dim RealHeight As Double = TopLeft.ImageSource.Height
    Dim RealWidth As Double = TopLeft.ImageSource.Width

    ColumnLeft.Width = New GridLength(sliceLeft)
    ColumnRight.Width = New GridLength(RealWidth - sliceRight)
    RowTop.Height = New GridLength(sliceTop)
    RowBottom.Height = New GridLength(RealHeight - sliceBottom)


    TopLeft.Viewbox = New Rect(0, 0, sliceLeft, sliceTop)
    TopCenter.Viewbox = New Rect(sliceLeft, 0, sliceRight - sliceLeft, sliceTop)
    TopRight.Viewbox = New Rect(sliceRight, 0, RealWidth - sliceRight, sliceTop)

    CenterLeft.Viewbox = New Rect(0, sliceTop, sliceLeft, sliceBottom - sliceTop)
    CenterCenter.Viewbox = New Rect(sliceLeft, sliceTop, sliceRight - sliceLeft, sliceBottom - sliceTop)
    CenterRight.Viewbox = New Rect(sliceRight, sliceTop, RealWidth - sliceRight, sliceBottom - sliceTop)

    BottomLeft.Viewbox = New Rect(0, sliceBottom, sliceLeft, RealHeight - sliceBottom)
    BottomCenter.Viewbox = New Rect(sliceLeft, sliceBottom, sliceRight - sliceLeft, RealHeight - sliceBottom)
    BottomRight.Viewbox = New Rect(sliceRight, sliceBottom, RealWidth - sliceRight, RealHeight - sliceBottom)

End Sub
Public Property ImageLocation() As ImageSource
    Get
        Return Nothing
    End Get
    Set(ByVal value As ImageSource)
        TopLeft.ImageSource = value
        TopCenter.ImageSource = value
        TopRight.ImageSource = value
        CenterLeft.ImageSource = value
        CenterCenter.ImageSource = value
        CenterRight.ImageSource = value
        BottomLeft.ImageSource = value
        BottomCenter.ImageSource = value
        BottomRight.ImageSource = value
    End Set
End Property

Public Property Slices() As String
    Get
        Return Nothing
    End Get
    Set(ByVal value As String)
        Dim sliceArray As Array = value.Split(" ")
        sliceTop = sliceArray(0)
        sliceRight = sliceArray(1)
        sliceBottom = sliceArray(2)
        sliceLeft = sliceArray(3)
        SetViewboxes()
    End Set
End Property

End Class

Пользовательский элемент управления будет использоваться следующим образом:

<my:SlicedImage ImageLocation="Images/left_bubble.png" Slices="18 25 19 24" />

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

1 голос
/ 02 июня 2009

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

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

В XAML это будет:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="20"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="20"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="20"/>
        <RowDefinition Height="*"/>
        <RowDefinition Height="20"/>
    </Grid.RowDefinitions>
</Grid>

Затем вы добавили бы объекты для рисования изображений (я буду использовать прямоугольники), а также объект для помещения контента (ContentPresenter):

<Rectangle Grid.Row="0" Grid.Column="0" x:Name="TopLeft"/>
<Rectangle Grid.Row="0" Grid.Column="1" x:Name="TopCenter"/>
<Rectangle Grid.Row="0" Grid.Column="2" x:Name="TopRight"/>

<Rectangle Grid.Row="1" Grid.Column="0" x:Name="CenterLeft"/>
<Rectangle Grid.Row="1" Grid.Column="2" x:Name="CenterRight"/>

<Rectangle Grid.Row="2" Grid.Column="0" x:Name="BottomLeft"/>
<Rectangle Grid.Row="2" Grid.Column="1" x:Name="BottomCenter"/>
<Rectangle Grid.Row="2" Grid.Column="2" x:Name="BottomRight"/>

<Grid Grid.Row="2" Grid.Column="1" x:Name="Middle">
  <Rectangle/>
  <ContentPresenter x:Name="MiddleContent"/>
</Grid>

Каждый из прямоугольников можно нарисовать с помощью ImageBrush, чтобы они отображали правильную часть исходного изображения:

<Rectangle>
    <Rectangle.Fill>
        <ImageBrush ImageSource="Image.png" TileMode="None" 
                    <!-- Add the settings necessary to show the correct part of the image --> />
    </Rectangle.Fill>
</Rectangle>

Обернув все это в пользовательский элемент управления, вы можете создать довольно удобный 9-фрагментный элемент управления изображением:

<local:NineSliceImage Image="Source.png" Slice="20,20">
    <TextBox Text="Nine Slice Image TextBox!"/>
</local:NineSliceImage>

Где Slice - это свойство типа System.Windows.Size, так что вы можете использовать его как Margin / Padding / и т.д. свойства для установки положения срезов.

Вы также захотите установить для SnapToDisplayPixels значение True для всех прямоугольников; в противном случае вы увидите небольшие промежутки между частями изображения при определенных разрешениях, так как WPF пытается интерполировать промежуточные пиксели.

Альтернативный, немного более быстрый способ сделать это, если вы планируете использовать множество этих элементов управления, - переопределить OnRender и сделать это там; Я делал это в прошлом для управления 3-фрагментным изображением, но это немного сложнее.

Это должно помочь вам пройти большую часть пути - если я что-то упустил, оставьте комментарий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...