Je me demandais si quelqu'un savait comment dupliquer la fonctionnalité 9 tranches de Flex/Flash dans WPF et VB.Net. J'ai utilisé la mise à l'échelle à 9 découpes plusieurs fois dans Flex et ce serait un atout formidable dans WPF. Je voudrais pouvoir avoir une image comme toile de fond d'une toile et la faire étirer sans ruiner les coins arrondis. S'il vous plaît, est-ce que quelqu'un sait comment faire cela?Images 9 tranches dans WPF
Répondre
Je ne connais aucune fonctionnalité intégrée qui peut le faire, mais vous pouvez écrire un contrôle personnalisé pour le faire. La partie saillante d'un tel contrôle serait une grille de 9 pièces dans laquelle 4 parties étaient de taille fixe (les coins), deux parties avaient des hauteurs fixes et des largeurs variables (partie centrale et inférieure centrale), deux parties avaient fixé largeurs et hauteurs variables (centre gauche et centre droit), et la partie finale avait la hauteur et la largeur variables (le milieu). S'étirer dans une seule direction (par exemple en faisant un bouton qui ne pousse que horizontalement) est aussi simple que de limiter la hauteur de la partie médiane.
En XAML, ce serait:
<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>
alors vous ajouter des objets à peindre les images sur (je vais utiliser Rectangles), ainsi qu'un objet à mettre du contenu dans (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>
Chacun des rectangles peut être peint à l'aide d'un ImageBrush afin qu'ils montrent la partie correcte de l'image source:
<Rectangle>
<Rectangle.Fill>
<ImageBrush ImageSource="Image.png" TileMode="None"
<!-- Add the settings necessary to show the correct part of the image --> />
</Rectangle.Fill>
</Rectangle>
Emballage tout cela en un contrôle personnalisé, vous pourriez produire un peu utilisable contrôle d'image 9 tranches:
<local:NineSliceImage Image="Source.png" Slice="20,20">
<TextBox Text="Nine Slice Image TextBox!"/>
</local:NineSliceImage>
Où tranche est une propriété de type System.Windows.Size, de sorte que vous pouvez l'utiliser comme le Margin/Padding/etc. propriétés pour définir la position des tranches.
Vous devez également définir SnapToDisplayPixels sur True sur tous les rectangles; Sinon, vous verrez de petits espaces entre les parties de l'image à certaines résolutions, car WPF essaie d'interpoler les pixels intermédiaires.
Une alternative, une façon légèrement plus rapide de le faire si vous prévoyez d'utiliser un grand nombre de ces contrôles est de surcharger OnRender et de le faire là; Je l'ai fait par le passé pour un contrôle d'image en trois tranches, mais c'est un peu plus compliqué.
Cela devrait vous permettre d'aller le plus loin possible - s'il y a quelque chose qui me manque, laissez un commentaire.
Voici ce que je fini par obtenir après quelques peiner:
C'est le SlicedImage.fichier 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>
Et le SlicedImage.xaml.vb pour ceux qui veulent cela dans 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
Le contrôle de l'utilisateur serait utilisé comme ceci:
<my:SlicedImage ImageLocation="Images/left_bubble.png" Slices="18 25 19 24" />
où ImageLocation est le emplacement de l'image, et tranches est "en haut à droite en bas à gauche" pour la façon dont l'image doit être découpée. Toutes les dimensions doivent être basées dans le coin supérieur gauche.
Juste remarqué ceci après avoir roulé mon propre contrôle personnalisé en C# .. :-) http://wldevries.wordpress.com/2014/06/08/image-ninegrid-for-wpf/ – Wouter