WPF Grid.IsSharedSizeScope in ItemsControl and ScrollViewer

1.1k views Asked by At

I'm simplyfying this log viewer. It works mostly as expected, but somehow the column lengths don't share the same size.

Here is my code:

    <Window.Resources>
    <local:IsGreaterThanConverter x:Key="IsGreaterThanConverter" />
    <sys:Int32 x:Key="MaxDisplayLineLength">200</sys:Int32>

    <Style TargetType="ItemsControl" x:Key="LogViewerStyle">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <ScrollViewer CanContentScroll="True">
                        <ItemsPresenter/>
                    </ScrollViewer>
                </ControlTemplate>
            </Setter.Value>
        </Setter>

        <Setter Property="ItemsPanel">
            <Setter.Value>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel IsItemsHost="True"/>
                </ItemsPanelTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <DataTemplate DataType="{x:Type logging:LogEntry}">
        <Grid IsSharedSizeScope="True">
            <Grid.ColumnDefinitions>
                <ColumnDefinition SharedSizeGroup="Date" Width="Auto"/>
                <ColumnDefinition SharedSizeGroup="Index" Width="Auto"/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>

            <TextBlock Name="Date" Text="{Binding DateTime, StringFormat={}{0:yyyy.MM.dd HH:mm:ss}}" Grid.Column="0" FontWeight="Bold" Margin="5,0,5,0"/>
            <TextBlock Name="Index" Text="{Binding Index, StringFormat=({0})}" Grid.Column="1" FontWeight="Bold" Margin="0,0,2,0" TextAlignment="Left" />
            <TextBlock Name="Line" Text="{Binding Line}" Grid.Column="2" TextWrapping="NoWrap" Margin="5,0,5,0"/>

            <Grid.Style>
                <Style TargetType="Grid">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Path=Source}" Value="LUA">
                            <Setter Property="Grid.Background" Value="White"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding Path=Source}" Value="PYTHON">
                            <Setter Property="Grid.Background" Value="LightGray"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </Grid.Style>
        </Grid>

        <!--
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding Path=Line.Length, Converter={StaticResource IsGreaterThanConverter}, ConverterParameter={StaticResource MaxDisplayLineLength}}" Value="True">
                <Setter TargetName="Line" Property="Visibility" Value="Collapsed"/>
            </DataTrigger>
        </DataTemplate.Triggers>
        -->
    </DataTemplate>
</Window.Resources>

<Grid>
    <!-- https://stackoverflow.com/a/16745054/9963147 -->
    <ItemsControl ItemsSource="{Binding LuaLog.Data, Mode=OneWay}" Style="{StaticResource LogViewerStyle}" Grid.IsSharedSizeScope="True">
        <ItemsControl.Template>
            <ControlTemplate>
                <ScrollViewer CanContentScroll="True" HorizontalScrollBarVisibility="Visible" utils:AutoScrollBehavior.AutoScroll="True">
                    <ItemsPresenter/>
                </ScrollViewer>
            </ControlTemplate>
        </ItemsControl.Template>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel IsItemsHost="True" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
</Grid>

I've not found any relevant posts to this problem, probably because I don't know which controls are relevant for this problem. I've tried adding Grid.IsSharedSizeScope to the following places:

  • topmost Grid
  • ItemsControl
  • ScrollViewer
  • ItemsPresenter

without any result:
enter image description here

Where do I have to add Grid.IsSharedSizeScope to get this working? Are there any rules of thumb in similar situations?

Edit: Andy-s solutions works.
Some warning to the future generations: it slows down the execution substantially, even with only 100 lines. Probably because of the space calculation. I'm going to use fixed column width.

Solution looks like this (don't forget to remove Grid.IsSharedSizeScope from ItemTemplate Grid)

        <ItemsControl ItemsSource="{Binding LuaLog.Data, Mode=OneWay}" Style="{StaticResource LogViewerStyle}" Grid.IsSharedSizeScope="True">
        <ItemsControl.ItemTemplate>
            <DataTemplate DataType="{x:Type logging:LogEntry}">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition SharedSizeGroup="Date" Width="Auto"/>
                        <ColumnDefinition SharedSizeGroup="Index" Width="Auto"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
...
1

There are 1 answers

0
Andy On BEST ANSWER

I think your problem is defining the datatemplate outside the itemscontrol. As I understand it, the scope applies to everything inside the control. Your datatemplate is not and hence maybe it's simply "outside" that scope.

I always use itemtemplate or itemscontrol.resources when I used sharedsizescope.

I would also make your last column width * so it takes up any space that's over.

In any event, this is some live markup I have that works:

<ItemsControl ItemsSource="{Binding}" Grid.IsSharedSizeScope="True"
              IsTabStop="False"
              >
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid >
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="30"/>
                    <ColumnDefinition Width="40"/>
                    <ColumnDefinition Width="Auto" SharedSizeGroup="sharedWidth"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>