James Joshua Street
James Joshua Street

Reputation: 3409

WPF Control not receiving desired availableWidth

My goal is to get the control the available size in the window, but currently I am getting infinity as the available size. At the topmost level I have a window with a graphviewer.

<Window x:Class="WpfExperimental.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:wpfExp="clr-namespace:WpfExperimental"
  Title="Window1" Height="900" Width="900">

  <wpfExp:GraphViewer/>
</Window>

In the graphviewer, have a toolbartray and a treeview inside a dockpanel with no set sizes for any of the three

<DockPanel x:Name ="maindockpanel"
             LastChildFill="True">
   <Toolbartray />
   <Treeview />

I have a controltemplate defined for a treeview that contains a grid (originally a stackpanel, but i changed it to grid just to be more certain of what is going on).

    <ControlTemplate TargetType="TreeView">
        <ScrollViewer 
            Focusable="False"
            CanContentScroll="False"
            Padding="4">
          <Grid>
            <Grid.RowDefinitions>
              <RowDefinition Height="Auto"/>
              <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid Grid.Row="0">
              <Grid.ColumnDefinitions>
                <ColumnDefinition Width="19" />
                <ColumnDefinition x:Name="SignalNamesColumnDefinition" Width="200" />
                <ColumnDefinition Width="*" />
              </Grid.ColumnDefinitions>
              <wpfExp:SignalNameBox x:Name="TreeViewTimeTextBox" Grid.Column="1"
                  Height="{Binding ElementName=graph_viewer, Path=GraphHeight, Mode=OneWay}"
                  MainText="Time" 
                />
              <wpfExp:SignalGraphAxis Grid.Column="2"
                  PenColor="{Binding ElementName=GraphColorPicker, Path=SelectedColor, Mode=OneWay}"
                  Height="{Binding ElementName=graph_viewer, Path=GraphHeight, Mode=OneWay}"                
                  PenWidth="{Binding ElementName=graph_viewer, Path=GraphPenWidth, Mode=OneWay}"
                  X_Scale="{Binding ElementName=graph_viewer, Path=X_Scale, Mode=OneWay}"
                  MaxTimeValue="{Binding ElementName=graph_viewer, Path=_SignalDataViewModel.MaxTimeValue, Mode=OneWay}"
                />
            </Grid>
            <ItemsPresenter Grid.Row="1" />
          </Grid>
        </ScrollViewer>

The DataTemplate gets applied to the ItemsPresenter in the above controltemplate.

<TreeView.ItemTemplate>
        <HierarchicalDataTemplate ItemsSource ="{Binding Path = bits}">
          <Grid x:Name="graph_viewer_grid" Background="Black">
            <Grid.ColumnDefinitions>
              <ColumnDefinition Width="200" />
              <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <wpfExp:SignalNameBox Grid.Column="0"
              Height="{Binding ElementName=graph_viewer, Path=GraphHeight, Mode=OneWay}"
              x:Name="signal_name_panel"
              MainText="{Binding Path = SignalName}" 
            />
            <wpfExp:SignalGraph Grid.Column="1"
              x:Name="signal_graph"
              IsSignal="True"
              BusTextColor="{Binding ElementName=BusTextColorPicker, Path=SelectedColor, Mode=OneWay}"
              GraphPenColor="{Binding ElementName=GraphColorPicker, Path=SelectedColor, Mode=OneWay}"
              Height="{Binding ElementName=graph_viewer, Path=GraphHeight, Mode=OneWay}"
              PenWidth="{Binding ElementName=graph_viewer, Path=GraphPenWidth, Mode=OneWay}"
              Signal="{Binding}" 
              signal_graph_window_width="{Binding ElementName=graph_viewer, Path=signal_graph_window_width, Mode=OneWay}"
              X_Scale="{Binding ElementName=graph_viewer, Path=X_Scale, Mode=OneWay}"
              MaxTimeValue="{Binding RelativeSource = {RelativeSource AncestorType={x:Type wpfExp:GraphViewer}}, Path = _SignalDataViewModel.MaxTimeValue}"
              />

          </Grid>
          <HierarchicalDataTemplate.ItemTemplate>
            <DataTemplate>
              <Grid Background="Black">
                <Grid.ColumnDefinitions>
                  <ColumnDefinition MinWidth="200"/>
                  <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <wpfExp:SignalNameBox Grid.Column="0"
                  Height="{Binding ElementName=graph_viewer, Path=GraphHeight, Mode=OneWay}"
                  x:Name="signal_name_panel"
                  MainText="{Binding Path = BitNumber}" 
                />

                <wpfExp:SignalGraph Grid.Column="1"
                  x:Name="signal_graph"
                  IsSignal="False"
                  BusTextColor="{Binding ElementName=BusTextColorPicker, Path=SelectedColor, Mode=OneWay}"
                  GraphPenColor="{Binding ElementName=GraphColorPicker, Path=SelectedColor, Mode=OneWay}"
                  Height="{Binding ElementName=graph_viewer, Path=GraphHeight, Mode=OneWay}"
                  PenWidth="{Binding ElementName=graph_viewer, Path=GraphPenWidth, Mode=OneWay}"
                  Bit="{Binding}" 
                  signal_graph_window_width="{Binding ElementName=graph_viewer, Path=signal_graph_window_width, Mode=OneWay}"
                  X_Scale="{Binding ElementName=graph_viewer, Path=X_Scale, Mode=OneWay}"
                  MaxTimeValue="{Binding RelativeSource = {RelativeSource AncestorType={x:Type wpfExp:GraphViewer}}, Path = _SignalDataViewModel.MaxTimeValue}"
                />

              </Grid>
            </DataTemplate>
          </HierarchicalDataTemplate.ItemTemplate>

I cannot understand why I am getting infinity space, I thought that I had all set sizes for grid, or the * meaning take available space. Which should (I thought) take the 900*900 space in window, apportion it to a real size, and then feed that to its children as availableSize. Really confused. Any help appreciated.

edit: Ok, yeah so it's the issue of how scrollviewer passes infinity width and height to children in its control.

so how should i proceed.

So I want my control to know the actual space taken up by the scrollviewer when doing its measure and arrange. basically i want to make the custom control's size the larger of the data times its scale or the actual size on the screen.

I was hoping to just pass the control the available size. But if not, is the correct thing to just find the visual parent scrollviewer and take its physical size? the problem I see with that is that the scrollviewer won't have an actual size during measure. Oh wait, it should have width and height set even if the actual width and height have not been set. So i guess I just use that. Is the correct thing to do to just search for the scrollviewer in code behind or should i bind it to some property on the control in xaml.

Upvotes: 1

Views: 323

Answers (1)

Abe Heidebrecht
Abe Heidebrecht

Reputation: 30498

Well, you have a ScrollViewer. Its entire purpose is to give an infinite size to children.

Setting CanContentScroll tells the ScrollViewer whether its children know how to implement logical scrolling. MSDN has more information.

If you want to disable horizontal scrolling, you should set HorizontalScrollbarVisibility="Disabled". There is a similar property for vertical scrolling.

Disabling the scrolling in the direction indicated will give you a fixed size. However, if you never want infinite layout space, why not remove the ScrollViewer from your template?

Edit after question edit

It sounds like you're trying to achieve a minimum scale multiplier such that you always fill as much of the viewport as possible. I think this should probably happen outside of your control's measure step. If so, then you can definitely bind to the ScrollViewer's ActualHeight and ActualWidth properties to manage the minimum scale.

Since modifying your scale will cause a new layout of your control, you will have one extra layout pass every time the ScrollViewer is resized, but that doesn't sound too bad.

Upvotes: 2

Related Questions