Why does setting the "Template" property in a style breaking scrolling?
I'm using this sample to create a multi-column tree view and I've noticed that scrolling no longer works correctly for this list view:
After some playing around I've discovered that the bit that is breaking the scrollbars is the setting of the "Template" property for the TreeListView:
<Style TargetType="{x:Type l:TreeListView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type l:TreeListView}">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<DockPanel>
<GridViewHeaderRowPresenter Columns="{StaticResource gvcc}" DockPanel.Dock="Top"/>
<ItemsPresenter/>
</DockPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Commenting out the above fixes the scrollbars (however obviously means that the grid column headers are not shown). In fact I've discovered that even the following template breaks the scrollbars:
<Style TargetType="{x:Type l:TreeListView}">
<Setter Property="Template">
<开发者_如何学CSetter.Value>
<ControlTemplate TargetType="{x:Type l:TreeListView}">
<ItemsPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Why is this?
I think this happens because you edit the template of the control defined by WPF. and it's defined to have a scrollBar. you override that template and don't add one.
i'm not 100% sure about that, but i'm wondering why are you messing with the Control Template to begin with? maybe what you want to edit is the DataTemplate? The DataTemplate decides how to present the object that is bound by Data Binding.
You need to implement your own scrollbars since you are overwriting the default template.
Wrap your ControlTemplate's ItemsPresenter
in a ScrollViewer
In the end I solved this by adding in the scrollbars myself - initially I implemented this the nieve way and just got the original content to scroll, the I discovered that the horizontal scroll bar didn't work properly if I did that (the headers didn't scroll).
Instead I used the Control Template Reference to figure out what the base control does and did a variation on wjat the ListView
does.
I can see now why I need to set the entire template when I do things like this - what I believed was simple actually turned out to be completely specific to my control.
Here is my Xaml:
<Style x:Key="{x:Static local:TreeListView.ScrollViewerStyleKey}" TargetType="ScrollViewer">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ScrollViewer">
<Grid Background="{TemplateBinding Background}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<DockPanel Margin="{TemplateBinding Padding}">
<ScrollViewer DockPanel.Dock="Top"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
Focusable="false">
<GridViewHeaderRowPresenter Margin="2,0,2,0"
Columns="{Binding Path=TemplatedParent.Columns,
RelativeSource={RelativeSource TemplatedParent}}"
ColumnHeaderContainerStyle="{Binding
Path=TemplatedParent.View.ColumnHeaderContainerStyle,
RelativeSource={RelativeSource TemplatedParent}}"
ColumnHeaderTemplate="{Binding
Path=TemplatedParent.View.ColumnHeaderTemplate,
RelativeSource={RelativeSource TemplatedParent}}"
ColumnHeaderTemplateSelector="{Binding
Path=TemplatedParent.View.ColumnHeaderTemplateSelector,
RelativeSource={RelativeSource TemplatedParent}}"
AllowsColumnReorder="{Binding
Path=TemplatedParent.View.AllowsColumnReorder,
RelativeSource={RelativeSource TemplatedParent}}"
ColumnHeaderContextMenu="{Binding
Path=TemplatedParent.View.ColumnHeaderContextMenu,
RelativeSource={RelativeSource TemplatedParent}}"
ColumnHeaderToolTip="{Binding
Path=TemplatedParent.View.ColumnHeaderToolTip,
RelativeSource={RelativeSource TemplatedParent}}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</ScrollViewer>
<ScrollContentPresenter Name="PART_ScrollContentPresenter"
KeyboardNavigation.DirectionalNavigation="Local"
CanHorizontallyScroll="False"
CanVerticallyScroll="False" />
</DockPanel>
<ScrollBar Name="PART_HorizontalScrollBar"
Orientation="Horizontal"
Grid.Row="1"
Maximum="{TemplateBinding ScrollableWidth}"
ViewportSize="{TemplateBinding ViewportWidth}"
Value="{TemplateBinding HorizontalOffset}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />
<ScrollBar Name="PART_VerticalScrollBar"
Grid.Column="1"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Value="{TemplateBinding VerticalOffset}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type local:TreeListView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TreeView">
<Border Name="Border" CornerRadius="1" BorderThickness="1">
<Border.BorderBrush>
<SolidColorBrush Color="{DynamicResource BorderMediumColor}" />
</Border.BorderBrush>
<Border.Background>
<SolidColorBrush Color="{DynamicResource ControlLightColor}" />
</Border.Background>
<ScrollViewer Style="{DynamicResource {x:Static local:TreeListView.ScrollViewerStyleKey}}">
<ItemsPresenter />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The above required that I add some extra properties to the control itself:
public static ResourceKey ScrollViewerStyleKey
{
get
{
return new ComponentResourceKey(typeof(TreeListView), "TreeListView_ScrollViewerStyleKey");
}
}
精彩评论