xamlindexingwinui-3scrollviewerwinui

How to bind index of current page of ItemsRepeater in WinUI 3?


I have ScrollViewer that contain ItemsRepeater of images and I want to bind in TextBox the current index page of ItemsRepeater when scroll the images. this is my .xaml code:

<StackPanel Orientation="Horizontal">
    <TextBlock>
        <Run Text="{x:Bind ViewModel.Pages.Count, Mode=OneWay}"/>
        <Run Text=" / "/>
    </TextBlock>
    <TextBox Text="{x:Bind ViewModel.PageIndex, Mode=TwoWay}" LostFocus="PageIndexTextBox_LostFocus" x:Name="PageIndexTextBox" InputScope="Number"/>
</StackPanel>
<ScrollViewer x:Name="scroll" ZoomMode="Enabled" Grid.Row="1"
              IsTabStop="True" IsVerticalScrollChainingEnabled="True"
              HorizontalAlignment="Stretch" VerticalAlignment="Top"
              HorizontalScrollMode="Enabled" HorizontalScrollBarVisibility="Hidden"
              VerticalScrollMode="Enabled" VerticalScrollBarVisibility="Auto"
              ViewChanged="ScrollViewer_ViewChanged">
    <ItemsRepeater ItemsSource="{x:Bind ViewModel.Pages, Mode=OneWay}" 
                   MaxWidth="{Binding ElementName=scroll, Path=ActualWidth}"
                   HorizontalAlignment="Stretch"
                   VerticalAlignment="Stretch"
                   x:Name="PdfImageRepeater">
        <ItemsRepeater.ItemTemplate>
            <DataTemplate x:DataType="pdfImage:PdfImage">
                <Grid Padding="5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                    <Image Source="{x:Bind Image, Mode=OneWay}" Stretch="Uniform" 
                           HorizontalAlignment="Center" VerticalAlignment="Center"/>
                </Grid>
            </DataTemplate>
        </ItemsRepeater.ItemTemplate>
        <ItemsRepeater.Layout>
            <StackLayout Orientation="Vertical"/>
        </ItemsRepeater.Layout>
    </ItemsRepeater>
</ScrollViewer>

And this is in my .xaml.cs code:

   private void PageIndexTextBox_LostFocus(object sender, RoutedEventArgs e)
   {
       if (int.TryParse(PageIndexTextBox.Text, out int pageIndex))
       {
           pageIndex -= 1;

           if (pageIndex >= 0 && pageIndex < ViewModel.Pages.Count)
           {
               var pageItem = PdfImageRepeater.GetOrCreateElement(pageIndex);
               pageItem.UpdateLayout();
               pageItem.StartBringIntoView();
           }
       }
   }

How can I add option to display index of current ScrollViewr page in WinUI 3 ?


Solution

  • If you can fix the height of the items, for example:

    <ItemsRepeater.ItemTemplate>
        <DataTemplate x:DataType="local:Member">
            <Grid
                MinHeight="50"
                MaxHeight="50">
                <!-- Item Content  -->
            </Grid>
        </DataTemplate x:DataType="local:Member">
    </ItemsRepeater.ItemTemplate>
    

    you can do something like this:

    private ScrollBar? VerticalScrollBar { get; set; }
    
    private void ItemsRepeaterScrollViewer_Loaded(object sender, RoutedEventArgs e)
    {
        if (sender is not ScrollViewer scrollViewer ||
            scrollViewer.FindDescendant<ScrollBar>(x => x.Orientation is Orientation.Vertical) is not ScrollBar verticalScrollBar)
        {
            return;
        }
    
        VerticalScrollBar = verticalScrollBar;
        VerticalScrollBar.ValueChanged += VerticalScrollBar_ValueChanged;
    }
    
    private void VerticalScrollBar_ValueChanged(object sender, RangeBaseValueChangedEventArgs e)
    {
        MemberIndexNumberBox.Value = Math.Round(e.NewValue / 50);
    }
    
    private void MemberIndexNumberBox_ValueChanged(NumberBox sender, NumberBoxValueChangedEventArgs args)
    {
        if (VerticalScrollBar is null)
        {
            return;
        }
    
        ItemsRepeaterScrollViewer.ScrollToVerticalOffset(args.NewValue * 50);
    }
    

    The FindDescendant extension comes from the CommunityToolkit.WinUI.Extensions NuGet package.