UWP Composition API, uwpcompositionapi
The requirement is that the first column is locked. How can I keep the lock column from moving with the scroll bar?
In fact, it is very easy to move the lock column and scrollviewer in the opposite direction.
Let's take a look at the template of this control. Well, it's actually very simple. It's the ListView template. The difference is that ScrollViewer adds TopHeader as the Column header.
<Border x:Name="RootBorder" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"> <ScrollViewer x:Name="ScrollViewer" Style="{StaticResource FlexGridScrollViewerStyle}" AutomationProperties.AccessibilityView="Raw" BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}" HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}" HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}" IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}" IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}" IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}" IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}" IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}" TabNavigation="{TemplateBinding TabNavigation}" VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}" VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}" ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}"> <ScrollViewer.TopHeader> <Grid> <ListView x:Name="ColumnHeader" SelectionMode="None" IsItemClickEnabled="True" Style="{StaticResource NoScrollViewerListViewStyle}" ItemsSource="{TemplateBinding ColumnsHeaderItemsSource}" ItemTemplate="{TemplateBinding ColumnsHeaderItemTemplate}"> <ListView.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal"/> </ItemsPanelTemplate> </ListView.ItemsPanel> </ListView> <ListView x:Name="FrozenColumnsHeader" Visibility="{TemplateBinding FrozenColumnsVisibility}" HorizontalAlignment="Left" VerticalAlignment="Stretch" SelectionMode="None" IsItemClickEnabled="True" Style="{StaticResource NoScrollViewerListViewStyle}" ItemsSource="{TemplateBinding FrozenColumnsHeaderItemsSource}" ItemTemplate="{TemplateBinding FrozenColumnsHeaderItemTemplate}"> <ListView.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal"/> </ItemsPanelTemplate> </ListView.ItemsPanel> </ListView> </Grid> </ScrollViewer.TopHeader> <ItemsPresenter HorizontalAlignment="Left" VerticalAlignment="Top" FooterTransitions="{TemplateBinding FooterTransitions}" FooterTemplate="{TemplateBinding FooterTemplate}" Footer="{TemplateBinding Footer}" Padding="{TemplateBinding Padding}"/> <!--HeaderTemplate="{TemplateBinding HeaderTemplate}" Header="{TemplateBinding Header}" HeaderTransitions="{TemplateBinding HeaderTransitions}"--> </ScrollViewer> </Border>
The ItemContainer of the custom ListView needs to be rewritten.
protected override bool IsItemItsOwnContainerOverride(object item) { return item is FlexGridItem; return base.IsItemItsOwnContainerOverride(item); } protected override DependencyObject GetContainerForItemOverride() { return new FlexGridItem(); return base.GetContainerForItemOverride(); }
This FlexGridItem is inherited from ListVIewItem, And the template of ListViewItem has to be rewritten. The key changes are as follows:
<Border x:Name="ContentContainer"> <Grid x:Name="InnerDragContent"> <Border x:Name="ContentBorder" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Margin="0"> <Grid> <ContentPresenter x:Name="contentPresenter" ContentTransitions="{TemplateBinding ContentTransitions}" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /> <!-- The 'Xg' text simulates the amount of space one line of text will occupy. In the DataPlaceholder state, the Content is not loaded yet so we approximate the size of the item using placeholder text. --> <Rectangle x:Name="pressedHider" Width="15" Opacity="0" Visibility="{TemplateBinding FrozenColumnsVisibility}" Margin="-10,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Stretch" Fill="{ThemeResource ApplicationPageBackgroundThemeBrush}"/> <ContentPresenter x:Name="frozenContent" Visibility="{TemplateBinding FrozenColumnsVisibility}" ContentTransitions="{TemplateBinding ContentTransitions}" HorizontalAlignment="Left" ContentTemplate="{TemplateBinding FrozenColumnsItemTemplate}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
FrozenContent is the column to be locked.
In FlexGridItem, let frozenContent slide horizontally with Scrollviewer.
internal void StartAnimation(ScrollViewer sv) { _sv = sv; if (_frozenContent == null || _sv == null || _pressedHider == null || _frozenContentVisual != null) { return; } _scrollerViewerManipulation = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(sv); _compositor = _scrollerViewerManipulation.Compositor; _offsetAnimation = _compositor.CreateExpressionAnimation("-min(0,ScrollManipulation.Translation.X)"); _offsetAnimation.SetReferenceParameter("ScrollManipulation", _scrollerViewerManipulation); _frozenContentVisual = ElementCompositionPreview.GetElementVisual(_frozenContent); _pressedHiderVisual = ElementCompositionPreview.GetElementVisual(_pressedHider); _frozenContentVisual.StartAnimation("Offset.X", _offsetAnimation); _pressedHiderVisual.StartAnimation("Offset.X", _offsetAnimation); }
I have read this code well before using the UWP Composition API. ScrollViewer moves 100 to the right, and the locked content also moves 100 to the right, so that the locked content looks like it does not move.
However, there are many limitations on the Grid continued by ListView, so you cannot operate ScrollViewer with your own ideas. For more features, see the DataGrid.
Benefits of Open Source: FlexGrid
Note: The Composition API only supports versions 10586 and later. The judgment conditions are as follows:
Usage conditions:
// Windows build 10240 and later. if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 1)) { ... } // Windows build10586 and later. if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 2)) { ... } // Windows build14332 and later. if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 3)) { ... }
Debugged
1. Windows build14332 and later: 1, 2, 3 are true.
2. Windows build10586 and later: 1 and 2 are true.
3. Windows build 10240 and later: 1 is true.
Because versions earlier than 10586 do not support the Composition API. So remember to judge when using it:
// Windows build10586 and later. if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 2)) { ... }