マウスホイールに対応する

Silverlight 2 Beta 1ではマウスホイールに対応するイベントが用意されていない。これがないとホイールスクロールで画像を拡大・縮小とかができないので、操作性が悪くなってしまう。

といっても方法が無いわけでもなくて、JavaScriptを使えば簡単にできる。

以下のコードをSilverlightページのコンストラクタにでも書いておけば、マウスホイールに対応できる。

Page.xaml.cs
// IE 用
HtmlPage.Document.AttachEvent("onmousewheel", new EventHandler<HtmlEventArgs>((s, e) => {
   var value = (double)e.EventObject.GetProperty("wheelDelta") / 120;

   if(value > 0) {
       // 下方向にスクロールされた
   } else {
       // 上方向にスクロールされた
   }
}));

といっても、これはブラウザ依存のコードでIEでしか動かない。他のブラウザで動作させようと思ったら、ブラウザ毎にコードを変える必要があるので注意!!

ちなみにIEFirefoxに対応させた例が以下。わざとややこしく書いてみた。

Page.xaml.cs

public partial class Page : UserControl {
    
   public Page() {
       InitializeComponent();

       AttachMouseWheelEvent(value => {
           if(value > 0) {
               // 下方向にスクロールされた
           } else {
               // 上方向にスクロールされた
           }
       });
   }

   private void AttachMouseWheelEvent(Action<double> action) {
       string eventName = HtmlPage.Window.GetProperty("addEventListener") != null ?
           "DOMMouseScroll" :  // Firefox
           "onmousewheel";     // IE

       HtmlPage.Document.AttachEvent(eventName, new EventHandler<HtmlEventArgs>((s, e) => {
           var strategies = new[] {
               // IE
               (Func<double?>)(() => {
                   var value = e.EventObject.GetProperty("WheelDelta");

                   return value != null ? (double?)value / 120 : null;
               }),
               // Firefox
               (Func<double?>)(() => {
                   var value = e.EventObject.GetProperty("detail");

                   return value != null ? (double?)value / 3 : null;
               })
           };
           action(strategies.FirstResult(value => value != null).Value);
       }));
   }
}

/// <summary>
/// Funcデリゲートの拡張クラス
/// </summary>
static class FuncExtension {

   public static T FirstResult<T>(this IEnumerable<Func<T>> collection, Predicate<T> predicate) {
       foreach(var func in collection) {
           T value = func();

           if(predicate(value)) return value;
       }
       return default(T);
   }

}

このへんは将来的にブラウザ互換レイヤーとかが追加されたりしないのかな。