簡體   English   中英

如何將延遲的PointerEnter事件實現到C# UWP項目中

[英]How to implement a delayed PointerEnter event into C# UWP project

我一直在嘗試在我的應用程序中實現一個功能,當用戶將鼠標懸停在 GridView 中的一個網格項目上幾秒鍾時,它將顯示一個中等大小的彈出網格,其中包含更多詳細信息。 我已經嘗試了一些在網上找到的方法,但我一直遇到錯誤,我不了解其根本原因,而且我覺得添加此功能的方法比我目前在網上找到的要簡單得多.

首先,我嘗試了一個解決方案,通過使用 Grid 的衍生物 class 進行調整 我遇到了一些問題(在我的最后一個問題中詳細說明),主要問題是我的計時器不再觸發,並且在 GridView 模板中使用我的“HoverGrid”數據模板的項目將不再顯示圖像作為HoverGrid 的子項目。 所以,我放棄了這種方法。

然后我嘗試直接在我的頁面的代碼隱藏中實現 Timer,這似乎(部分)工作,因為它正確觸發了 PointerEnter、PointerExit 和 TimerElapsed 事件,但是,當嘗試操作與 TimerElapsed 事件相關的任何 UI 時,我會得到:

System.Exception: '應用程序調用了一個為不同線程編組的接口。 (HRESULT 異常:0x8001010E (RPC_E_WRONG_THREAD))'

這是 XAML:

<Page
    x:Class="myproject.Pages.MyPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Height="950"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    mc:Ignorable="d">

    <Grid x:Name="ContentGrid">
        <ListView
                    x:Name="AreaPanels"
                    Margin="0,10,0,0"
                    HorizontalContentAlignment="Stretch"
                    SelectionMode="None">
            <ListView.ItemsPanel>
                <ItemsPanelTemplate>
                    <ItemsStackPanel AreStickyGroupHeadersEnabled="True" />
                </ItemsPanelTemplate>
            </ListView.ItemsPanel>

            <controls:AdaptiveGridView
                            CanDragItems="True"
                            DesiredWidth="140"
                            ItemHeight="140">
                <controls:AdaptiveGridView.ItemTemplate>
                    <DataTemplate x:Name="IconTextTemplate" x:DataType="Image">
                        <Grid
                                        PointerEntered="ImageHoverStart"
                                        PointerExited="ImageHoverEnd">
                            <Image
                                            Opacity="1"
                                            Source="/Assets/Placeholders/sample_image.jpg"
                                            Stretch="UniformToFill" />
                        </Grid>
                    </DataTemplate>
                </controls:AdaptiveGridView.ItemTemplate>
                <Grid />
                <Grid />
                <Grid />
                <Grid />
            </controls:AdaptiveGridView>
        </ListView>
    </Grid>
</Page>

代碼隱藏(C#):

using System.Diagnostics;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;

namespace myproject.Pages
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MyPage : Page
    {
        //Variables for Grid functions
        public object hoveredGridItem = null;
        public PointerRoutedEventArgs hoveredGridItemArgs = null;
        public System.Timers.Timer hoverTimer = new System.Timers.Timer();

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

        public MyPage()
        {
            this.InitializeComponent();
            hoverTimer.Enabled = true;
            hoverTimer.Interval = 2000;
            TimerElapsed += OnTimerElapsed;
        }

        private void ImageHoverStart(object sender, PointerRoutedEventArgs e)
        {
            Debug.WriteLine("Fired: ImageHoverStart");
            hoverTimer.Start();
            hoveredGridItem = sender;
            hoveredGridItemArgs = e;
        }

        private void ImageHoverEnd(object sender, PointerRoutedEventArgs e)
        {
            Debug.WriteLine("Fired: ImageHoverEnd");
            hoverTimer.Stop();
            hoveredGridItem = null;
            hoveredGridItemArgs = null;
        }

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

            if (hoveredGridItem.GetType().ToString() == "Windows.UI.Xaml.Controls.Grid")
            {
                Debug.WriteLine(hoveredGridItem.ToString());
                Debug.WriteLine(hoveredGridItemArgs.ToString());
                //Get the hovered image and associated arguments that were stored
                Grid itm = (Grid)hoveredGridItem;
                PointerRoutedEventArgs f = hoveredGridItemArgs;

                //Get image position and bounds
                //GeneralTransform transform = itm.TransformToVisual(Window.Current.Content);
                //Point coordinatePointToWindow = transform.TransformPoint(new Point(0, 0));
                //Rect winBounds = Window.Current.Bounds;

                //Testing other UI items
                itm.Visibility = Visibility.Visible;

                // other UI stuff ...
            }
        }
    }
}

我嘗試引用一些 UI 元素,例如 Window.Content.Current 和其他元素(作為解決方法),但仍然得到相同的 System.Exception。 我知道這與 TimerElapsed 在與 UI 線程不同的線程上有關,並四處尋找如何解決這個問題但無法解決。

我的兩個問題是我無法解決線程編組問題(異步運行的一些問題),但更重要的是,該解決方案似乎有點復雜,可能比需要的更難。

首先要解決線程問題,您必須使用 UIElement 的 Dispatcher:

await itm.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
    itm.Visibility = Visibility.Visible;
});

其次,您是否考慮過為此使用工具提示? 它應該很容易實現:

<Grid Background="Transparent">
    <Image Opacity="1" Source="/Assets/StoreLogo.png" Stretch="UniformToFill" />
    
    <!--Tooltip implementation:-->
    <ToolTipService.ToolTip>
        <Image Source="/Assets/StoreLogo.png"/>
    </ToolTipService.ToolTip>
</Grid>

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM