Tech Off Thread

10 posts

Forum Read Only

This forum has been made read only by the site admins. No new threads or comments can be added.

Question about WPF, MeasureOverride and ArrangeOverride

Back to Forum: Tech Off
  • User profile image
    BitFlipper

    I'm much more familiar with WinForms than WPF but I am learning...

    I have a situation where I have a UserControl that needs to lay out child controls at runtime in a way that isn't supported by any of the currently supplied containers (StackPanel, Grid, etc). So in my derived UserControl, I override MeasureOverride and ArrangeOverride.

    But for both of these, on each child you are supposed to call Measure (when overriding MeasureOverride) or Arrange (when overriding ArrangeOverride).

    OK fine, except there are additional controls inbetween the derived UserControl and where the child controls actually reside. There is a Border and a Grid control inbetween the derived UserControl and the child controls. Am I supposed to call Measure and Arrange on the child controls even though they are two levels deeper, or should I also derive a new class from Grid that contains the actual child controls.

    Maybe I'm just not "getting" a lot of the WPF concepts yet but everything seems way more complicated than it needs to be. Now suddenly we have Width, RenderWidth, ActualWidth, a logical tree, a visual tree, etc.

    EDIT: Currently the problem I'm running into is that the derived UserControl can be
    enlarged based on the child sizes and positions, but it never shrinks again. All
    container controls in the hierarchy have height set the Auto.

  • User profile image
    wkempf

    You really should be creating a Panel to do this, not a UserControl. Panels were specifically designed for doing layout. Controls are going to be much harder to deal with here for some of the reasons you mentioned.

     

    ArrangeOverride and MeasureOverride are supposed to be called ONLY for the children. When you talk about "levels" it means your talking about controls that are descendants, but not children. This is why it's kind of pointless to try to use a Control for doing layout. Create a Panel and use it in your UserControl to handle the layout.

  • User profile image
    BitFlipper

    @wkempf:

    OK but this means I need to split my code into multiple classes. The main logic will be in the "root" control, while the layout logic will be in a different control. I guess that is not so bad.

    But I'm still not 100% sure how to approach this. So are you suggesting I don't use UserControl as my "root" control, and instead use Panel? Or are you suggesting I should derive from Panel and use it as a nested control after my Border control to host the actual child controls (and keep UserControl as my "root" control)?

  • User profile image
    wkempf

    Create a Panel that solely cares about layout. Then create a UserControl that uses your Panel. Keep the Panel generic and use attached properties to control the final layout.

     

    <MyControl ...>

       <MyPanel>

          <SomeWidget MyPanel.SomeLayoutProperty="{Binding ...}"/>

       </MyPanel>

    </MyControl>

     

    If this doesn't make sense then give more detail about the control and the layout logic and I can try and make it more concrete for what you're doing.

  • User profile image
    BitFlipper

    @wkempf:

    Thanks that makes sense. I'm not sure I can keep the panel generic though because the child items have various properties that affect their layout.

    What I'm doing is creating an interactive "signal graph" control for an audio application. It is presented as a block diagram to the user and the user can connect the output pins of one block to the input pins of another block (click and drag on pins to connect them). What I need to do in this particular case is layout the pins. Each one can be MIDI/Audio, Input/Output, Collapsed/Expanded, and has a Channel propety. Each one of those properties affect the layout of the pin.

  • User profile image
    wkempf

    That's why you use attached properties Smiley.

    <SignalGraphPanel>
       <SomeControl SignalGraphPanel.IsMIDI="True" SignalGraphPanel.IsInput="True" SignalGraphPanel.IsExpanded="True"/>
    </SignalGraphPanel>

    That's just illustration. It would be better to use Enums instead of a boolean and this stuff would likely be populated through data binding, but you get the idea. There's probably also some better ways to model all of this, but you get the idea.

  • User profile image
    BitFlipper

    @wkempf:

    But remember that all of this stuff gets created at runtime, not design time. The user either loads an existing project, or creates a new project from scratch. I'm not sure whether using attached properties buys me anything in that case, does it?

    Anyway, I'm re-evaluating the layout of the pins and I think I might be able to make this work by using a series of nested Grids and StackPanels. If so, I would get the layout "for free".

    I'm just wondering what the overhead is when you have a lot of containers like that.

  • User profile image
    wkempf

    Maybe it would help to look at something concrete?

    http://graphsharp.codeplex.com/

    http://sachabarber.net/?p=815

     

  • User profile image
    BitFlipper

    @wkempf:

    Thanks, looks good!

  • User profile image
    BitFlipper

    Something like this would work (sorry, I can't get the formatting correct):

     

    <StackPanel HorizontalAlignment="Left" Margin="163,127,0,0" Width="211" VerticalAlignment="Top">
             <StackPanel Margin="0,0,0,5">
              <Grid>
               <StackPanel x:Name="m_audioInputPins" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Left" Width="40" VerticalAlignment="Top">
                <my:SignalGraphPin Width="Auto" d:LayoutOverrides="Height"/>
               </StackPanel>
               <StackPanel x:Name="m_audioOutputPins" HorizontalAlignment="Right" Width="40" VerticalAlignment="Top">
                <my:SignalGraphPin Width="Auto" d:LayoutOverrides="Height"/>
                <my:SignalGraphPin Width="Auto" d:LayoutOverrides="Height"/>
               </StackPanel>
              </Grid>
             </StackPanel>
             <StackPanel>
              <Grid>
               <StackPanel x:Name="m_midiInputPins" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Left" Width="40" VerticalAlignment="Top">
                <my:SignalGraphPin Width="Auto" d:LayoutOverrides="Height"/>
               </StackPanel>
               <StackPanel x:Name="m_midiOutputPins" HorizontalAlignment="Right" Width="40" VerticalAlignment="Top">
                <my:SignalGraphPin Width="Auto" d:LayoutOverrides="Height"/>
                <my:SignalGraphPin Width="Auto" d:LayoutOverrides="Height"/>
               </StackPanel>
              </Grid>
             </StackPanel>
            </StackPanel>

Conversation locked

This conversation has been locked by the site admins. No new comments can be made.