c# - 响应式扩展和 MouseEventArgs 源

标签 c# .net wpf system.reactive

我在我的 WPF 应用程序中使用 RX 来跟踪鼠标移动。

与使用 RX 示例方法时相比,当直接订阅鼠标移动事件时,我在 MouseEventArgs 中获得了不同的来源。

为了便于说明,这里有一个简单的例子:

我有一个包含网格和按钮的窗口:

<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>

我用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
}

第一个处理程序将 System.Windows.Controls.Button 作为源,而第二个处理程序将 Microsoft.Windows.Themes.ButtonChrome 作为源。

不同来源的原因是什么?

最佳答案

我没有使用 WPF 的经验,所以对这个答案持保留态度......

但是,根据您对 Do 的实验,似乎正在发生的事情是在事件触发并且 Sample 缓存值之后,事件对象大概发生了变化通过 WPF。

MouseEventArgs documentation备注部分是这样说的:

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.

这似乎表明,WPF 在元素层次结构中向上冒泡时确实改变了事件对象。对象上的任何可设置属性都受此行为影响。在这种情况下,Source 似乎是您唯一需要担心的事情。

要处理这个问题,您实际上需要在应用任何引入异步性的 Rx 运算符之前缓存 Source 值,因为您只能信任 Source 属性您的 WPF 事件处理程序正在运行。最简单的方法是使用 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
}

关于c# - 响应式扩展和 MouseEventArgs 源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25730095/

相关文章:

c# - 修复跨线程异常

c# - NancyFx 将接口(interface)传递给模块构造函数导致错误

c# - 以编程方式添加时,引用库中的 TraceSource 不记录

c# - 关于使用 Monitor.TryEnter 和锁定对象的问题

c# - 自动关闭RegSvr32提示

wpf - WPF MediaKit音频问题

c# - WinForm设计器错误打开设计器

c# - 如何将 IntPtr 传递给非托管 C++ CLR 托管代码的方法?

c# - 在 WPF DesignData 文件中设置本地类的名​​称属性时出错

c# - 从 ContextMenu 实现 "Rename"