我在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
为源。
不同来源的原因是什么?
答案 0 :(得分:0)
我没有使用WPF的经验,所以请耐心等待这个答案......
但是,根据您对Do
的实验,看来发生的事情是,在事件触发并Sample
缓存该值后,事件对象可能会被WPF突变。
MouseEventArgs documentation的Remarks
部分说明了这一点:
附加事件和基本元素路由事件共享它们 事件数据,以及路由的冒泡和隧道版本 事件还共享事件数据。这可能会影响处理 事件发生在事件路线上的特征。对于 详细信息,请参阅输入概述。
这似乎表明,事实上,WPF会将事件对象变为元素层次结构。对象上的任何可设置属性都受此行为的影响。在这种情况下,似乎Source
是唯一需要担心的事情。
要处理这个问题,在应用引入异步性的任何Rx运算符之前,实际上需要缓存Source
值,因为只要WPF事件处理程序正在运行,您就只能信任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
}