2009-06-02 22 views
1

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

1

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.

2

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.

+0

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