Reactive Extensions and Source MouseEventArgs

I am using RX in my WPF applications to track mouse movement.

When I subscribe directly to the mouse move event, I get a different origin in the MouseEventArgs compared to when I use the RX sample method.

Here's a simple example for explanation:

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 am subscribing to a mouse move event using 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 has System.Windows.Controls.Button

a source, while the second handler has Microsoft.Windows.Themes.ButtonChrome

a source.

What is the reason for the different source?

+3


source to share


1 answer


I have no experience with WPF, so take this answer with a grain of salt ...

But based on your experimenting with Do

, what seems to be happening is that after the event is fired and the Sample

value is cached, the event object is mutated, presumably WPF.

Remarks

The MouseEventArgs documentation section says this:

Attached events and base element related events separate their event data, and the bubbling and tunneling options for routed events also contain event data. This can affect the processed characteristics of the event as it travels along the event route. See the Input Overview section for details.



This seems to indicate that WPF is mutating the event object as it aligns the element hierarchy. Any set property of an object depends on this behavior. In this case, it seems that Source

is the only thing you need to worry about.

To deal with this, you really need to cache the value Source

before applying any Rx statement that introduces asynchrony, because you can only trust the property Source

as long as the WPF event handler is running. The easiest way is to use a Select

capture clause 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
}

      

0


source







All Articles