xin9le.net

Microsoft の製品/技術が大好きな Microsoft MVP な管理人の技術ブログです。

Rx入門 (19) - マウス位置のトラッキング

今回は、ボタン上の一部でマウス位置のトラッキングを行うというだけの (つまんない) サンプルを紹介します。CAD系のソフトだとステータスバーにマウスの座標位置が表示されるものがありますが、そう言ったケースで応用が利くかもしれません。

サンプルコード

以下にXAMLコードを示します。トラッキング領域指定用のButtonと、マウス座標位置表示用のTextBlockが置いてあるだけです。

<Window x:Class="Sample38_MousePositionTracker.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Sample38_MousePositionTracker" Height="300" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBlock Name="display" />
        <Button Name="button" Content="Run" Grid.Row="1"/>
    </Grid>
</Window>

次に、MouseMoveイベントを拾い、マウス位置を取得して表示するコードを示します。ボタンの右下1/4の領域でのみ位置をトラッキングするようにしました。

using System;
using System.Reactive.Linq;
using System.Windows;
using System.Windows.Input;
 
namespace Sample38_MousePositionTracker
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            this.InitializeComponent();
            Observable.FromEventPattern<MouseEventArgs>(this.button, "MouseMove")
            .Do(_ => this.display.Text = null)
            .Select(pattern => pattern.EventArgs.GetPosition(this))
            .Where(position => (position.X > this.button.ActualWidth  / 2) &&
                               (position.Y > this.button.ActualHeight / 2))
            .Subscribe(position => this.display.Text = string.Format("(X, Y) = {0}", position));
        }
    }
}

実行例

実行すると以下のようになります。マウスをボタン領域の右下に移動させると座標位置が表示されます。(ボタンをクリックしても何も起こらないのはご愛嬌...)

MousePositionTracker

「イベントハンドラで条件判定して座標位置を文字列に変換して...なんてもう古い!」というのは嘘です。結局同じことを違う形で書いているだけです。けど、イベントデータのフィルタリングや射影などがLINQの形式で簡単に行えるというのは、イベントハンドラでは簡単に実現できなかった別の拡張性/汎用性があるという意味で重要です。

ただし、何でもかんでもIObservable<T>にすると良いかと言うとそうではありません (特にこのような簡単なケースでは)。どっちがコードを綺麗に書けるか/分かりやすいか、どっちがバグの原因を減らせるかなどを考えて選択しましょう。