2009-11-16 15 views
6

In WPF, voglio creare una finestra che è simile al seguente:WPF layout di controllo utente come una corsa

Application with user controls http://www.freeimagehosting.net/uploads/86209e1a87.png

sullo schermo sono quattro controllo utente, # 1, 2, 3, 4. Come puoi vedere, il controllo utente 2 non dovrebbe essere visualizzato come una casella, ma in linea.

Se questo fosse un documento flusso WPF:

  • 1, 3, 4 sarebbe un paragrafo (pugilato)
  • 2 una corsa (inline)

La ragione è che 2 potrebbe essere utilizzato in un altro formato senza divisione per 3.

Avete qualche idea su come farlo in modo corretto?

Un'idea già pensato:

  • 2 è e utente ordinario di controllo (pugilato). Quando vengono inseriti nella finestra, 2, 3, 4 vengono collocati in un'area di disegno, utilizzando lì controllo Z e margine ton come vengono visualizzati
  • 2 ha una griglia già formattata in modo che possa accettare 3 e 4 in esso come ContentControl e li iniettiamo via Xaml o codice
  • 2 espone la griglia principale come una proprietà e tramite la proprietà Proprietà associata, aggiungiamo i dati per 3 e 4
  • Creiamo il nostro controllo layout e implementare i metodi Arrange and Measure per creare un layout che si comporta come una corsa

E alcuni altri che non sono così puliti ...

Qualche idea?

Grazie,

Patrick

risposta

1

Penso che tu abbia il modulo suddiviso in modo non corretto, IMO.

L'area 2 non deve includere il pezzo inferiore che stai descrivendo che desideri avere "in linea".

in modo da separare (per quanto concerne la layout), e probabilmente in forma in una griglia con 2 colonne e 2 righe insieme Area 3 e Area 4. Area 3 sarebbe quindi necessario avere un rowspan di 2.

Lo XAML, in questo caso, sarebbe effettivamente piuttosto pulito se fatto in questo modo.

Potrebbe sembrare qualcosa di simile:

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition /> 
     <RowDefinition /> 
     <RowDefinition /> 
    </Grid.RowDefinitions> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition /> 
    </Grid.ColumnDefinitions> 

    <uC:Area1 Grid.Row="0"><!-- Area Control here --></uC:Area1> 
    <uC:Area2 Grid.Row="1"><!-- Area Control here --></uC:Area2> 

    <Grid Grid.Row="2"> 
     <Grid.RowDefinitions> 
      <RowDefinition /> 
      <RowDefinition /> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition /> 
      <ColumnDefinition /> 
     </Grid.ColumnDefinitions> 

     <uC:AreaDuree Grid.Row="0" Grid.Column="0"> 
      <!-- Area Control here --> 
     </uC:AreaDuree> 

     <uC:Area4 Grid.Row="1" Grid.Column="0"> 
      <!-- Area Control here --> 
     </uC:Area4> 

     <uC:Area3 Grid.RowSpan="2" Grid.Column="1"> 
      <!-- Area Control here --> 
     </uC:Area3>       

    </Grid> 

</Grid> 
+0

Sì, che sarebbe grande. Ho modificato la domanda per notare che il # 2 potrebbe essere usato in un altro posto. – PBelanger

+0

@PBelanger va bene, ma questo significa solo che i controlli utente devono essere ulteriormente incapsulati in modo da poter modificare i rispettivi layout. Avere la parte inferiore di Area2 il suo controllo consente di posizionarlo dove vuoi su qualsiasi numero di schemi di layout. – Joseph

1

vi consiglio di dividere il controllo # 2 a 3 o 4 più specifiche UserControl. Quindi carica # 2, # 3, # 4 all'interno di un WrapPanel. Controlla questo link: Layout of UserControl per implementare una strategia Arrange and Mesure del pannello wrap intelligente.

1

Per me, per semplificare la vita del tuo designer, ti suggerisco la soluzione di ContentControl.

In questo modo, il tuo progettista potrebbe facilmente aggiungere i propri controlli e per te, solo per rendere il tuo Usercontrol # 2 abbastanza intelligente da rendere il tuo layour nel modo giusto.

-1

Si può pensare di avere # 3 e # 4 come parte del controllo utente # 2, quindi le cose rendono più semplice il layout. Una griglia di livello superiore espone n. 1 e n. 2

Vedere il secondo layout di controllo utente. E tutto griglia con * dimensioni in modo che venga ridimensionato in base alle dimensioni della finestra.

alt text http://img5.imageshack.us/img5/4419/40506576.jpg

+0

Se ha posto la domanda è probabilmente perché ha bisogno di utilizzare l'UserControl da solo. La domanda è: "come spostare/ridimensionare automaticamente UserControl/Panel in fase di esecuzione a seconda del contesto?", NON come renderlo in un altro modo. –

+0

Sì, ma il suggerimento è ancora meglio di niente ... – esylvestre

+0

Non so perché non lo voti? La soluzione è esattamente simile a quella per cui @Joseph ha aggiunto XAML. Il mio è solo una rappresentazione visuale sullo stesso –

1

Mi sorprende che nessuno ha ancora suggerito utilizzando un vero e proprio FlowDocument a tracciare l'interfaccia utente.

Ho usato FlowDocument prima di ottenere accordi complessi. Funziona piuttosto bene, tranne che alcune proprietà ereditate sono bloccate (ad esempio TextElement.FontSize). Questo non è difficile da aggirare.

Nel tuo caso, interrompi il n. 2 in un UserControl separato per sezione e all'interno di FlowDocument, utilizza InlineUIContainer per racchiudere ciascuna sezione.

<Window> 
    <DockPanel> 
    ... toolbars, etc ... 

    <FlowDocumentScrollViewer ...> 
     <FlowDocument> 
     ... 
     <InlineUIContainer> 
      <my:PartialNumberTwo DataContext="{Binding ...}" /> 
     </InlineUIContainer> 
     ... 

Ovviamente ci sono dei limiti a ciò che FlowDocument può fare, quindi potrebbe non funzionare per lo scenario.

Un'opzione estremamente flessibile è quella di creare un pannello personalizzato che espone i suoi figli in uno stile WrapPanel, ma facendo i rettangoli di adattamento, e prima di iniziare esso segna qualsiasi area sovrapposta dai propri fratelli del pannello come non disponibile.

Tale pannello sarebbe stato utilizzato in questo modo:

<Grid ...> 
    ... RowDefinitions, ColumnDefinitions ... 

    <panels:WrapIntoRemainingSpacePanel RowSpan="4" ColumnSpan="3"> <!-- fill whole grid --> 
    <my:Control2Part1 /> 
    <my:Control2Part2 /> 
    <my:Control2Part3 /> 
    <my:Control2Part4 /> 
</panels:WrapIntoRemainingSpacePanel> 

<my:Control1 Grid.Row="0" Grid.ColumnSpan="3" /> 
<my:Control3 Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="2" /> 
<my:Control4 Grid.Row="3" Grid.RowSpan="2" /> 

Questo pannello sarà attuato come segue:

  1. In ArrangeOverride, pianificare un callback Dispatcher.BeginInvoke per fare il disposizione reale e rapporto intero utilizzato
  2. Nella richiamata, ottenere i rettangoli che rappresentano il limite di tutti i miei fratelli g scatole nello spazio delle coordinate del mio genitore.
  3. Coordinate Y ordinate (in alto e in basso) di tutti i rettangoli posizionati
  4. Posizionare ogni bambino trovando la prima coordinata Y nell'elenco ordinato in cui vi è uno spazio orizzontale da qualche parte per il contenuto e posizionandolo il più a sinistra possibile VisualTransform
  5. Monitor fratelli per eventuali modifiche InvalidateArrange chiamata()
0

Penso che sia una semplice griglia, il 'trucco' è che è perfettamente bene di avere una copertura di controllare un altro - WPF sarà sempre renderli nello stesso ordine:

Ho usato Altezza = "Auto" per tutte le righe della griglia, a seconda di come sono impostati i controlli utente, potrebbe essere necessario specificare un'altezza reale per farli allineare correttamente.

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition Height="Auto"/> 
    </Grid.RowDefinitions> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="*"/> 
     <ColumnDefinition Width="Auto"/> 
    </Grid.ColumnDefinitions> 
    <uc:UserControl1 Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"/> 
    <uc:UserControl2 Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Grid.RowSpan="2"/> 
    <uc:UserControl3 Grid.Row="2" Grid.Column="1" Grid.RowSpan="2"/> 
    <uc:UserControl4 Grid.Row="3" Grid.Column="0"/> 
<Grid> 
0

È 1 Grid grande, con 3 righe e 2 colonne. Ogni zona di tale griglia contiene una griglia in grado di ricevere i controlli dell'utente. Quindi il numero di griglia3 ha solo bisogno di ottenere il margine superiore impostato su -75. Si sovrappone alla griglia numero 2 se viene abbassata nell'xaml. Quindi devi solo bloccare le colonne e le righe a seconda di come vuoi che reagisca.

<Grid x:Name="LayoutRoot"> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="0.55*"/> 
     <ColumnDefinition Width="0.45*"/> 
    </Grid.ColumnDefinitions> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="0.363*"/> 
     <RowDefinition Height="0.369*"/> 
     <RowDefinition Height="0.268*"/> 
    </Grid.RowDefinitions> 
    <Grid Grid.ColumnSpan="2" Background="#FF48C5D0"/> 
    <Grid Margin="1,0,0,0" Grid.ColumnSpan="2" Grid.Row="1" Background="#FFD2A268"/> 
    <Grid Margin="1,0,0,0" Grid.Row="2" Background="#FFB7F075"/> 
    <Grid Grid.Column="1" Grid.Row="2" Background="#FFB129EC" Margin="0,-75,0,0"/> 
</Grid> 

Martin Lamontagne

Problemi correlati