6 Stimmen

WPF Layout der Benutzersteuerung als Lauf

In WPF möchte ich ein Fenster erstellen, das wie das folgende aussieht:

Anwendung mit Benutzerkontrollen http://www.freeimagehosting.net/uploads/86209e1a87.png

Auf dem Bildschirm befinden sich vier Benutzerkontrollen, #1, 2, 3, 4. Wie Sie sehen können, sollte die Benutzerkontrolle 2 nicht als Box, sondern als Inline gerendert werden.

Wenn dies ein WPF-Flow-Dokument wäre:

  • 1, 3, 4 wären ein Absatz (Boxen)
  • 2 ein Lauf (Inlining)

Der Grund dafür ist, dass 2 in einer anderen Form verwendet werden könnte, ohne dass es zu einer Aufspaltung in 3 kommt.

Haben Sie eine Idee, wie man das richtig macht?

Eine Idee, an die ich schon gedacht habe:

  • 2 ist eine gewöhnliche Benutzerkontrolle (Boxen). Wenn im Fenster platziert, 2, 3, 4 werden in einem Canvas platziert, wobei Z-Ordnung und Randtonnensteuerung wie sie gerendert werden
  • 2 hat ein Raster, das bereits so formatiert ist, dass es 3 und 4 darin als ContentControl aufnehmen kann, und wir injizieren sie über Xaml oder Code dahinter
  • 2 stellt das Hauptgitter als Eigenschaft dar, und über die Eigenschaft Attached Goodness fügen wir die Daten für 3 und 4 hinzu
  • Wir erstellen unser eigenes Layout-Steuerelement und implementieren die Methoden Arrange und Measure, um ein Layout zu erstellen, das sich wie ein Run

Und einige andere, die nicht so sauber sind...

Haben Sie eine Idee?

Danke,

Patrick

1voto

Joseph Punkte 24916

Ich glaube, Sie haben Ihr Formular falsch aufgeteilt, IMO.

Bereich 2 sollte nicht das untere Stück enthalten, das Sie beschreiben und das Sie "inlined" haben wollen.

Es sollte (was das Layout betrifft) getrennt sein und wahrscheinlich in ein Raster mit 2 Spalten und 2 Zeilen zusammen mit Bereich 3 und Bereich 4 passen. Bereich 3 müsste dann eine Zeilenspanne von 2 haben.

Die XAML wäre in diesem Fall sogar ziemlich sauber, wenn sie auf diese Weise erstellt würde.

Das könnte in etwa so aussehen:

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

1voto

Ich schlage vor, dass Sie Ihr Control #2 in 3 oder 4 spezifischere UserControl aufteilen. Dann laden Sie #2, #3, #4 innerhalb eines WrapPanel. Prüfen Sie dies Link: Aufbau des UserControls eine intelligente Strategie zum Anordnen und Vermessen von Schalttafeln zu implementieren.

1voto

esylvestre Punkte 1860

Um das Leben Ihres Designers zu vereinfachen, würde ich Ihnen die Lösung von ContentControl vorschlagen.

Auf diese Weise kann Ihr Designer seine Steuerelemente einfach hinzufügen und Sie müssen nur sicherstellen, dass Ihr Usercontrol #2 intelligent genug ist, um Ihr Layout richtig darzustellen.

1voto

Ray Burns Punkte 60870

Ich bin überrascht, dass noch niemand vorgeschlagen hat unter Verwendung eines aktuellen FlowDocuments um Ihre Benutzeroberfläche zu gestalten.

Ich habe die FlowDocument um komplexe Arrangements zu erreichen. Es funktioniert recht gut, außer dass die Vererbung einiger Eigenschaften blockiert ist ( TextElement.FontSize zum Beispiel). Dies ist nicht schwer zu umgehen.

In Ihrem Fall unterteilen Sie #2 einfach in ein separates UserControl pro Abschnitt, und verwenden Sie innerhalb Ihres FlowDocuments InlineUIContainer, um jeden Abschnitt zu umhüllen.

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

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

Natürlich sind den Möglichkeiten von FlowDocument Grenzen gesetzt, so dass es für Ihr Szenario möglicherweise nicht geeignet ist.

Eine äußerst flexible Option ist die Erstellung eines benutzerdefinierten Bedienfelds, das seine untergeordneten Elemente im WrapPanel-Stil anordnet, allerdings durch Einpassen von Rechtecken, und vor dem Start alle Bereiche, die von den eigenen Geschwistern des Bedienfelds überlappt werden, als nicht verfügbar markiert.

Eine solche Tafel würde wie folgt verwendet werden:

<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" />

Dieses Gremium würde wie folgt umgesetzt werden:

  1. Planen Sie in ArrangeOverride einen Dispatcher.BeginInvoke-Callback ein, der die eigentliche Anordnung vornimmt und die gesamte verwendete Größe meldet
  2. Im Callback werden Rechtecke abgerufen, die alle Bounding Boxes meiner Geschwister im Koordinatenraum meiner Eltern darstellen.
  3. Y-Koordinaten (oben und unten) aller platzierten Rechtecke sortieren
  4. Platzieren Sie jedes Kind, indem Sie die erste Y-Koordinate in der sortierten Liste finden, an der irgendwo ein horizontaler Platz für den Inhalt ist, und platzieren Sie sie so weit links wie möglich
  5. VisualTransform der Geschwister auf Änderungen überwachen, ggf. InvalidateArrange() aufrufen

0voto

Nir Punkte 28685

Ich denke, es ist ein einfaches Raster, der "Trick" ist, dass es völlig in Ordnung ist, ein Steuerelement über ein anderes zu haben - WPF wird sie immer in der gleichen Reihenfolge wiedergeben:

Ich habe Height="Auto" für alle Rasterzeilen verwendet. Je nachdem, wie die Benutzersteuerelemente eingerichtet sind, müssen Sie möglicherweise eine echte Höhe angeben, damit sie richtig ausgerichtet sind.

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X