简体   繁体   English

反应性扩展和MouseEventArgs源

[英]Reactive extensions and MouseEventArgs source

I am using RX in my WPF applications to track mouse movement. 我在WPF应用程序中使用RX来跟踪鼠标移动。

When subscribing directly to the mouse move event I get a different source in my MouseEventArgs compared to when I use the sample method of RX. 直接订阅鼠标移动事件时,与使用RX的示例方法相比,我在MouseEventArgs中获得了不同的源。

For the sake of explanation here is a simple example: 为了便于解释,这里有一个简单的例子:

I have a window containing a grid and a button: 我有一个包含网格和按钮的窗口:

<Window x:Class="WpfApplication4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication4"
        Title="MainWindow" Height="350" Width="525">
    <Grid x:Name="grid">
        <Button></Button>
    </Grid>
</Window>

I subscribe to the mouse move event with RX: 我订阅了RX的鼠标移动事件:

void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
    Observable.FromEventPattern<MouseEventArgs>(grid, "MouseMove").Subscribe(mouseMoveRx);
    Observable.FromEventPattern<MouseEventArgs>(grid, "MouseMove").Sample(TimeSpan.FromSeconds(1)).Subscribe(mouseMoveRxSample);
}

private void mouseMoveRx(System.Reactive.EventPattern<MouseEventArgs> obj)
{
    var element = obj.EventArgs.Source as UIElement; 
    //element is System.Windows.Controls.Button
}

private void mouseMoveRxSample(System.Reactive.EventPattern<MouseEventArgs> obj)
{
    var element = obj.EventArgs.Source as UIElement;
    //element is Microsoft.Windows.Themes.ButtonChrome
}

The first handler is having System.Windows.Controls.Button as source whereas the second handler is having Microsoft.Windows.Themes.ButtonChrome as source. 第一个处理程序将System.Windows.Controls.Button作为源,而第二个处理程序将Microsoft.Windows.Themes.ButtonChrome作为源。

What is the reason for the different source? 不同来源的原因是什么?

I have no experience with WPF so take this answer with a grain of salt... 我没有WPF的经验,所以请耐心等待这个答案......

But, based on your experiment with Do , it appears that what is happening is that after the event fires and Sample caches the value, the event object is mutated presumably by WPF. 但是,根据你对Do的实验,看来发生的事情是在事件触发和Sample缓存值之后,事件对象可能是由WPF变异的。

The Remarks section of MouseEventArgs documentation says this: MouseEventArgs文档Remarks部分Remarks了这一点:

The attached events and the base element routed events share their event data, and the bubbling and tunneling versions of the routed events also share event data. 附加事件和基本元素路由事件共享其事件数据,路由事件的冒泡和隧道版本也共享事件数据。 This can affect the handled characteristics of the event as it travels the event route. 这会影响事件在事件路径中传播时的处理特征。 For details, see Input Overview. 有关详细信息,请参阅输入概述

This seems to suggest that indeed WPF mutates the event object as it bubbles it up the element hierarchy. 这似乎表明,事实上,WPF会将事件对象变为元素层次结构。 Any settable property on the object is subject to this behavior. 对象上的任何可设置属性都受此行为的影响。 In this case it appears that Source is the only thing you need to worry about. 在这种情况下,看起来Source是您唯一需要担心的事情。

To handle this, you effectively need to cache the Source value before you apply any Rx operator that introduces asynchronicity because you can only trust the Source property for as long as your WPF event handler is running. 要处理这个问题,在应用引入异步性的任何Rx运算符之前,实际上需要缓存Source值,因为只要WPF事件处理程序正在运行,您就只能信任Source属性。 The simplest way is to use a Select clause to capture Source : 最简单的方法是使用Select子句捕获Source

Observable.FromEventPattern<MouseEventArgs>(grid, "MouseMove")
    .Select(e => Tuple.Create(e.EventArgs.Source as UIElement, e.EventArgs))
    .Sample(TimeSpan.FromSeconds(1))
    .Subscribe(mouseMoveRxSample);

// ...

private void mouseMoveRxSample(Tuple<UIElement, MouseEventArgs> obj)
{
    var element = obj.Item1;
    //element is System.Windows.Controls.Button
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM