2013-03-10 14 views
5

Ho un che contiene alcuni verticali e orizzontali <Line> s. Voglio che la griglia sia scalabile con le dimensioni della finestra e mantenga le sue proporzioni, quindi è contenuta in un <Viewbox Stretch="Uniform">.Mantenimento di linee a spessore fisso in WPF con ridimensionamento/allungamento di Viewbox

Tuttavia, voglio anche le linee per rendere sempre con una larghezza di 1 pixel, per cui uso:

Line line = new Line(); 
line.SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased); 
// other line settings here... 

Questo rende aspetto iniziale le righe ideale, ma non appena si inizia a ridimensionare la finestra , lo stiramento/ridimensionamento viene attivato e le linee diventano di nuovo una miscela di 1 e 2 pixel di spessore.

C'è un modo per avere le linee sempre di 1 pixel di spessore e anche per il ridimensionamento della finestra/griglia?

Update - Utilizzando la geometria variabile come da Clemens' suggerimento

@Clemens - Grazie per evidenziare le differenze di rendering tra le linee e percorsi. Mentre provo a rielaborare il mio codice usando il tuo esempio, ho la sensazione di affondare che sto scavando più buchi per me stesso e non afferro l'intero concetto (interamente colpa mia, non tua, sono solo una novità di WPF) .

aggiungerò alcuni screenshot per illustrare la seguente descrizione:

Sto facendo un gioco da tavolo (per il gioco di Go, nel caso in cui aiuta a capire il layout a tutti). Ho una griglia 9x9 e sto pianificando di posizionare le parti del gioco semplicemente aggiungendo un'ellisse ad una particolare cella della griglia.

Per disegnare le linee sottostanti sul tabellone, tuttavia, ho bisogno di tracciare linee che intersecano il centro delle celle attraverso il pannello (in Go, i pezzi sono posizionati sulle intersezioni, non al centro delle celle).

Potrebbe essere che sto prendendo completamente l'approccio sbagliato, per favore sentitevi liberi di dirmi di ricominciare da capo su una strada diversa, piuttosto che hackerare all'interno della struttura attuale.

Ecco come ho fatto finora (sto aggiungendo i percorsi programmaticamente, a causa del modo in cui le coordinate vengono calcolate Non so se può essere fatto in XAML.):

XAML:

<Grid MinHeight="400" MinWidth="400" ShowGridLines="False" x:Name="boardGrid"> 
    <Grid.Resources> 
     <ScaleTransform x:Key="transform" 
      ScaleX="{Binding ActualWidth, ElementName=boardGrid}" 
      ScaleY="{Binding ActualHeight, ElementName=boardGrid}" /> 
    </Grid.Resources> 
    <Grid.RowDefinitions> 
     <RowDefinition></RowDefinition> 
     <!-- more rows, 9 in total --> 
    </Grid.RowDefinitions> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition></ColumnDefinition> 
     <!-- more columns, 9 in total --> 
    </Grid.ColumnDefinitions> 

    <!-- example game pieces --> 
    <Ellipse Stroke="Black" Fill="#333333" Grid.Row="3" Grid.Column="2" /> 
    <Ellipse Stroke="#777777" Fill="#FFFFFF" Grid.Row="4" Grid.Column="4" /> 
</Grid> 

C#:

int cols = 9; 
int rows = 9; 

// Draw horizontal lines 
for (int row = 0; row < rows; row++) 
{ 
    var path = new System.Windows.Shapes.Path(); 
    path.Stroke = Brushes.Black; 
    path.StrokeThickness = 1; 
    path.SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased); 
    Grid.SetRow(path, row); 
    Grid.SetColumnSpan(path, cols); 
    Grid.SetZIndex(path, -1); 

    double cellWidth = boardGrid.ColumnDefinitions[0].ActualWidth; 
    double cellHeight = boardGrid.RowDefinitions[0].ActualHeight; 
    double x1 = (cellWidth/2)/boardGrid.ActualWidth; 
    double y1 = (cellHeight/2)/boardGrid.ActualHeight; 
    double x2 = ((cellWidth * cols) - (cellWidth/2))/boardGrid.ActualWidth; 
    double y2 = (cellHeight/2)/boardGrid.ActualHeight; 

    path.Data = new LineGeometry(new Point(x1, y1), 
           new Point(x2, y2), 
          (ScaleTransform)boardGrid.TryFindResource("transform")); 
    boardGrid.Children.Add(path); 
} 

// Similar loop code follows for vertical lines... 

Questo è ciò che ottengo quando si utilizza il codice di cui sopra

Result when using paths

Questo è praticamente come voglio che guardi. E 'sollevato altre 2 domande per me:

1) ci sto mettendo il giusto approccio in cui sto calcolando la x1, x2, y1 e y2 valori da loro immersioni per la larghezza totale bordo per creare un numero compreso tra 0 e 1 , in modo che ScaleTransform possa quindi essere applicato a loro?

2) Ora che non uso più uno Viewbox, come faccio a eseguire il ridimensionamento a rapporto fisso?Se allargo la finestra, la scheda si estende a dismisura (vedi immagine sotto). (Non anti-alias le linee più, però, che è grande.)

Stretched board loses aspect ratio

So che questo è di arrivare a essere un po 'di un post monolitico. Sono molto grato per la tua pazienza e le tue risposte.

+0

posta uno screenshot per favore. –

+0

Ho modificato la domanda e aggiunto screenshot. – Twicetimes

+0

Vedere la mia risposta modificata per come ottenere un ridimensionamento uniforme. – Clemens

risposta

10

Un Viewbox può solo "visivamente" ridimensionare il suo elemento figlio, incluso lo spessore di qualsiasi tratto reso. Quello di cui hai bisogno è un ridimensionamento che si applica solo alla geometria delle linee (o di altre forme), ma lascia inalterato il tratto.

Invece di usare Line oggetti, è possibile disegnare le linee da Path oggetti che utilizzano trasformato LineGeometries per le loro proprietà Data. È possibile creare un ScaleTransform che ridimensiona dalle coordinate logiche alle coordinate del riquadro utilizzando la larghezza e l'altezza della Griglia come fattori di scala in direzione xe y. Ogni LineGeometry (o di qualsiasi altra geometria) userebbero coordinate logiche nel campo 0..1:

<Grid x:Name="grid"> 
    <Grid.Resources> 
     <ScaleTransform x:Key="transform" 
         ScaleX="{Binding ActualWidth, ElementName=grid}" 
         ScaleY="{Binding ActualHeight, ElementName=grid}"/> 
    </Grid.Resources> 
    <Path Stroke="Black" StrokeThickness="1"> 
     <Path.Data> 
      <LineGeometry StartPoint="0.1,0.1" EndPoint="0.9,0.9" 
          Transform="{StaticResource transform}"/> 
     </Path.Data> 
    </Path> 
</Grid> 

Al fine di ottenere una divisa ridimensionamento si può semplicemente legare entrambi ScaleX e ScaleY proprietà del ScaleTransform a uno la ActualWidth o ActualHeight della Griglia:

<Grid x:Name="grid"> 
    <Grid.Resources> 
     <ScaleTransform x:Key="transform" 
         ScaleX="{Binding ActualWidth, ElementName=grid}" 
         ScaleY="{Binding ActualWidth, ElementName=grid}"/> 
    </Grid.Resources> 
    ... 
</Grid> 

Si può anche calcolare il fattore di scala uniforme dal valore minimo della larghezza e l'altezza, con un po 'di codice dietro:

<Grid x:Name="grid" SizeChanged="grid_SizeChanged"> 
    <Grid.Resources> 
     <ScaleTransform x:Key="transform"/> 
    </Grid.Resources> 
    ... 
</Grid> 

con un gestore SizeChanged come questo:

private void grid_SizeChanged(object sender, SizeChangedEventArgs e) 
{ 
    var transform = grid.Resources["transform"] as ScaleTransform; 
    var minScale = Math.Min(grid.ActualWidth, grid.ActualHeight); 
    transform.ScaleX = minScale; 
    transform.ScaleY = minScale; 
} 
+0

Grazie per aver chiarito le differenze nel rendering della geometria. Ho rielaborato il mio codice usando Paths e modificato la mia domanda originale con i miei risultati. – Twicetimes

+0

I collegamenti su ScaleTransform sono a posto e ho implementato il gestore SizeChanged, ma al ridimensionamento della finestra, la griglia si estende ancora senza un rapporto fisso. – Twicetimes

+0

Ho pensato che stessimo parlando di come mantenere lo spessore della linea, non del layout in generale. Ad ogni modo, per mantenere il quadrato della griglia, potresti ad esempio legare la sua altezza alla sua larghezza effettiva. C'è sicuramente più di un modo per raggiungerlo, a seconda del layout generale. – Clemens

Problemi correlati