WPF中的9切片图像

时间:2009-06-02 13:11:02

标签: wpf vb.net flex image

我想知道是否有人知道如何在WPF和VB.Net中复制Flex / Flash的9切片功能。我在Flex中多次使用9切片缩放,这将是WPF中的一项重要资产。我希望能够将一个图像作为我的Canvas背景,让它伸展而不会破坏圆角。请问,有谁知道怎么做?

2 个答案:

答案 0 :(得分:2)

这是我在一些劳动之后得到的结果:

这是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>

对于那些在VB.Net中想要这个的人来说,SlicedImage.xaml.vb:

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 :(得分:1)

我不知道任何可以执行此操作的内置功能,但您可以编写自定义控件来执行此操作。

这种控制的显着部分是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 / etc一样使用它。用于设置切片位置的属性。

您还需要在所有矩形上将SnapToDisplayPixels设置为True;否则,当WPF尝试插入中间像素时,您会在某些分辨率下看到图像片段之间的小间隙。

如果您计划使用大量这些控件,另一种稍微更快的方法是覆盖OnRender并在那里执行;我过去已经做过3片图像控制了,但这有点棘手。

这应该可以让你大部分时间到处 - 如果有什么我想念的话,请发表评论。