1

I am working on implementing a feature into a UWP app where when a Grid item is hovered over in a AdaptiveGridView that after 2 seconds it will show a popup with more details about the hovered item in the form of another formatted Grid. This was working just fine until I needed to add a 2-second delay before the popup appears.

I have been adapting a similar thread in an attempt to make this work (How to use mousehover delay in c#?) but I have not been able to override the PointerEntered/PointerExited functions due to some errors:

Line 43: CS0505: 'HoverGrid.PointerEntered(PointerEventHandler)': cannot override because 'UIElement.PointerEntered' is not a function

Line 45: CS0079: The event 'UIElement.PointerEntered' can only appear on the left hand side of += or -=

To be honest, I am not sure if this is the best way to implement the hover delayed event either, but its something I am trying

Currently I have created a HoverGrid.cs class that is receiving the errors (below). I have tried tweaking the arguments/naming of the methods but it doesnt seem to do anything.

I have also tried to implement Timers directly in the page that has the events I am ultimately working with, but I was having issues with that which is why I am trying this method out if possible.

namespace ViperContentManager.Classes.Controls
{
    public class HoverGrid : Windows.UI.Xaml.Controls.Grid
    {
        protected System.Timers.Timer timer;

        public bool IsHoverEnabled { get; set; }
        public double Delay { get; set; }

        public event System.Timers.ElapsedEventHandler TimerElapsed
        {
            add
            {
                timer.Elapsed += value;
            }
            remove
            {
                timer.Elapsed -= value;
            }
        }

        public HoverGrid()
        {
            // defaults: hover trigger enabled with 3000 ms delay
            IsHoverEnabled = true;
            Delay = 3000;

            timer = new System.Timers.Timer
            {
                AutoReset = false,
                Interval = Delay
            };
        }

        protected override void PointerEntered(PointerEventHandler e)
        {
            base.PointerEntered();
            if (IsHoverEnabled)
            {
                timer.Start();
            }
        }

        protected override void PointerExited(PointerEventHandler e)
        {
            base.PointerExited();
            timer.Stop();
        }
    }
}

For anyone curious, this is what the code-behind for the page that would be hosting the hoverGrid looks like (although HoverGrid is not yet implemented into my XAML at all). Forgive some of the extra variable declarations, I was trying to implement the hover function a few ways and haven't yet cleaned it up.

namespace MyProject.Pages
{
    public sealed partial class ImageUploaderPage : Page
    {
        public object selected = null;
        public double thumbSize = 150;

        //Variables for on-hover popup
        public double detailPopLeft, detailPopRight, detailPopTop, detailPopBottom;
        public Rect winBounds = new Rect(0,0,0,0);
        public UIElement winContent = null;
        public Windows.UI.Xaml.Window currentWindow = null;
        public GeneralTransform hovTransform = null;
        public Point hovPointToWindow = new Point(0,0);
        public System.Timers.Timer hoverTimer = new System.Timers.Timer();
        public object hoveredImage = null;
        public PointerRoutedEventArgs hoveredImageArgs = null;

        public ImageUploaderPage()
        {
            this.InitializeComponent();

            //Create and set up the HoverTimer
            hoverTimer = new System.Timers.Timer();
            hoverTimer.Interval = 2000;
            hoverTimer.Elapsed += OnTimerElapsed;
            hoverTimer.AutoReset = true;
        }

        //public event System.Timers.ElapsedEventHandler TimerElapsed
        //{ add { hoverTimer.Elapsed += value; } remove { hoverTimer.Elapsed -= value; } }

        private void onImageHover(object sender, PointerRoutedEventArgs e)
        {
            hoveredImage = sender;
            Grid img = (Grid)sender;
            hoveredImageArgs = e;
            hoverTimer.Stop();
            hoverTimer.Start();
            currentWindow = Window.Current;
            winBounds = Window.Current.Bounds;
            winContent = Window.Current.Content;
            GeneralTransform transform = img.TransformToVisual(winContent);
            hovPointToWindow = transform.TransformPoint(new Point(0, 0));
        }

        private void onImageEndHover(object sender, PointerRoutedEventArgs e)
        {
            hoverTimer.Stop();
            hoveredImage = null;
            hoveredImageArgs = null;
        }

        private void OnTimerElapsed(object source, System.Timers.ElapsedEventArgs e)
        {
            Debug.WriteLine("Timer elapsed!");
            hoverTimer.Stop();

            if (hoveredImage.GetType().ToString() == "Windows.UI.Xaml.Controls.Grid")
            {

                //Get the hovered image and associated arguments that were stored
                Grid img = (Grid)hoveredImage;
                PointerRoutedEventArgs f = hoveredImageArgs;

                //Get image position and bounds
                GeneralTransform transform = img.TransformToVisual(Window.Current.Content);
                Point coordinatePointToWindow = transform.TransformPoint(new Point(0, 0));
                Rect winBounds = Window.Current.Bounds;
                img.Visibility = Visibility.Visible;
                double imgX1 = coordinatePointToWindow.X;
                double imgX2 = imgX1 + img.ActualWidth;
                double imgY1 = coordinatePointToWindow.Y;
                double imgY2 = imgY1 + img.ActualHeight;
// (other logic here to determine pop position and display things in the UI)
    }
}
}

Mark L
  • 83
  • 7
  • The best way to handle an event would be to use behaviors: https://github.com/microsoft/XamlBehaviors And, in general, deriving from system controls or building custom controls often indicates that something went wrong. – Oleg Mikhailov Dec 29 '22 at 20:26
  • I agree, even with Wordless' fix it only fixed the immediate problem and I didnt end up getting the function working – Mark L Dec 29 '22 at 20:36

1 Answers1

0

Your issue here is that you're trying to use a function to override a property.
Because UIElement.PointerEntered is an Event, you need to assign a delegate(of type PointerEventHandler) to it instead.

Here's an example snippet:

// Your constructor
public HoverGrid()
{
    this.PointerEntered += HandlePointerEntered;
    // Do other setup
}

protected void HandlePointerEntered(object sender, PointerRoutedEventArgs args)
{
    // Handle somehow
}
  • 1
    Thanks! This helped me fix the immediate issue and I looked into events/delegates a bit more to understand that. Sadly I think the subclass in general wasn't the best approach and the errors kept piling up. Ill ask a separate question for that – Mark L Dec 29 '22 at 20:37