Search code examples
c#listviewuwpmarker

C# UWP Listview/GridView mark of selected item


I am creating UWP app, and I maked external arrow "marker" of selected item in listview...

Like this:enter image description here

I have managed to achieve this with next code:

var current = lvMain.Items.FirstOrDefault(a => (a as MyModel).Selected) as MyModel;
ListViewItem selected = lvMain.ContainerFromItem(current) as ListViewItem;    
GeneralTransform generalTransform1 = gvEpg.TransformToVisual(selected);
Point currentPoint = generalTransform1.TransformPoint(new Point());

In Scroll change event I am calling this and set the arrow position by the Point of my item. And this is working.

But, I want to simplified this. Is there any kind of binding or something like that, that would make arrow always follow the item?


Solution

  • Here's the sample.

    XAML MainPage:

    <Page.Resources>
        <DataTemplate x:Key="DataTemplate">
            <Canvas Height="80" Width="200">
                <TextBlock Text="{Binding}"/>
            </Canvas>
        </DataTemplate>
    </Page.Resources>
    
    <StackPanel Orientation="Horizontal">
        <ListView x:Name="ListView" Width="400"
                  SelectionChanged="ListView_OnSelectionChanged"
                  ItemTemplate="{StaticResource DataTemplate}"/>
    
        <Canvas x:Name="ParentCanvas">
            <Image x:Name="Arrow" 
                   Stretch="UniformToFill" Width="200" Height="80" 
                   Source="Assets/Red_Left_Arrow.png"/>
        </Canvas>
    </StackPanel>
    

    Code behind:

        private readonly List<string> _names = new List<string>();
        private Visual _rectangleVisual;
        private Visual _parentVisual;
    
        public MainPage()
        {
            InitializeComponent();
            Loaded += MainPage_Loaded;
        }
    
        private void MainPage_Loaded(object sender, RoutedEventArgs e)
        {
            for (int i = 0; i < 32; i++)
            {
                _names.Add("item " + i);
            }
    
            ListView.ItemsSource = _names;
    
            _parentVisual = ElementCompositionPreview.GetElementVisual(ParentCanvas);
            _rectangleVisual = ElementCompositionPreview.GetElementVisual(Arrow);
    
            var border = VisualTreeHelper.GetChild(ListView, 0) as Border;
            var scrollViewer = border.Child as ScrollViewer;
    
            var scrollerProperties = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(scrollViewer);
    
            var offsetExpressionAnimation = _rectangleVisual.Compositor.CreateExpressionAnimation("Scroller.Translation.Y");
            offsetExpressionAnimation.SetReferenceParameter("Scroller", scrollerProperties);
    
            _rectangleVisual.StartAnimation("Offset.Y", offsetExpressionAnimation);
        }
    
        private void ListView_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var listViewItem = ListView.ContainerFromItem(ListView.SelectedItem) as ListViewItem;
            var listItemVisual = ElementCompositionPreview.GetElementVisual(listViewItem);
    
            _parentVisual.Offset = new Vector3(_parentVisual.Offset.X, listItemVisual.Offset.Y, 0);
        }
    

    Looks like what you asked for:

    enter image description here