WPF User Management Layout as a Run

In WPF, I want to create a window that looks like this:

User Controls Application http://www.freeimagehosting.net/uploads/86209e1a87.png

There are four user controls on the screen, # 1, 2, 3, 4. As you can see, user control 2 should not be displayed as a field, but built-in.

If it was a WPF stream document:

  • 1, 3, 4 will be a paragraph (box)
  • 2 a run (inlining)

The reason is that 2 could be used in another form without dividing into 3.

Do you have any ideas how to do this properly?

Some idea already thought:

  • 2 and normal user control (boxing). When they are placed in a window, 2, 3, 4 are placed in the canvas, using the Z-order and the margin of a ton of control there as they are displayed
  • 2 has a grid already formatted so that it can accept 3 and 4 as a ContentControl, and we enter them through Xaml or the code for
  • 2 provides the main grid as a property, and through the Attached Property property adds data for 3 and 4
  • We create our own layout and implement the Arrange and Measure methods to create a layout that acts like Run

And some others that are not so clean ...

Any thoughts?

Thanks,

Patrick

+6
c # layout wpf user-controls
source share
7 answers

I think you have the wrong form, IMO.

In area 2, you should not include the lower part, which you describe that you want to have “inline”.

It should separate (with respect to the layout) and probably fit into the grid with two columns and two rows, together with region 3 and region 4. Then, for region 3, you need a column 2 times.

XAML, in this case, will actually be pretty clean if it is done.

It might look something like this:

<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> 
+1
source share

I suggest you split your Control # 2 into 3 or 4 more specific UserControls. Then load # 2, # 3, # 4 inside the WrapPanel. Check out the link: Layout of UserControl to implement a wrapping and matching strategy.

+1
source share

For me, to simplify the life of your designer, I offer you a ContentControl solution.

That way, your designer could easily add your controls to you, just make sure your Usercontrol No. 2 is smart enough to make your plan. The right way.

+1
source share

I am surprised that no one suggested using the actual FlowDocument to lay out your interface.

I used FlowDocument before to achieve complex arrangements. It works quite well, except that some inheritance of properties is blocked (e.g. t21>). This is not hard to get around.

In your case, just put # 2 in a separate UserControl for each section and inside your FlowDocument use InlineUIContainer to wrap each section.

 <Window> <DockPanel> ... toolbars, etc ... <FlowDocumentScrollViewer ...> <FlowDocument> ... <InlineUIContainer> <my:PartialNumberTwo DataContext="{Binding ...}" /> </InlineUIContainer> ... 

Of course, there are restrictions that FlowDocument can fulfill, so it may not work for your scenario.

An extremely flexible option is to create a custom panel that sets out its children in the WrapPanel style, but does this by fitting rectangles, and prior to launching it selects any area covered by our own siblings as inaccessible.

Such a panel will be used as follows:

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

This panel will be implemented as follows:

  • In ArrangeOverride, schedule a Dispatcher.BeginInvoke callback to do the actual placement and report the full size used
  • In the callback, get the rectangles representing all the bounding fields of my siblings in my parent coordinate space.
  • Sort Y coordinates (top and bottom) of all placed rectangles
  • Place each child by finding the first Y coordinate in a sorted list that has space for somewhere for content somewhere and place it as far as possible on the left
  • VisualTransform Monitor siblings for changes if any call to InvalidateArrange ()
+1
source share

I think this is a simple grid, the "trick" is that it works great for one control panel of another - WPF will always display them in the same order:

I used Height = "Auto" for all grid lines, depending on how you customize the user controls, you may need to specify a real height to make them line up correctly.

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

This is 1 large grid, with 3 rows and 2 columns. Each zone of this grid contains a grid capable of accepting custom controls. Thus, grid number 3 should get a maximum margin of -75. It will overlap grid number 2 if it places it lower in xaml. Then you just need to lock the columns and rows depending on how you want it to respond.

 <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

0
source share

Perhaps consider that # 3 and # 4 are part of user control # 2, then things get simpler. The top level grid lists # 1 and # 2

See the "Second Custom Layout" section. And all this is a grid with a size * so that it changes depending on the size of the window.

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

-one
source share

All Articles